safety-eval-service-frontend/src/pages/Container/EnterpriseInfo/PersonnelChange/index.js

360 lines
12 KiB
JavaScript
Raw Normal View History

2026-06-23 18:07:30 +08:00
import { Connect } from "@cqsjjb/jjb-dva-runtime";
2026-07-07 09:07:19 +08:00
import { Button, Descriptions, Form, Input, message, Modal, Select, Space, Table, Tag, Typography } from "antd";
import TableAction from "@cqsjjb/jjb-react-admin-component/TableAction";
2026-06-23 18:07:30 +08:00
import { useEffect, useState } from "react";
2026-06-29 16:45:58 +08:00
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
2026-07-07 09:07:19 +08:00
import SearchForm from "@cqsjjb/jjb-react-admin-component/SearchForm";
import ControlWrapper from "@cqsjjb/jjb-react-admin-component/ControlWrapper";
import { AntdTableFuncControl } from "@cqsjjb/jjb-common-decorator/antd";
import { tools } from "@cqsjjb/jjb-common-lib";
2026-06-23 18:07:30 +08:00
import { NS_STAFF_CHANGE_LOG, NS_STAFF_INFO } from "~/enumerate/namespace";
2026-07-07 09:07:19 +08:00
import {
CHANGE_COUNT_STYLE,
RESIGN_AUDIT_STATUS_LABEL,
AUDIT_STATUS_COLOR,
} from "~/utils/enterpriseForm";
2026-06-29 16:45:58 +08:00
2026-07-07 09:07:19 +08:00
const { router } = tools;
2026-06-23 18:07:30 +08:00
2026-07-07 09:07:19 +08:00
const EMPLOYMENT_STATUS_OPTIONS = [
{ value: 1, label: "在职" },
{ value: 2, label: "离职" },
];
const RESIGN_AUDIT_OPTIONS = Object.entries(RESIGN_AUDIT_STATUS_LABEL).map(([value, label]) => ({
value: Number(value),
label,
}));
2026-06-23 18:07:30 +08:00
function PersonnelChangePage(props) {
const [viewMode, setViewMode] = useState("list");
const [selectedStaff, setSelectedStaff] = useState(null);
const [auditModalOpen, setAuditModalOpen] = useState(false);
const [viewResignOpen, setViewResignOpen] = useState(false);
const [resignInfo, setResignInfo] = useState({});
const [rejectReason, setRejectReason] = useState("");
const [searchForm] = Form.useForm();
2026-07-07 09:07:19 +08:00
const { staffChangeLog } = props;
const {
staffChangeLogStaffList: staffList,
staffChangeLogStaffTotal: staffTotal,
staffChangeLogLoading: loading,
staffChangeLogChangeList: changeList,
staffChangeLogChangeTotal: changeTotal,
} = staffChangeLog || {};
2026-06-23 18:07:30 +08:00
2026-07-07 09:07:19 +08:00
const handleSearch = () => {
props.staffChangeLogStaffList({ ...router.query });
};
2026-06-23 18:07:30 +08:00
useEffect(() => {
2026-07-07 09:07:19 +08:00
searchForm.setFieldsValue(router.query);
handleSearch();
2026-06-23 18:07:30 +08:00
}, []);
2026-07-07 09:07:19 +08:00
const handleLogSearch = () => {
if (selectedStaff?.staffId) {
props.staffChangeLogList({ eqStaffId: selectedStaff.staffId });
}
};
2026-06-23 18:07:30 +08:00
useEffect(() => {
if (viewMode === "log" && selectedStaff?.staffId) {
2026-07-07 09:07:19 +08:00
handleLogSearch();
2026-06-23 18:07:30 +08:00
}
}, [viewMode, selectedStaff?.staffId]);
const onDelete = (record) => {
Modal.confirm({
title: "提示",
content: "数据将会删除,您是否确认删除?",
okText: "是",
cancelText: "否",
onOk: async () => {
2026-07-07 15:58:05 +08:00
const id = record.id ?? record.staffId;
if (!id) {
message.error("缺少人员ID无法删除");
return;
}
const res = await props.staffInfoRemove?.({ id });
2026-06-23 18:07:30 +08:00
if (res?.success !== false) {
message.success("删除成功");
2026-07-07 09:07:19 +08:00
handleSearch();
} else {
2026-06-23 18:07:30 +08:00
message.error(res?.message || "删除失败");
}
},
});
};
const openResignAudit = async (record) => {
try {
2026-07-07 09:07:19 +08:00
const res = await props.staffResignationInfo({ id: record.resignApplyId });
const data = res?.data || {};
setResignInfo(data);
2026-06-23 18:07:30 +08:00
setSelectedStaff(record);
setRejectReason("");
setAuditModalOpen(true);
2026-07-07 09:07:19 +08:00
} catch {
2026-06-23 18:07:30 +08:00
message.error("获取离职申请详情失败");
}
};
const openResignView = async (record) => {
2026-07-07 15:58:05 +08:00
if (!record?.resignApplyId) {
message.warning("该人员暂无离职申请记录");
return;
}
2026-06-23 18:07:30 +08:00
try {
2026-07-07 09:07:19 +08:00
const res = await props.staffResignationInfo({ id: record.resignApplyId });
2026-06-23 18:07:30 +08:00
setResignInfo(res?.data || {});
setViewResignOpen(true);
2026-07-07 09:07:19 +08:00
} catch {
2026-06-23 18:07:30 +08:00
message.error("获取离职申请详情失败");
}
};
const submitAudit = async (passed) => {
if (!passed && !rejectReason?.trim()) {
message.warning("请填写退回原因");
return;
}
try {
const res = await props.staffResignationAudit({
id: resignInfo.id,
2026-07-07 09:07:19 +08:00
auditStatusCode: passed ? 1 : 2,
auditStatusName: passed ? "已审核" : "已退回",
2026-06-23 18:07:30 +08:00
rejectReason: passed ? undefined : rejectReason,
});
if (res?.success !== false) {
message.success(passed ? "审核通过" : "已退回");
setAuditModalOpen(false);
2026-07-07 09:07:19 +08:00
handleSearch();
} else {
2026-06-23 18:07:30 +08:00
message.error(res?.message || "审核操作失败");
}
2026-07-07 09:07:19 +08:00
} catch {
2026-06-23 18:07:30 +08:00
message.error("审核操作失败");
}
};
2026-07-07 09:07:19 +08:00
const staffColumns = [
{ title: "账户", dataIndex: "account", width: 130 },
{ title: "姓名", dataIndex: "userName", width: 100 },
{ title: "部门", dataIndex: "deptName", width: 120 },
{
title: "信息变更数",
dataIndex: "changeCount",
width: 110,
render: (_, record) => {
const n = Number(record.changeCount ?? 0);
const style = n > 0 ? CHANGE_COUNT_STYLE.active : CHANGE_COUNT_STYLE.zero;
if (n <= 0) {
return <span style={style}>{n}</span>;
}
return (
<Typography.Link
style={style}
onClick={() => {
setSelectedStaff(record);
setViewMode("log");
}}
>
{n}
</Typography.Link>
);
},
},
{
title: "就职状态",
dataIndex: "employmentStatusCode",
width: 90,
render: (_, record) => {
const code = record.employmentStatusCode ?? record.employmentStatus;
return <Tag color={code === 2 ? "error" : "success"}>{code === 2 ? "离职" : "在职"}</Tag>;
},
},
{
title: "离职申请审核状态",
dataIndex: "resignAuditStatus",
width: 140,
render: (_, record) => {
const code = record.resignAuditStatus ?? record.auditStatus ?? record.auditStatusCode;
2026-07-07 16:50:31 +08:00
const label = RESIGN_AUDIT_STATUS_LABEL[code];
return label ? <Tag color={AUDIT_STATUS_COLOR[code]}>{label}</Tag> : "-";
2026-07-07 09:07:19 +08:00
},
},
{
title: "操作",
width: 200,
fixed: "right",
render: (_, record) => (
<TableAction>
<Button type="link" size="small" onClick={() => openResignView(record)}>
2026-07-07 15:58:05 +08:00
查看离职状态
2026-07-07 09:07:19 +08:00
</Button>
{record.resignApplyId && Number(record.resignAuditStatus) === 0 && (
<Button type="link" size="small" onClick={() => openResignAudit(record)}>
离职审核
</Button>
)}
<Button danger type="link" size="small" onClick={() => onDelete(record)}>
删除
</Button>
</TableAction>
),
},
];
const logColumns = [
{ title: "变更事项", dataIndex: "changeItem", width: 200 },
{ title: "变更时间", dataIndex: "changeTime", width: 160 },
{ title: "操作人", dataIndex: "createBy", width: 100 },
];
2026-06-23 18:07:30 +08:00
if (viewMode === "log") {
return (
2026-06-29 16:45:58 +08:00
<PageLayout title="人员变更次数">
2026-07-07 09:07:19 +08:00
<Button style={{ marginBottom: 16 }} onClick={() => setViewMode("list")}>
返回
</Button>
<div style={{ marginBottom: 8 }}>人员{selectedStaff?.staffName || selectedStaff?.userName}</div>
2026-06-23 18:07:30 +08:00
<Table
2026-07-07 09:07:19 +08:00
rowKey="id"
columns={logColumns}
dataSource={changeList}
scroll={{ y: props.scrollY }}
loading={loading}
pagination={{
total: changeTotal,
showSizeChanger: true,
showQuickJumper: true,
showTotal: (t) => `${t}`,
current: router.query.current || 1,
pageSize: router.query.size || 10,
onChange: (page, pageSize) => {
router.query = { ...router.query, current: page, size: pageSize };
handleLogSearch();
},
}}
2026-06-23 18:07:30 +08:00
/>
2026-06-29 16:45:58 +08:00
</PageLayout>
2026-06-23 18:07:30 +08:00
);
}
return (
2026-06-30 18:30:30 +08:00
<PageLayout
title={
<div>
<span>人员变更管理</span>
<div className="pageLayout-extra">
机构管理员在人员信息管理页面进行相应的修改操作
</div>
</div>
}
>
2026-07-07 09:07:19 +08:00
<SearchForm
style={{ marginBottom: 24 }}
2026-06-23 18:07:30 +08:00
form={searchForm}
2026-07-07 09:07:19 +08:00
loading={loading}
formLine={[
<Form.Item key="account" name="account">
<ControlWrapper.Input label="账户" placeholder="请输入" allowClear />
</Form.Item>,
<Form.Item key="userName" name="userName">
<ControlWrapper.Input label="姓名" placeholder="请输入" allowClear />
</Form.Item>,
<Form.Item key="employmentStatusCode" name="employmentStatusCode">
<ControlWrapper.Select label="就职状态" placeholder="请选择" allowClear style={{ width: "100%" }}>
{EMPLOYMENT_STATUS_OPTIONS.map((o) => (
<Select.Option key={o.value} value={o.value}>{o.label}</Select.Option>
))}
</ControlWrapper.Select>
</Form.Item>,
<Form.Item key="resignAuditStatus" name="resignAuditStatus">
<ControlWrapper.Select label="复核状态" placeholder="请选择" allowClear style={{ width: "100%" }}>
{RESIGN_AUDIT_OPTIONS.map((o) => (
<Select.Option key={o.value} value={o.value}>{o.label}</Select.Option>
))}
</ControlWrapper.Select>
</Form.Item>,
2026-06-23 18:07:30 +08:00
]}
2026-07-07 11:39:02 +08:00
onReset={(value) => {
router.query = { ...value, current: 1, size: 10 };
2026-07-07 09:07:19 +08:00
handleSearch();
}}
2026-07-07 11:39:02 +08:00
onFinish={(value) => {
router.query = { ...value, current: 1, size: 10 };
2026-07-07 09:07:19 +08:00
handleSearch();
}}
2026-06-23 18:07:30 +08:00
/>
2026-07-07 09:07:19 +08:00
2026-06-23 18:07:30 +08:00
<Table
2026-07-07 09:07:19 +08:00
rowKey={(record) => record.id || record.staffId}
columns={staffColumns}
dataSource={staffList}
scroll={{ y: props.scrollY }}
loading={loading}
pagination={{
total: staffTotal,
showSizeChanger: true,
showQuickJumper: true,
showTotal: (t) => `${t}`,
current: router.query.current || 1,
pageSize: router.query.size || 10,
onChange: (page, pageSize) => {
router.query = { ...router.query, current: page, size: pageSize };
handleSearch();
2026-06-23 18:07:30 +08:00
},
2026-07-07 09:07:19 +08:00
}}
2026-06-23 18:07:30 +08:00
/>
<Modal
open={auditModalOpen}
2026-07-06 18:06:49 +08:00
destroyOnHidden
2026-06-23 18:07:30 +08:00
title="审核离职申请"
width={720}
2026-07-07 09:07:19 +08:00
footer={
2026-06-23 18:07:30 +08:00
<Space>
<Button onClick={() => setAuditModalOpen(false)}>取消</Button>
<Button danger onClick={() => submitAudit(false)}>退回</Button>
<Button type="primary" onClick={() => submitAudit(true)}>通过</Button>
</Space>
2026-07-07 09:07:19 +08:00
}
2026-06-23 18:07:30 +08:00
onCancel={() => setAuditModalOpen(false)}
>
<Descriptions bordered column={1} labelStyle={{ width: 120 }}>
<Descriptions.Item label="申请人">{resignInfo.applicantName}</Descriptions.Item>
<Descriptions.Item label="申请时间">{resignInfo.applyTime}</Descriptions.Item>
2026-07-07 09:07:19 +08:00
<Descriptions.Item label="预计离职日期">{resignInfo.expectedResignDate}</Descriptions.Item>
<Descriptions.Item label="离职原因">{resignInfo.resignReason}</Descriptions.Item>
2026-06-23 18:07:30 +08:00
<Descriptions.Item label="备注">{resignInfo.remark}</Descriptions.Item>
</Descriptions>
<Form.Item label="退回原因" style={{ marginTop: 16 }}>
<Input.TextArea rows={3} value={rejectReason} onChange={(e) => setRejectReason(e.target.value)} />
</Form.Item>
</Modal>
<Modal
open={viewResignOpen}
2026-07-06 18:06:49 +08:00
destroyOnHidden
2026-06-23 18:07:30 +08:00
title="查看离职申请"
width={720}
cancelText="返回"
okButtonProps={{ style: { display: "none" } }}
onCancel={() => setViewResignOpen(false)}
>
<Descriptions bordered column={1} labelStyle={{ width: 120 }}>
<Descriptions.Item label="申请人">{resignInfo.applicantName}</Descriptions.Item>
<Descriptions.Item label="申请时间">{resignInfo.applyTime}</Descriptions.Item>
2026-07-07 09:07:19 +08:00
<Descriptions.Item label="预计离职日期">{resignInfo.expectedResignDate}</Descriptions.Item>
<Descriptions.Item label="离职原因">{resignInfo.resignReason}</Descriptions.Item>
2026-06-23 18:07:30 +08:00
<Descriptions.Item label="备注">{resignInfo.remark}</Descriptions.Item>
</Descriptions>
</Modal>
2026-06-29 16:45:58 +08:00
</PageLayout>
2026-06-23 18:07:30 +08:00
);
}
2026-07-07 09:07:19 +08:00
export default Connect([NS_STAFF_CHANGE_LOG, NS_STAFF_INFO], true)(AntdTableFuncControl(PersonnelChangePage));