feat
parent
ca38ee44ae
commit
6acae8d648
|
|
@ -13,8 +13,8 @@ module.exports = {
|
||||||
//API_HOST: "http://localhost:80",
|
//API_HOST: "http://localhost:80",
|
||||||
|
|
||||||
// API_HOST: "http://192.168.0.134",
|
// API_HOST: "http://192.168.0.134",
|
||||||
// API_HOST: "http://192.168.0.150", //太浅
|
API_HOST: "http://192.168.0.150", //太浅
|
||||||
API_HOST: "https://gbs-gateway.qhdsafety.com",
|
// API_HOST: "https://gbs-gateway.qhdsafety.com",
|
||||||
// API_HOST: "http://192.168.0.103", //huwei
|
// API_HOST: "http://192.168.0.103", //huwei
|
||||||
},
|
},
|
||||||
production: {
|
production: {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { declareRequest } from "@cqsjjb/jjb-dva-runtime";
|
import { declareRequest } from "@cqsjjb/jjb-dva-runtime";
|
||||||
|
|
||||||
/** 教育培训 — 培训课件管理 / 培训课程管理 */
|
/** 教育培训 — 培训课件管理 / 培训课程管理 / 班级管理 */
|
||||||
|
|
||||||
/** 分页查询课件 */
|
/** 分页查询课件 */
|
||||||
export const coursewarePage = declareRequest(
|
export const coursewarePage = declareRequest(
|
||||||
|
|
@ -39,3 +39,28 @@ export const coursePage = declareRequest(
|
||||||
"Get > /safetyEval/courseManagement/page",
|
"Get > /safetyEval/courseManagement/page",
|
||||||
"courseList: [] | res.data || [] & courseTotal: 0 | res.total || 0",
|
"courseList: [] | res.data || [] & courseTotal: 0 | res.total || 0",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** 新增课程 */
|
||||||
|
export const courseAdd = declareRequest(
|
||||||
|
"courseConfirmLoading",
|
||||||
|
"Post > @/safetyEval/courseManagement/save",
|
||||||
|
);
|
||||||
|
|
||||||
|
/** 课程详情 */
|
||||||
|
export const courseDetail = declareRequest(
|
||||||
|
"courseDetailLoading",
|
||||||
|
"Get > /safetyEval/courseManagement/get",
|
||||||
|
);
|
||||||
|
|
||||||
|
/** 修改课程 */
|
||||||
|
export const courseModify = declareRequest(
|
||||||
|
"courseConfirmLoading",
|
||||||
|
"Post > @/safetyEval/courseManagement/modify",
|
||||||
|
);
|
||||||
|
|
||||||
|
/** 分页查询班级 */
|
||||||
|
export const classPage = declareRequest(
|
||||||
|
"classLoading",
|
||||||
|
"Get > /safetyEval/classManagement/page",
|
||||||
|
"classList: [] | res.data || [] & classTotal: 0 | res.total || 0",
|
||||||
|
);
|
||||||
|
|
|
||||||
|
|
@ -662,6 +662,21 @@ export const COURSEWARE_TYPE_MAP = COURSEWARE_TYPE_OPTIONS.reduce(
|
||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** 班级状态(0未申请/1待开班/2培训中/3培训结束) */
|
||||||
|
export const CLASS_STATUS_OPTIONS = [
|
||||||
|
{ label: "未申请", value: 0 },
|
||||||
|
{ label: "待开班", value: 1 },
|
||||||
|
{ label: "培训中", value: 2 },
|
||||||
|
{ label: "培训结束", value: 3 },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const CLASS_STATUS_MAP = {
|
||||||
|
0: { label: "未申请", status: "default" },
|
||||||
|
1: { label: "待开班", status: "warning" },
|
||||||
|
2: { label: "培训中", status: "processing" },
|
||||||
|
3: { label: "培训结束", status: "success" },
|
||||||
|
};
|
||||||
|
|
||||||
/** 试卷类型(fixed平台试卷/config_rule规则试卷) */
|
/** 试卷类型(fixed平台试卷/config_rule规则试卷) */
|
||||||
export const PAPER_TYPE_OPTIONS = [
|
export const PAPER_TYPE_OPTIONS = [
|
||||||
{ label: "平台试卷", value: "fixed" },
|
{ label: "平台试卷", value: "fixed" },
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,278 @@
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { Badge, Button, Form, Input, Modal, Table, message } from "antd";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
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 { 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 {
|
||||||
|
CLASS_STATUS_MAP,
|
||||||
|
CLASS_STATUS_OPTIONS,
|
||||||
|
COURSEWARE_TRAINING_TYPE_MAP,
|
||||||
|
COURSEWARE_TRAINING_TYPE_OPTIONS,
|
||||||
|
} from "~/enumerate/constant";
|
||||||
|
|
||||||
|
const { router } = tools;
|
||||||
|
|
||||||
|
/** 涉及学员人员数 / 完成人员数:学员统计接口未接入,暂用假数据 */
|
||||||
|
const MOCK_STUDENT_COUNT = 10;
|
||||||
|
const MOCK_COMPLETED_COUNT = 5;
|
||||||
|
/** 班级总人次:同上,暂用假数据 */
|
||||||
|
const MOCK_TOTAL_PERSON_TIMES = 93;
|
||||||
|
|
||||||
|
/** 搜索表单值 → 查询参数:培训时间范围拆为后端字段(yyyy-MM-dd) */
|
||||||
|
const buildQuery = (value) => {
|
||||||
|
const { trainingDateRange, ...rest } = value || {};
|
||||||
|
return {
|
||||||
|
...rest,
|
||||||
|
...(trainingDateRange?.[0]
|
||||||
|
? { startDateBegin: trainingDateRange[0].format("YYYY-MM-DD") }
|
||||||
|
: {}),
|
||||||
|
...(trainingDateRange?.[1]
|
||||||
|
? { endDateEnd: trainingDateRange[1].format("YYYY-MM-DD") }
|
||||||
|
: {}),
|
||||||
|
current: 1,
|
||||||
|
size: 10,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 教育培训 — 班级管理 */
|
||||||
|
function ClassManagePage(props) {
|
||||||
|
const [searchForm] = Form.useForm();
|
||||||
|
const { courseware } = props;
|
||||||
|
const { classList, classTotal: total, classLoading: loading } =
|
||||||
|
courseware || {};
|
||||||
|
|
||||||
|
const handleSearch = () => {
|
||||||
|
props.classPage(router.query);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const { startDateBegin, endDateEnd, ...rest } = router.query;
|
||||||
|
searchForm.setFieldsValue({
|
||||||
|
...rest,
|
||||||
|
...(startDateBegin && endDateEnd
|
||||||
|
? { trainingDateRange: [dayjs(startDateBegin), dayjs(endDateEnd)] }
|
||||||
|
: {}),
|
||||||
|
});
|
||||||
|
handleSearch();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onDelete = (record) => {
|
||||||
|
Modal.confirm({
|
||||||
|
title: "提示",
|
||||||
|
content: "数据将会删除,您是否确认删除?",
|
||||||
|
okText: "是",
|
||||||
|
cancelText: "否",
|
||||||
|
onOk: () => {
|
||||||
|
message.info(`班级「${record.className}」删除接口待接入`);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
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: "unitName",
|
||||||
|
width: 180,
|
||||||
|
ellipsis: true,
|
||||||
|
render: (v) => v || "-",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "班级名称",
|
||||||
|
dataIndex: "className",
|
||||||
|
width: 180,
|
||||||
|
ellipsis: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "班级编码",
|
||||||
|
dataIndex: "classCode",
|
||||||
|
width: 180,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "培训类型",
|
||||||
|
dataIndex: "trainingType",
|
||||||
|
width: 160,
|
||||||
|
ellipsis: true,
|
||||||
|
render: (v) => COURSEWARE_TRAINING_TYPE_MAP[v] ?? (v || "-"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "培训开始时间",
|
||||||
|
dataIndex: "startDate",
|
||||||
|
width: 120,
|
||||||
|
render: (v) => v || "-",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "结束时间",
|
||||||
|
dataIndex: "endDate",
|
||||||
|
width: 120,
|
||||||
|
render: (v) => v || "-",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "涉及学员人员数",
|
||||||
|
dataIndex: "studentCount",
|
||||||
|
width: 120,
|
||||||
|
render: () => MOCK_STUDENT_COUNT,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "完成人员数",
|
||||||
|
dataIndex: "completedCount",
|
||||||
|
width: 100,
|
||||||
|
render: () => MOCK_COMPLETED_COUNT,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "班级状态",
|
||||||
|
dataIndex: "status",
|
||||||
|
width: 100,
|
||||||
|
render: (v) => {
|
||||||
|
const item = CLASS_STATUS_MAP[v];
|
||||||
|
return item ? <Badge status={item.status} text={item.label} /> : "-";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "操作",
|
||||||
|
width: 240,
|
||||||
|
fixed: "right",
|
||||||
|
render: (_, record) => (
|
||||||
|
<TableAction>
|
||||||
|
<Button
|
||||||
|
type="link"
|
||||||
|
size="small"
|
||||||
|
onClick={() => message.info("班级编辑接口待接入")}
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="link"
|
||||||
|
size="small"
|
||||||
|
onClick={() => message.info("学员列表功能待接入")}
|
||||||
|
>
|
||||||
|
学员列表
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="link"
|
||||||
|
size="small"
|
||||||
|
onClick={() => message.info("课程列表功能待接入")}
|
||||||
|
>
|
||||||
|
课程列表
|
||||||
|
</Button>
|
||||||
|
{record.status === 2 && (
|
||||||
|
<Button
|
||||||
|
type="link"
|
||||||
|
size="small"
|
||||||
|
onClick={() => message.info("班级延期接口待接入")}
|
||||||
|
>
|
||||||
|
延期
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
danger
|
||||||
|
type="link"
|
||||||
|
size="small"
|
||||||
|
onClick={() => onDelete(record)}
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</Button>
|
||||||
|
</TableAction>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageLayout title="班级管理">
|
||||||
|
<SearchForm
|
||||||
|
style={{ marginBottom: 24 }}
|
||||||
|
form={searchForm}
|
||||||
|
loading={loading}
|
||||||
|
formLine={[
|
||||||
|
<Form.Item key="classCode" name="classCode">
|
||||||
|
<ControlWrapper.Input
|
||||||
|
label="班级编码"
|
||||||
|
placeholder="请输入"
|
||||||
|
allowClear
|
||||||
|
maxLength={50}
|
||||||
|
/>
|
||||||
|
</Form.Item>,
|
||||||
|
<Form.Item key="className" name="className">
|
||||||
|
<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={CLASS_STATUS_OPTIONS}
|
||||||
|
/>
|
||||||
|
</Form.Item>,
|
||||||
|
<Form.Item key="trainingDateRange" name="trainingDateRange">
|
||||||
|
<ControlWrapper.DatePicker.RangePicker label="培训时间" />
|
||||||
|
</Form.Item>,
|
||||||
|
]}
|
||||||
|
onReset={(value) => {
|
||||||
|
router.query = buildQuery(value);
|
||||||
|
handleSearch();
|
||||||
|
}}
|
||||||
|
onFinish={(value) => {
|
||||||
|
router.query = buildQuery(value);
|
||||||
|
handleSearch();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<Table
|
||||||
|
rowKey="id"
|
||||||
|
columns={columns}
|
||||||
|
dataSource={Array.isArray(classList) ? classList : []}
|
||||||
|
scroll={{ x: 1800, 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();
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</PageLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Connect(
|
||||||
|
[NS_COURSEWARE],
|
||||||
|
true,
|
||||||
|
)(AntdTableFuncControl(ClassManagePage));
|
||||||
|
|
@ -0,0 +1,414 @@
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Form,
|
||||||
|
Input,
|
||||||
|
Modal,
|
||||||
|
Select,
|
||||||
|
Space,
|
||||||
|
Spin,
|
||||||
|
Table,
|
||||||
|
message,
|
||||||
|
} from "antd";
|
||||||
|
import { DeleteOutlined, PlusOutlined } from "@ant-design/icons";
|
||||||
|
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
|
||||||
|
import TableAction from "@cqsjjb/jjb-react-admin-component/TableAction";
|
||||||
|
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||||
|
import PreviewUrlButton from "~/components/PreviewUrlButton";
|
||||||
|
import { tools } from "@cqsjjb/jjb-common-lib";
|
||||||
|
import AttachmentUpload from "~/components/AttachmentUpload";
|
||||||
|
import { NS_COURSEWARE } from "~/enumerate/namespace";
|
||||||
|
import {
|
||||||
|
COURSEWARE_TRAINING_TYPE_MAP,
|
||||||
|
COURSEWARE_TRAINING_TYPE_OPTIONS,
|
||||||
|
} from "~/enumerate/constant";
|
||||||
|
|
||||||
|
const { TextArea } = Input;
|
||||||
|
const { router } = tools;
|
||||||
|
|
||||||
|
/** 教育培训 — 新增/编辑课程 */
|
||||||
|
function CourseAddPage(props) {
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
const [selectOpen, setSelectOpen] = useState(false);
|
||||||
|
const courseId = router.query.courseId;
|
||||||
|
const isEdit = !!courseId;
|
||||||
|
// 查看模式:仅展示不可编辑
|
||||||
|
const isView = router.query.mode === "view";
|
||||||
|
// 编辑模式:详情就绪后再挂载表单,通过 initialValues 回显;新增模式直接挂载
|
||||||
|
|
||||||
|
const confirmLoading = props.courseware?.courseConfirmLoading;
|
||||||
|
const { courseDetailLoading } = props.courseware;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isEdit) return;
|
||||||
|
(async () => {
|
||||||
|
const res = await props.courseDetail({ id: courseId });
|
||||||
|
if (res?.success !== false && res?.data) {
|
||||||
|
form.setFieldsValue({
|
||||||
|
courseName: res.data.courseName,
|
||||||
|
trainingType: res.data.trainingType,
|
||||||
|
courseDescription: res.data.courseDescription,
|
||||||
|
courseCover: JSON.parse(res.data.courseCover || "[]"),
|
||||||
|
courseRelCoursewareDTOList: (res.data.courseRelCoursewareVOList || []).map(
|
||||||
|
({
|
||||||
|
coursewareId,
|
||||||
|
coursewareName,
|
||||||
|
coursewareDocument,
|
||||||
|
classHourDuration,
|
||||||
|
creditHours,
|
||||||
|
sort,
|
||||||
|
}) => ({
|
||||||
|
coursewareId,
|
||||||
|
coursewareName,
|
||||||
|
coursewareDocument,
|
||||||
|
classHourDuration,
|
||||||
|
creditHours,
|
||||||
|
sort,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
props.history.goBack();
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
try {
|
||||||
|
const values = await form.validateFields();
|
||||||
|
// 封面组件值为 fileList 数组,提交时序列化为 JSON 数组字符串
|
||||||
|
values.courseCover = values.courseCover?.length
|
||||||
|
? JSON.stringify(values.courseCover)
|
||||||
|
: undefined;
|
||||||
|
// 归属课件:Form.List 未注册字段(coursewareId 等)不在 validateFields 结果中,从表单 store 取完整数据并附带排序
|
||||||
|
const relList = form.getFieldValue("courseRelCoursewareDTOList") || [];
|
||||||
|
values.courseRelCoursewareDTOList = relList.length
|
||||||
|
? relList.map((item, index) => ({ ...item, sort: index + 1 }))
|
||||||
|
: undefined;
|
||||||
|
const res = await (isEdit
|
||||||
|
? props.courseModify({ id: courseId, ...values })
|
||||||
|
: props.courseAdd(values));
|
||||||
|
if (res?.success !== false) {
|
||||||
|
message.success("保存成功");
|
||||||
|
props.history.goBack();
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// 表单校验失败或请求异常,由 antd / http 层提示
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageLayout
|
||||||
|
title={isView ? "查看课程" : isEdit ? "编辑课程" : "新增课程"}
|
||||||
|
history={props.history}
|
||||||
|
previous
|
||||||
|
footer={
|
||||||
|
isView ?
|
||||||
|
null
|
||||||
|
: (
|
||||||
|
<Space>
|
||||||
|
<Button onClick={() => props.history.goBack()}>取消</Button>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
loading={confirmLoading}
|
||||||
|
onClick={handleSubmit}
|
||||||
|
>
|
||||||
|
提交
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Spin spinning={isEdit && courseDetailLoading}>
|
||||||
|
{(
|
||||||
|
<>
|
||||||
|
<h3>课程基本信息</h3>
|
||||||
|
<Form
|
||||||
|
form={form}
|
||||||
|
layout="vertical"
|
||||||
|
disabled={isView}
|
||||||
|
|
||||||
|
>
|
||||||
|
<Form.Item
|
||||||
|
label="课程名称"
|
||||||
|
name="courseName"
|
||||||
|
rules={[{ required: true, message: "请输入课程名称" }]}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
placeholder="这里输入课程名称…"
|
||||||
|
allowClear
|
||||||
|
maxLength={50}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label="培训类型"
|
||||||
|
name="trainingType"
|
||||||
|
rules={[{ required: true, message: "请选择培训类型" }]}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
placeholder="请选择培训类型"
|
||||||
|
allowClear
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
options={COURSEWARE_TRAINING_TYPE_OPTIONS}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label="课程描述"
|
||||||
|
name="courseDescription"
|
||||||
|
rules={[{ required: true, message: "请输入课程描述" }]}
|
||||||
|
>
|
||||||
|
<TextArea
|
||||||
|
placeholder="这里输入课程描述…"
|
||||||
|
allowClear
|
||||||
|
rows={4}
|
||||||
|
maxLength={500}
|
||||||
|
showCount
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<AttachmentUpload
|
||||||
|
label="课程封面"
|
||||||
|
name="courseCover"
|
||||||
|
disabled={isView}
|
||||||
|
maxCount={1}
|
||||||
|
accept=".png,.jpg,.jpeg"
|
||||||
|
rules={[{ required: true, message: "请上传课程封面" }]}
|
||||||
|
/>
|
||||||
|
<h3>课程目录</h3>
|
||||||
|
<Form.List name="courseRelCoursewareDTOList">
|
||||||
|
{(_, { add, remove }) => {
|
||||||
|
// Form.List 重渲染时从 store 读取最新完整数据(含未注册字段)
|
||||||
|
const list = form.getFieldValue("courseRelCoursewareDTOList") || [];
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{!isView && (
|
||||||
|
<Button
|
||||||
|
type="dashed"
|
||||||
|
icon={<PlusOutlined />}
|
||||||
|
style={{ marginBottom: 12 }}
|
||||||
|
onClick={() => setSelectOpen(true)}
|
||||||
|
>
|
||||||
|
添加课件
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<Table
|
||||||
|
rowKey="coursewareId"
|
||||||
|
size="small"
|
||||||
|
columns={[
|
||||||
|
{ title: "序号", width: 60, render: (_, __, i) => i + 1 },
|
||||||
|
{
|
||||||
|
title: "课件名称",
|
||||||
|
render: (_, record) => (
|
||||||
|
<Form.Item
|
||||||
|
name={[record.fieldKey, "coursewareName"]}
|
||||||
|
noStyle
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
placeholder="请输入课件名称"
|
||||||
|
allowClear
|
||||||
|
maxLength={50}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "课时时长(小时)",
|
||||||
|
dataIndex: "classHourDuration",
|
||||||
|
width: 130,
|
||||||
|
render: (v) => (v == null ? "-" : v),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "学时",
|
||||||
|
dataIndex: "creditHours",
|
||||||
|
width: 90,
|
||||||
|
render: (v) => (v == null ? "-" : v),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "操作",
|
||||||
|
width: 80,
|
||||||
|
render: (_, record) => {
|
||||||
|
const data = JSON.parse(record.coursewareDocument || "[]")?.[0] || {};
|
||||||
|
return (
|
||||||
|
<TableAction>
|
||||||
|
<PreviewUrlButton url={data.url} >预览</PreviewUrlButton>
|
||||||
|
{!isView && (
|
||||||
|
<Button
|
||||||
|
danger
|
||||||
|
type="link"
|
||||||
|
size="small"
|
||||||
|
icon={<DeleteOutlined />}
|
||||||
|
onClick={() => remove(record.fieldKey)}
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</TableAction>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
dataSource={list.map((item, fieldKey) => ({
|
||||||
|
...item,
|
||||||
|
fieldKey,
|
||||||
|
}))}
|
||||||
|
pagination={false}
|
||||||
|
locale={{
|
||||||
|
emptyText: list.length
|
||||||
|
? undefined
|
||||||
|
: "暂无课件,请点击添加课件",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<CoursewareSelectModal
|
||||||
|
open={selectOpen}
|
||||||
|
loading={props.courseware?.coursewareLoading}
|
||||||
|
dataSource={props.courseware?.coursewareList}
|
||||||
|
total={props.courseware?.coursewareTotal}
|
||||||
|
requestPage={props.coursewarePage}
|
||||||
|
selectedIds={list.map((item) => item.coursewareId)}
|
||||||
|
onOk={(rows) => {
|
||||||
|
// 课件列表记录映射为课程关联课件 DTO 字段,通过 Form.List 原生 add 逐条追加
|
||||||
|
rows.forEach(
|
||||||
|
({
|
||||||
|
id,
|
||||||
|
coursewareName,
|
||||||
|
coursewareDocument,
|
||||||
|
classHourDuration,
|
||||||
|
creditHours,
|
||||||
|
}) =>
|
||||||
|
add({
|
||||||
|
coursewareId: id,
|
||||||
|
coursewareName,
|
||||||
|
coursewareDocument,
|
||||||
|
classHourDuration,
|
||||||
|
creditHours,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
setSelectOpen(false);
|
||||||
|
}}
|
||||||
|
onCancel={() => setSelectOpen(false)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.List>
|
||||||
|
</Form>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Spin>
|
||||||
|
</PageLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 选择课件弹窗:数据源同培训课件管理列表 */
|
||||||
|
function CoursewareSelectModal({
|
||||||
|
open,
|
||||||
|
loading,
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
open={open}
|
||||||
|
title="添加课件"
|
||||||
|
width={760}
|
||||||
|
destroyOnHidden
|
||||||
|
okText={`确定${selectedRows.length ? `(已选 ${selectedRows.length})` : ""}`}
|
||||||
|
okButtonProps={{ disabled: !selectedRows.length }}
|
||||||
|
onOk={() => onOk(selectedRows)}
|
||||||
|
onCancel={onCancel}
|
||||||
|
afterOpenChange={(visible) => {
|
||||||
|
if (visible) {
|
||||||
|
setKeyword("");
|
||||||
|
setSelectedRows([]);
|
||||||
|
handleSearch({ current: 1, size: 10 });
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<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, coursewareName: value })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Table
|
||||||
|
rowKey="id"
|
||||||
|
size="small"
|
||||||
|
loading={loading}
|
||||||
|
columns={[
|
||||||
|
{ title: "课件名称", dataIndex: "coursewareName", ellipsis: true },
|
||||||
|
{
|
||||||
|
title: "培训类型",
|
||||||
|
dataIndex: "trainingType",
|
||||||
|
width: 180,
|
||||||
|
render: (v) => COURSEWARE_TRAINING_TYPE_MAP[v] ?? (v || "-"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "课时时长(小时)",
|
||||||
|
dataIndex: "classHourDuration",
|
||||||
|
width: 130,
|
||||||
|
render: (v) => (v == null ? "-" : v),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "学时",
|
||||||
|
dataIndex: "creditHours",
|
||||||
|
width: 80,
|
||||||
|
render: (v) => (v == null ? "-" : v),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "操作",
|
||||||
|
width: 80,
|
||||||
|
render: (_, record) => {
|
||||||
|
const data = JSON.parse(record.coursewareDocument || "[]")?.[0] || {};
|
||||||
|
return <TableAction>
|
||||||
|
<PreviewUrlButton url={data.url} >预览</PreviewUrlButton>
|
||||||
|
</TableAction>
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
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,
|
||||||
|
coursewareName: query.coursewareName,
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Connect([NS_COURSEWARE], true)(CourseAddPage);
|
||||||
|
|
@ -0,0 +1,202 @@
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { Badge, Button, Form, Table, message } from "antd";
|
||||||
|
import { PlusOutlined } from "@ant-design/icons";
|
||||||
|
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 { 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_OPTIONS,
|
||||||
|
} from "~/enumerate/constant";
|
||||||
|
|
||||||
|
const { router } = tools;
|
||||||
|
|
||||||
|
/** 培训课程管理 */
|
||||||
|
function CourseManagePage(props) {
|
||||||
|
const [searchForm] = Form.useForm();
|
||||||
|
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: 180,
|
||||||
|
fixed: "right",
|
||||||
|
render: (_, record) => (
|
||||||
|
<TableAction>
|
||||||
|
<Button
|
||||||
|
type="link"
|
||||||
|
size="small"
|
||||||
|
onClick={() =>
|
||||||
|
props.history.push(`Add?courseId=${record.id}&mode=view`)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="link"
|
||||||
|
size="small"
|
||||||
|
onClick={() => props.history.push(`Add?courseId=${record.id}`)}
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
danger
|
||||||
|
type="link"
|
||||||
|
size="small"
|
||||||
|
onClick={() => message.info("课程删除接口待接入")}
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</Button>
|
||||||
|
</TableAction>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageLayout
|
||||||
|
title="培训课程管理"
|
||||||
|
extra={
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
icon={<PlusOutlined />}
|
||||||
|
onClick={() => props.history.push("Add")}
|
||||||
|
>
|
||||||
|
新增
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<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();
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</PageLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Connect(
|
||||||
|
[NS_COURSEWARE],
|
||||||
|
true,
|
||||||
|
)(AntdTableFuncControl(CourseManagePage));
|
||||||
|
|
@ -1,299 +1,6 @@
|
||||||
import { useEffect, useState } from "react";
|
import React 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;
|
/** 课程管理路由出口(List 课程列表 / Add 新增课程) */
|
||||||
|
export default function CourseManage(props) {
|
||||||
/** 解析课件文档字段:JSON 数组字符串,容错非法格式 */
|
return props.children;
|
||||||
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));
|
|
||||||
|
|
|
||||||
|
|
@ -295,10 +295,15 @@ const menuItems = [
|
||||||
icon: <FileTextOutlined />,
|
icon: <FileTextOutlined />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "/safetyEval/container/EduTraining/CourseManage",
|
key: "/safetyEval/container/EduTraining/CourseManage/List",
|
||||||
label: "培训课程管理",
|
label: "培训课程管理",
|
||||||
icon: <FileTextOutlined />,
|
icon: <FileTextOutlined />,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: "/safetyEval/container/EduTraining/ClassManage",
|
||||||
|
label: "班级管理",
|
||||||
|
icon: <FileTextOutlined />,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: "/safetyEval/container/EduTraining/PaperManage/List",
|
key: "/safetyEval/container/EduTraining/PaperManage/List",
|
||||||
label: "试卷管理",
|
label: "试卷管理",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue