tangjie 2026-08-24 18:31:18 +08:00
commit 0bcd00608a
4 changed files with 146 additions and 54 deletions

View File

@ -120,6 +120,18 @@ export const classRemove = declareRequest(
"Post > @/safetyEval/classManagement/delete", "Post > @/safetyEval/classManagement/delete",
); );
/** 班级延期 */
export const classDelay = declareRequest(
"classDelayLoading",
"Post > @/safetyEval/classManagement/delay",
);
/** 班级完成(申请开班) */
export const classComplete = declareRequest(
"classCompleteLoading",
"Post > @/safetyEval/classManagement/complete",
);
/** 绑定试卷(请求体:{ id, paperId, paperType, examMinutes } */ /** 绑定试卷(请求体:{ id, paperId, paperType, examMinutes } */
export const classBindPaper = declareRequest( export const classBindPaper = declareRequest(
"classBindPaperLoading", "classBindPaperLoading",

View File

@ -6,6 +6,7 @@ import {
Form, Form,
Input, Input,
InputNumber, InputNumber,
Modal,
Radio, Radio,
Row, Row,
Select, Select,
@ -18,7 +19,7 @@ import dayjs from "dayjs";
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout"; import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
import { Connect } from "@cqsjjb/jjb-dva-runtime"; import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { tools } from "@cqsjjb/jjb-common-lib"; import { tools } from "@cqsjjb/jjb-common-lib";
import { NS_COURSEWARE } from "~/enumerate/namespace"; import { NS_COURSEWARE, NS_ORG_INFO } from "~/enumerate/namespace";
import { import {
CLASS_UNIT_TYPE_OPTIONS, CLASS_UNIT_TYPE_OPTIONS,
CLASS_YES_NO_OPTIONS, CLASS_YES_NO_OPTIONS,
@ -35,27 +36,50 @@ function ClassAddPage(props) {
const [form] = Form.useForm(); const [form] = Form.useForm();
/** 已保存的班级 id有值时解锁学员/课程 Tab */ /** 已保存的班级 id有值时解锁学员/课程 Tab */
const [savedClassId, setSavedClassId] = useState(router.query.classId); const [savedClassId, setSavedClassId] = useState(router.query.classId);
const [orgOptions, setOrgOptions] = useState([]);
const [activeTab, setActiveTab] = useState("base");
const isEdit = !!router.query.classId; const isEdit = !!router.query.classId;
const [classStatus, setClassStatus] = useState(isEdit ? undefined : 0);
const unlocked = !!savedClassId; const unlocked = !!savedClassId;
const confirmLoading = props.courseware?.classConfirmLoading; const confirmLoading = props.courseware?.classConfirmLoading;
const completeLoading = props.courseware?.classCompleteLoading;
const detailLoading = props.courseware?.classDetailLoading; const detailLoading = props.courseware?.classDetailLoading;
/** 是否开启考试:选否时隐藏其余考试相关字段 */ /** 是否开启考试:选否时隐藏其余考试相关字段 */
const openExam = Form.useWatch("openExam", form); const openExam = Form.useWatch("openExam", form);
const handleUnitChange = (unitId) => {
const target = orgOptions.find((item) => item.value === unitId);
form.setFieldValue("unitName", target?.label);
};
useEffect(() => { useEffect(() => {
if (!isEdit) return;
(async () => { (async () => {
const orgRes = await props.registeredOrgList({ current: 1, size: 200, state: 0 });
const list = orgRes?.data || [];
const options = list.map((item) => ({
label: item.unitName,
value: item.id,
}));
setOrgOptions(options);
if (!isEdit) return;
const res = await props.classDetail({ id: router.query.classId }); const res = await props.classDetail({ id: router.query.classId });
if (res?.success !== false && res?.data) { if (res?.success !== false && res?.data) {
const data = res.data; const data = res.data;
let unitId = data.unitId;
if (!unitId && data.unitName) {
unitId = options.find((item) => item.label === data.unitName)?.value;
}
form.setFieldsValue({ form.setFieldsValue({
...data, ...data,
unitId,
trainingDateRange: trainingDateRange:
data.startDate && data.endDate data.startDate && data.endDate
? [dayjs(data.startDate), dayjs(data.endDate)] ? [dayjs(data.startDate), dayjs(data.endDate)]
: undefined, : undefined,
}); });
setClassStatus(data.status);
} else { } else {
props.history.goBack(); props.history.goBack();
} }
@ -90,6 +114,21 @@ function ClassAddPage(props) {
} }
}; };
const handleComplete = () => {
Modal.confirm({
title: "提示",
content: "完成之后将开班,不能再进行其它更改,确认继续吗?",
okText: "确定",
cancelText: "取消",
onOk: async () => {
const res = await props.classComplete({ id: savedClassId });
if (res?.success === false) return;
message.success("完成成功");
props.history.goBack();
},
});
};
return ( return (
<PageLayout <PageLayout
title={isEdit ? "编辑班级" : "新增班级"} title={isEdit ? "编辑班级" : "新增班级"}
@ -101,10 +140,17 @@ function ClassAddPage(props) {
<Button type="primary" loading={confirmLoading} onClick={handleSubmit}> <Button type="primary" loading={confirmLoading} onClick={handleSubmit}>
保存 保存
</Button> </Button>
{activeTab === "course" && unlocked && classStatus === 0 && (
<Button type="primary" loading={completeLoading} onClick={handleComplete}>
完成
</Button>
)}
</Space> </Space>
} }
> >
<Tabs <Tabs
activeKey={activeTab}
onChange={setActiveTab}
items={[ items={[
{ {
key: "base", key: "base",
@ -145,42 +191,21 @@ function ClassAddPage(props) {
<Col span={12}> <Col span={12}>
<Form.Item <Form.Item
label="参训单位" label="参训单位"
name="unitName" name="unitId"
rules={[{ required: true, message: "请输入参训单位" }]} rules={[{ required: true, message: "请选择参训单位" }]}
> >
<Input placeholder="请输入参训单位" allowClear maxLength={50} /> <Select
</Form.Item> placeholder="请选择参训单位"
</Col>
<Col span={12}>
<Form.Item
label="记录人员"
name="recorder"
rules={[{ required: true, message: "请输入记录人员" }]}
>
<Input placeholder="请输入记录人员" allowClear maxLength={50} />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="考核人员"
name="assessor"
rules={[{ required: true, message: "请输入考核人员" }]}
>
<Input placeholder="请输入考核人员" allowClear maxLength={50} />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="安全管理部门负责人"
name="safetyManager"
rules={[{ required: true, message: "请输入安全管理部门负责人" }]}
>
<Input
placeholder="请输入安全管理部门负责人"
allowClear allowClear
maxLength={50} showSearch
optionFilterProp="label"
options={orgOptions}
onChange={handleUnitChange}
/> />
</Form.Item> </Form.Item>
<Form.Item name="unitName" hidden>
<Input />
</Form.Item>
</Col> </Col>
<Col span={12}> <Col span={12}>
<Form.Item <Form.Item
@ -284,4 +309,4 @@ function ClassAddPage(props) {
); );
} }
export default Connect([NS_COURSEWARE], true)(ClassAddPage); export default Connect([NS_COURSEWARE, NS_ORG_INFO], true)(ClassAddPage);

View File

@ -1,5 +1,5 @@
import { useEffect } from "react"; import { useEffect, useState } from "react";
import { Badge, Button, Form, Input, Modal, Table, message } from "antd"; import { Badge, Button, DatePicker, Form, Input, Modal, Table, message } from "antd";
import { PlusOutlined } from "@ant-design/icons"; import { PlusOutlined } from "@ant-design/icons";
import dayjs from "dayjs"; import dayjs from "dayjs";
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout"; import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
@ -40,9 +40,13 @@ const buildQuery = (value) => {
/** 教育培训 — 班级管理 */ /** 教育培训 — 班级管理 */
function ClassManagePage(props) { function ClassManagePage(props) {
const [searchForm] = Form.useForm(); const [searchForm] = Form.useForm();
const [delayForm] = Form.useForm();
const [delayOpen, setDelayOpen] = useState(false);
const [delayRecord, setDelayRecord] = useState(null);
const { courseware } = props; const { courseware } = props;
const { classList, classTotal: total, classLoading: loading } = const { classList, classTotal: total, classLoading: loading } =
courseware || {}; courseware || {};
const delayLoading = courseware?.classDelayLoading;
const handleSearch = () => { const handleSearch = () => {
props.classPage(router.query); props.classPage(router.query);
@ -75,6 +79,30 @@ function ClassManagePage(props) {
}); });
}; };
const openDelayModal = (record) => {
setDelayRecord(record);
delayForm.setFieldsValue({
delayTime: record.endDate ? dayjs(record.endDate) : dayjs(),
});
setDelayOpen(true);
};
const handleDelayOk = async () => {
try {
const values = await delayForm.validateFields();
const res = await props.classDelay({
id: delayRecord.id,
delayTime: values.delayTime.format("YYYY-MM-DD"),
});
if (res?.success === false) return;
message.success("延期成功");
setDelayOpen(false);
handleSearch();
} catch {
// 表单校验失败
}
};
const columns = [ const columns = [
{ {
title: "序号", title: "序号",
@ -156,15 +184,7 @@ function ClassManagePage(props) {
编辑 编辑
</Button> </Button>
{record.status === 2 && ( {record.status === 0 ? (
<Button
type="link"
size="small"
onClick={() => message.info("班级延期接口待接入")}
>
延期
</Button>
)}
<Button <Button
danger danger
type="link" type="link"
@ -173,6 +193,15 @@ function ClassManagePage(props) {
> >
删除 删除
</Button> </Button>
) : (
<Button
type="link"
size="small"
onClick={() => openDelayModal(record)}
>
延期
</Button>
)}
</TableAction> </TableAction>
), ),
}, },
@ -263,6 +292,30 @@ function ClassManagePage(props) {
}, },
}} }}
/> />
<Modal
title="延期"
open={delayOpen}
onCancel={() => setDelayOpen(false)}
onOk={handleDelayOk}
confirmLoading={delayLoading}
destroyOnHidden
>
<Form form={delayForm} layout="vertical">
<Form.Item
label="培训结束时间"
name="delayTime"
rules={[{ required: true, message: "请选择培训结束时间" }]}
>
<DatePicker
style={{ width: "100%" }}
disabledDate={(current) =>
current && current.startOf("day").isBefore(dayjs().startOf("day"))
}
/>
</Form.Item>
</Form>
</Modal>
</PageLayout> </PageLayout>
); );
} }

View File

@ -98,6 +98,7 @@ function CourseManagePage(props) {
> >
查看 查看
</Button> </Button>
{record.used !== 1 && (
<Button <Button
type="link" type="link"
size="small" size="small"
@ -105,6 +106,7 @@ function CourseManagePage(props) {
> >
编辑 编辑
</Button> </Button>
)}
<Button <Button
danger danger
type="link" type="link"