300 lines
8.5 KiB
JavaScript
300 lines
8.5 KiB
JavaScript
|
|
import { useEffect, useState } from "react";
|
|||
|
|
import {
|
|||
|
|
Badge,
|
|||
|
|
Button,
|
|||
|
|
Descriptions,
|
|||
|
|
Form,
|
|||
|
|
Modal,
|
|||
|
|
Table,
|
|||
|
|
message,
|
|||
|
|
} from "antd";
|
|||
|
|
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
|
|||
|
|
import TableAction from "@cqsjjb/jjb-react-admin-component/TableAction";
|
|||
|
|
import ControlWrapper from "@cqsjjb/jjb-react-admin-component/ControlWrapper";
|
|||
|
|
import SearchForm from "~/components/SearchForm";
|
|||
|
|
import PreviewUrlButton from "~/components/PreviewUrlButton";
|
|||
|
|
import { AntdTableFuncControl } from "@cqsjjb/jjb-common-decorator/antd";
|
|||
|
|
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|||
|
|
import { tools } from "@cqsjjb/jjb-common-lib";
|
|||
|
|
import { NS_COURSEWARE } from "~/enumerate/namespace";
|
|||
|
|
import {
|
|||
|
|
COURSEWARE_STATUS_MAP,
|
|||
|
|
COURSEWARE_STATUS_OPTIONS,
|
|||
|
|
COURSEWARE_TRAINING_TYPE_MAP,
|
|||
|
|
COURSEWARE_TRAINING_TYPE_OPTIONS,
|
|||
|
|
} from "~/enumerate/constant";
|
|||
|
|
|
|||
|
|
const { router } = tools;
|
|||
|
|
|
|||
|
|
/** 解析课件文档字段:JSON 数组字符串,容错非法格式 */
|
|||
|
|
const parseCoursewareDocument = (raw) => {
|
|||
|
|
if (!raw) return [];
|
|||
|
|
try {
|
|||
|
|
const parsed = JSON.parse(raw);
|
|||
|
|
return Array.isArray(parsed) ? parsed : [];
|
|||
|
|
} catch {
|
|||
|
|
return [];
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/** 培训课程管理 */
|
|||
|
|
function CourseManagePage(props) {
|
|||
|
|
const [searchForm] = Form.useForm();
|
|||
|
|
const [viewRecord, setViewRecord] = useState(null);
|
|||
|
|
const { courseware } = props;
|
|||
|
|
const { courseList: dataSource, courseTotal: total, courseLoading: loading } =
|
|||
|
|
courseware || {};
|
|||
|
|
|
|||
|
|
const handleSearch = () => {
|
|||
|
|
props.coursePage(router.query);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
useEffect(() => {
|
|||
|
|
searchForm.setFieldsValue(router.query);
|
|||
|
|
handleSearch();
|
|||
|
|
}, []);
|
|||
|
|
|
|||
|
|
const columns = [
|
|||
|
|
{
|
|||
|
|
title: "序号",
|
|||
|
|
width: 70,
|
|||
|
|
fixed: "left",
|
|||
|
|
render: (_, __, index) => {
|
|||
|
|
const current = Number(router.query.current) || 1;
|
|||
|
|
const size = Number(router.query.size) || 10;
|
|||
|
|
return (current - 1) * size + index + 1;
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
title: "课程名称",
|
|||
|
|
dataIndex: "courseName",
|
|||
|
|
width: 260,
|
|||
|
|
ellipsis: true,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
title: "课程描述",
|
|||
|
|
dataIndex: "courseDescription",
|
|||
|
|
width: 320,
|
|||
|
|
ellipsis: true,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
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),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
title: "上传单位",
|
|||
|
|
dataIndex: "uploadUnit",
|
|||
|
|
width: 200,
|
|||
|
|
ellipsis: true,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
title: "是否已使用",
|
|||
|
|
dataIndex: "used",
|
|||
|
|
width: 100,
|
|||
|
|
render: (v) => (v === 1 ? "已使用" : "未使用"),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
title: "操作",
|
|||
|
|
width: 200,
|
|||
|
|
fixed: "right",
|
|||
|
|
render: (_, record) => (
|
|||
|
|
<TableAction>
|
|||
|
|
<Button
|
|||
|
|
type="link"
|
|||
|
|
size="small"
|
|||
|
|
onClick={() => setViewRecord(record)}
|
|||
|
|
>
|
|||
|
|
查看
|
|||
|
|
</Button>
|
|||
|
|
<Button
|
|||
|
|
type="link"
|
|||
|
|
size="small"
|
|||
|
|
onClick={() => message.info("课程启用/禁用接口待接入")}
|
|||
|
|
>
|
|||
|
|
{record.status === 1 ? "禁用" : "启用"}
|
|||
|
|
</Button>
|
|||
|
|
<Button
|
|||
|
|
type="link"
|
|||
|
|
size="small"
|
|||
|
|
onClick={() => message.info("课程编辑接口待接入")}
|
|||
|
|
>
|
|||
|
|
编辑
|
|||
|
|
</Button>
|
|||
|
|
<Button
|
|||
|
|
danger
|
|||
|
|
type="link"
|
|||
|
|
size="small"
|
|||
|
|
onClick={() => message.info("课程删除接口待接入")}
|
|||
|
|
>
|
|||
|
|
删除
|
|||
|
|
</Button>
|
|||
|
|
</TableAction>
|
|||
|
|
),
|
|||
|
|
},
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
const relatedCourseware = viewRecord?.courseRelCoursewareVOList || [];
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<PageLayout title="培训课程管理">
|
|||
|
|
<SearchForm
|
|||
|
|
style={{ marginBottom: 24 }}
|
|||
|
|
form={searchForm}
|
|||
|
|
loading={loading}
|
|||
|
|
formLine={[
|
|||
|
|
<Form.Item key="courseName" name="courseName">
|
|||
|
|
<ControlWrapper.Input
|
|||
|
|
label="课程名称"
|
|||
|
|
placeholder="请输入名称"
|
|||
|
|
allowClear
|
|||
|
|
maxLength={50}
|
|||
|
|
/>
|
|||
|
|
</Form.Item>,
|
|||
|
|
<Form.Item key="trainingType" name="trainingType">
|
|||
|
|
<ControlWrapper.Select
|
|||
|
|
label="培训类型"
|
|||
|
|
placeholder="请选择"
|
|||
|
|
allowClear
|
|||
|
|
style={{ width: "100%" }}
|
|||
|
|
options={COURSEWARE_TRAINING_TYPE_OPTIONS}
|
|||
|
|
/>
|
|||
|
|
</Form.Item>,
|
|||
|
|
<Form.Item key="status" name="status">
|
|||
|
|
<ControlWrapper.Select
|
|||
|
|
label="课程状态"
|
|||
|
|
placeholder="请选择课程状态"
|
|||
|
|
allowClear
|
|||
|
|
style={{ width: "100%" }}
|
|||
|
|
options={COURSEWARE_STATUS_OPTIONS}
|
|||
|
|
/>
|
|||
|
|
</Form.Item>,
|
|||
|
|
]}
|
|||
|
|
onReset={(value) => {
|
|||
|
|
router.query = { ...value, current: 1, size: 10 };
|
|||
|
|
handleSearch();
|
|||
|
|
}}
|
|||
|
|
onFinish={(value) => {
|
|||
|
|
router.query = { ...value, current: 1, size: 10 };
|
|||
|
|
handleSearch();
|
|||
|
|
}}
|
|||
|
|
/>
|
|||
|
|
|
|||
|
|
<Table
|
|||
|
|
rowKey="id"
|
|||
|
|
columns={columns}
|
|||
|
|
dataSource={Array.isArray(dataSource) ? dataSource : []}
|
|||
|
|
scroll={{ x: 1500, y: props.scrollY }}
|
|||
|
|
loading={loading}
|
|||
|
|
pagination={{
|
|||
|
|
total,
|
|||
|
|
showSizeChanger: true,
|
|||
|
|
showQuickJumper: true,
|
|||
|
|
showTotal: (t) => `共 ${t} 条`,
|
|||
|
|
current: Number(router.query.current) || 1,
|
|||
|
|
pageSize: Number(router.query.size) || 10,
|
|||
|
|
onChange: (page, pageSize) => {
|
|||
|
|
router.query = { ...router.query, current: page, size: pageSize };
|
|||
|
|
handleSearch();
|
|||
|
|
},
|
|||
|
|
}}
|
|||
|
|
/>
|
|||
|
|
|
|||
|
|
<Modal
|
|||
|
|
title="课程详情"
|
|||
|
|
open={!!viewRecord}
|
|||
|
|
width={760}
|
|||
|
|
footer={null}
|
|||
|
|
onCancel={() => setViewRecord(null)}
|
|||
|
|
>
|
|||
|
|
<Descriptions column={2} bordered size="small">
|
|||
|
|
<Descriptions.Item label="课程名称" span={2}>
|
|||
|
|
{viewRecord?.courseName || "-"}
|
|||
|
|
</Descriptions.Item>
|
|||
|
|
<Descriptions.Item label="培训类型">
|
|||
|
|
{COURSEWARE_TRAINING_TYPE_MAP[viewRecord?.trainingType]
|
|||
|
|
?? (viewRecord?.trainingType || "-")}
|
|||
|
|
</Descriptions.Item>
|
|||
|
|
<Descriptions.Item label="课程状态">
|
|||
|
|
{COURSEWARE_STATUS_MAP[viewRecord?.status]?.label || "-"}
|
|||
|
|
</Descriptions.Item>
|
|||
|
|
<Descriptions.Item label="总课时">
|
|||
|
|
{viewRecord?.classHourDuration ?? "-"}
|
|||
|
|
</Descriptions.Item>
|
|||
|
|
<Descriptions.Item label="是否已使用">
|
|||
|
|
{viewRecord?.used === 1 ? "已使用" : "未使用"}
|
|||
|
|
</Descriptions.Item>
|
|||
|
|
<Descriptions.Item label="上传单位" span={2}>
|
|||
|
|
{viewRecord?.uploadUnit || "-"}
|
|||
|
|
</Descriptions.Item>
|
|||
|
|
<Descriptions.Item label="课程描述" span={2}>
|
|||
|
|
{viewRecord?.courseDescription || "-"}
|
|||
|
|
</Descriptions.Item>
|
|||
|
|
</Descriptions>
|
|||
|
|
|
|||
|
|
<div style={{ marginTop: 16, marginBottom: 8, fontWeight: 600 }}>
|
|||
|
|
关联课件
|
|||
|
|
</div>
|
|||
|
|
<Table
|
|||
|
|
rowKey={(row) => row.coursewareId}
|
|||
|
|
size="small"
|
|||
|
|
columns={[
|
|||
|
|
{ title: "序号", width: 60, render: (_, __, i) => i + 1 },
|
|||
|
|
{
|
|||
|
|
title: "课件名称",
|
|||
|
|
dataIndex: "coursewareName",
|
|||
|
|
ellipsis: true,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
title: "课时时长(小时)",
|
|||
|
|
dataIndex: "classHourDuration",
|
|||
|
|
width: 130,
|
|||
|
|
render: (v) => (v == null ? "-" : v),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
title: "学时",
|
|||
|
|
dataIndex: "creditHours",
|
|||
|
|
width: 90,
|
|||
|
|
render: (v) => (v == null ? "-" : v),
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
title: "课件文档",
|
|||
|
|
dataIndex: "coursewareDocument",
|
|||
|
|
width: 160,
|
|||
|
|
render: (raw) => {
|
|||
|
|
const files = parseCoursewareDocument(raw);
|
|||
|
|
return files.length ? (
|
|||
|
|
files.map((f, i) => (
|
|||
|
|
<PreviewUrlButton key={f.uid || i} url={f.url}>
|
|||
|
|
{f.name || f.url}
|
|||
|
|
</PreviewUrlButton>
|
|||
|
|
))
|
|||
|
|
) : (
|
|||
|
|
"-"
|
|||
|
|
);
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
]}
|
|||
|
|
dataSource={relatedCourseware}
|
|||
|
|
pagination={false}
|
|||
|
|
/>
|
|||
|
|
</Modal>
|
|||
|
|
</PageLayout>
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export default Connect(
|
|||
|
|
[NS_COURSEWARE],
|
|||
|
|
true,
|
|||
|
|
)(AntdTableFuncControl(CourseManagePage));
|