safety-eval-service-frontend/src/pages/Container/EduTraining/ClassManage/Add/CourseTab.js

314 lines
8.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { useEffect, useState } from "react";
import { Badge, Button, Form, Input, Modal, Space, Table, message } from "antd";
import ControlWrapper from "@cqsjjb/jjb-react-admin-component/ControlWrapper";
import SearchForm from "~/components/SearchForm";
import TableAction from "@cqsjjb/jjb-react-admin-component/TableAction";
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { NS_COURSEWARE } from "~/enumerate/namespace";
import { COURSEWARE_STATUS_MAP } from "~/enumerate/constant";
import ClassPaperConfig from "./PaperConfig";
/** 视频累计时长(小时)→ “X分钟Y秒” */
const formatVideoDuration = (hours) => {
if (hours == null) return "-";
const totalSeconds = Math.round(hours * 3600);
return `${Math.floor(totalSeconds / 60)}分钟${totalSeconds % 60}`;
};
/** 班级详情 — 课程 Tab班级课程查询 */
function ClassCourseTab(props) {
const { classId } = props;
const [searchForm] = Form.useForm();
const [query, setQuery] = useState({ current: 1, size: 10 });
const [selectOpen, setSelectOpen] = useState(false);
const {
classCourseList: dataSource,
classCourseTotal: total,
classCourseLoading: loading,
} = props.courseware || {};
const tableSource = Array.isArray(dataSource) ? dataSource : [];
const handleSearch = (params = query) => {
props.classCoursePage({ ...params, classId });
};
useEffect(() => {
if (!classId) return;
handleSearch(query);
}, [classId]);
const columns = [
{
title: "序号",
width: 70,
fixed: "left",
render: (_, __, index) => (query.current - 1) * query.size + index + 1,
},
{
title: "课程名称",
dataIndex: "courseName",
width: 320,
ellipsis: true,
render: (v) => v || "-",
},
{
title: "要求完成总学时",
dataIndex: "requiredTotalHours",
width: 130,
render: (v) => (v == null ? "-" : v),
},
{
title: "视频累计时长",
dataIndex: "videoDuration",
width: 130,
render: (v) => formatVideoDuration(v),
},
{
title: "上课学员数",
dataIndex: "studentCount",
width: 110,
render: (v) => (v == null ? "-" : v),
},
{
title: "已完成学员数",
dataIndex: "completedCount",
width: 120,
render: (v) => (v == null ? "-" : v),
},
{
title: "操作",
width: 140,
fixed: "right",
render: (_, record) => (
<TableAction>
<Button
type="link"
size="small"
onClick={() => message.info("课程查看功能待接入")}
>
查看
</Button>
<Button
danger
type="link"
size="small"
onClick={() =>
Modal.confirm({
title: "确认删除该课程?",
content: `删除后不可恢复,确认删除课程「${
record.courseName || ""
}」吗?`,
onOk: async () => {
const res = await props.classCourseRemove({
data: record.id,
});
if (res?.success !== false) {
message.success("删除成功");
handleSearch();
}
},
})
}
>
删除
</Button>
</TableAction>
),
},
];
return (
<>
<SearchForm
style={{ marginBottom: 16 }}
form={searchForm}
loading={loading}
formLine={[
<Form.Item key="courseName" name="courseName">
<ControlWrapper.Input
label="课程名称"
placeholder="请输入"
allowClear
maxLength={50}
/>
</Form.Item>,
]}
onReset={(value) => {
const next = { ...value, current: 1, size: 10 };
setQuery(next);
handleSearch(next);
}}
onFinish={(value) => {
const next = { ...value, current: 1, size: 10 };
setQuery(next);
handleSearch(next);
}}
/>
<Space style={{ marginBottom: 12 }}>
<Button type="primary" onClick={() => setSelectOpen(true)}>
选择课程
</Button>
<ClassPaperConfig classId={classId} />
</Space>
<Table
rowKey="id"
columns={columns}
dataSource={tableSource}
scroll={{ x: 1000 }}
loading={loading}
pagination={{
total,
showSizeChanger: true,
showQuickJumper: true,
showTotal: (t) => `${t}`,
current: query.current,
pageSize: query.size,
onChange: (page, pageSize) => {
const next = { ...query, current: page, size: pageSize };
setQuery(next);
handleSearch(next);
},
}}
/>
<CourseSelectModal
open={selectOpen}
loading={props.courseware?.courseLoading}
confirmLoading={props.courseware?.classCourseConfirmLoading}
dataSource={props.courseware?.courseList}
total={props.courseware?.courseTotal}
requestPage={props.coursePage}
selectedIds={tableSource.map((item) => item.courseId)}
onOk={async (rows) => {
// 批量新增班级课程
const res = await props.classCourseBatchSave(
rows.map(({ id, courseName, classHourDuration }) => ({
classId,
courseId: id,
courseName,
requiredTotalHours: classHourDuration,
})),
);
if (res?.success === false) return;
message.success("添加成功");
setSelectOpen(false);
handleSearch();
}}
onCancel={() => setSelectOpen(false)}
/>
</>
);
}
/** 选择课程弹窗:数据源同培训课程管理列表 */
function CourseSelectModal({
open,
loading,
confirmLoading,
dataSource,
total,
requestPage,
selectedIds,
onOk,
onCancel,
}) {
const [query, setQuery] = useState({ current: 1, size: 10 });
const [keyword, setKeyword] = useState("");
const [selectedRows, setSelectedRows] = useState([]);
const handleSearch = (params) => {
setQuery(params);
requestPage(params);
};
useEffect(() => {
if (open) {
setKeyword("");
setSelectedRows([]);
handleSearch({ current: 1, size: 10 });
}
}, [open]);
return (
<Modal
open={open}
title="选择课程"
width={860}
loading={loading}
confirmLoading={confirmLoading}
destroyOnHidden
okText={`确定${selectedRows.length ? `(已选 ${selectedRows.length}` : ""}`}
okButtonProps={{ disabled: !selectedRows.length }}
onOk={() => onOk(selectedRows)}
onCancel={onCancel}
>
<Input.Search
placeholder="请输入课程名称"
allowClear
style={{ width: 280, marginBottom: 12 }}
value={keyword}
onChange={(e) => setKeyword(e.target.value)}
onSearch={(value) =>
handleSearch({ current: 1, size: query.size, courseName: value })
}
/>
<Table
rowKey="id"
size="small"
columns={[
{ title: "课程名称", dataIndex: "courseName", ellipsis: true },
{
title: "课程描述",
dataIndex: "courseDescription",
width: 260,
ellipsis: true,
render: (v) => v || "-",
},
{
title: "课程状态",
dataIndex: "status",
width: 90,
render: (v) => {
const item = COURSEWARE_STATUS_MAP[v];
return item ? <Badge status={item.status} text={item.label} /> : "-";
},
},
{
title: "总课时",
dataIndex: "classHourDuration",
width: 90,
render: (v) => (v == null ? "-" : v),
},
]}
dataSource={Array.isArray(dataSource) ? dataSource : []}
rowSelection={{
preserveSelectedRowKeys: true,
selectedRowKeys: selectedRows.map((r) => r.id),
getCheckboxProps: (record) => ({
disabled: selectedIds.includes(record.id),
}),
onChange: (_, rows) => setSelectedRows(rows),
}}
pagination={{
total,
size: "small",
showTotal: (t) => `${t}`,
current: Number(query.current) || 1,
pageSize: Number(query.size) || 10,
onChange: (page, pageSize) =>
handleSearch({
current: page,
size: pageSize,
courseName: query.courseName,
}),
}}
/>
</Modal>
);
}
export default Connect([NS_COURSEWARE], true)(ClassCourseTab);