dev-tmp1
zhanglei 2026-08-24 18:29:53 +08:00
parent cec496fa42
commit 2a7fba03f3
4 changed files with 146 additions and 54 deletions

View File

@ -89,6 +89,18 @@ export const classRemove = declareRequest(
"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 } */
export const classBindPaper = declareRequest(
"classBindPaperLoading",

View File

@ -6,6 +6,7 @@ import {
Form,
Input,
InputNumber,
Modal,
Radio,
Row,
Select,
@ -18,7 +19,7 @@ import dayjs from "dayjs";
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { tools } from "@cqsjjb/jjb-common-lib";
import { NS_COURSEWARE } from "~/enumerate/namespace";
import { NS_COURSEWARE, NS_ORG_INFO } from "~/enumerate/namespace";
import {
CLASS_UNIT_TYPE_OPTIONS,
CLASS_YES_NO_OPTIONS,
@ -35,27 +36,50 @@ function ClassAddPage(props) {
const [form] = Form.useForm();
/** 已保存的班级 id有值时解锁学员/课程 Tab */
const [savedClassId, setSavedClassId] = useState(router.query.classId);
const [orgOptions, setOrgOptions] = useState([]);
const [activeTab, setActiveTab] = useState("base");
const isEdit = !!router.query.classId;
const [classStatus, setClassStatus] = useState(isEdit ? undefined : 0);
const unlocked = !!savedClassId;
const confirmLoading = props.courseware?.classConfirmLoading;
const completeLoading = props.courseware?.classCompleteLoading;
const detailLoading = props.courseware?.classDetailLoading;
/** 是否开启考试:选否时隐藏其余考试相关字段 */
const openExam = Form.useWatch("openExam", form);
const handleUnitChange = (unitId) => {
const target = orgOptions.find((item) => item.value === unitId);
form.setFieldValue("unitName", target?.label);
};
useEffect(() => {
if (!isEdit) return;
(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 });
if (res?.success !== false && 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({
...data,
unitId,
trainingDateRange:
data.startDate && data.endDate
? [dayjs(data.startDate), dayjs(data.endDate)]
: undefined,
});
setClassStatus(data.status);
} else {
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 (
<PageLayout
title={isEdit ? "编辑班级" : "新增班级"}
@ -101,10 +140,17 @@ function ClassAddPage(props) {
<Button type="primary" loading={confirmLoading} onClick={handleSubmit}>
保存
</Button>
{activeTab === "course" && unlocked && classStatus === 0 && (
<Button type="primary" loading={completeLoading} onClick={handleComplete}>
完成
</Button>
)}
</Space>
}
>
<Tabs
activeKey={activeTab}
onChange={setActiveTab}
items={[
{
key: "base",
@ -145,42 +191,21 @@ function ClassAddPage(props) {
<Col span={12}>
<Form.Item
label="参训单位"
name="unitName"
rules={[{ required: true, message: "请输入参训单位" }]}
name="unitId"
rules={[{ required: true, message: "请选择参训单位" }]}
>
<Input placeholder="请输入参训单位" allowClear maxLength={50} />
</Form.Item>
</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="请输入安全管理部门负责人"
<Select
placeholder="请选择参训单位"
allowClear
maxLength={50}
showSearch
optionFilterProp="label"
options={orgOptions}
onChange={handleUnitChange}
/>
</Form.Item>
<Form.Item name="unitName" hidden>
<Input />
</Form.Item>
</Col>
<Col span={12}>
<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 { Badge, Button, Form, Input, Modal, Table, message } from "antd";
import { useEffect, useState } from "react";
import { Badge, Button, DatePicker, Form, Input, Modal, Table, message } from "antd";
import { PlusOutlined } from "@ant-design/icons";
import dayjs from "dayjs";
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
@ -40,9 +40,13 @@ const buildQuery = (value) => {
/** 教育培训 — 班级管理 */
function ClassManagePage(props) {
const [searchForm] = Form.useForm();
const [delayForm] = Form.useForm();
const [delayOpen, setDelayOpen] = useState(false);
const [delayRecord, setDelayRecord] = useState(null);
const { courseware } = props;
const { classList, classTotal: total, classLoading: loading } =
courseware || {};
const delayLoading = courseware?.classDelayLoading;
const handleSearch = () => {
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 = [
{
title: "序号",
@ -156,15 +184,7 @@ function ClassManagePage(props) {
编辑
</Button>
{record.status === 2 && (
<Button
type="link"
size="small"
onClick={() => message.info("班级延期接口待接入")}
>
延期
</Button>
)}
{record.status === 0 ? (
<Button
danger
type="link"
@ -173,6 +193,15 @@ function ClassManagePage(props) {
>
删除
</Button>
) : (
<Button
type="link"
size="small"
onClick={() => openDelayModal(record)}
>
延期
</Button>
)}
</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>
);
}

View File

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