360 lines
12 KiB
JavaScript
360 lines
12 KiB
JavaScript
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||
import { Button, Descriptions, Form, Input, message, Modal, Select, Space, Table, Tag, Typography } from "antd";
|
||
import TableAction from "@cqsjjb/jjb-react-admin-component/TableAction";
|
||
import { useEffect, useState } from "react";
|
||
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
|
||
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";
|
||
import { NS_STAFF_CHANGE_LOG, NS_STAFF_INFO } from "~/enumerate/namespace";
|
||
import {
|
||
CHANGE_COUNT_STYLE,
|
||
RESIGN_AUDIT_STATUS_LABEL,
|
||
AUDIT_STATUS_COLOR,
|
||
} from "~/utils/enterpriseForm";
|
||
|
||
const { router } = tools;
|
||
|
||
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,
|
||
}));
|
||
|
||
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();
|
||
|
||
const { staffChangeLog } = props;
|
||
const {
|
||
staffChangeLogStaffList: staffList,
|
||
staffChangeLogStaffTotal: staffTotal,
|
||
staffChangeLogLoading: loading,
|
||
staffChangeLogChangeList: changeList,
|
||
staffChangeLogChangeTotal: changeTotal,
|
||
} = staffChangeLog || {};
|
||
|
||
const handleSearch = () => {
|
||
props.staffChangeLogStaffList({ ...router.query });
|
||
};
|
||
|
||
useEffect(() => {
|
||
searchForm.setFieldsValue(router.query);
|
||
handleSearch();
|
||
}, []);
|
||
|
||
const handleLogSearch = () => {
|
||
if (selectedStaff?.staffId) {
|
||
props.staffChangeLogList({ eqStaffId: selectedStaff.staffId });
|
||
}
|
||
};
|
||
|
||
useEffect(() => {
|
||
if (viewMode === "log" && selectedStaff?.staffId) {
|
||
handleLogSearch();
|
||
}
|
||
}, [viewMode, selectedStaff?.staffId]);
|
||
|
||
const onDelete = (record) => {
|
||
Modal.confirm({
|
||
title: "提示",
|
||
content: "数据将会删除,您是否确认删除?",
|
||
okText: "是",
|
||
cancelText: "否",
|
||
onOk: async () => {
|
||
const id = record.id ?? record.staffId;
|
||
if (!id) {
|
||
message.error("缺少人员ID,无法删除");
|
||
return;
|
||
}
|
||
const res = await props.staffInfoRemove?.({ id });
|
||
if (res?.success !== false) {
|
||
message.success("删除成功");
|
||
handleSearch();
|
||
} else {
|
||
message.error(res?.message || "删除失败");
|
||
}
|
||
},
|
||
});
|
||
};
|
||
|
||
const openResignAudit = async (record) => {
|
||
try {
|
||
const res = await props.staffResignationInfo({ id: record.resignApplyId });
|
||
const data = res?.data || {};
|
||
setResignInfo(data);
|
||
setSelectedStaff(record);
|
||
setRejectReason("");
|
||
setAuditModalOpen(true);
|
||
} catch {
|
||
message.error("获取离职申请详情失败");
|
||
}
|
||
};
|
||
|
||
const openResignView = async (record) => {
|
||
if (!record?.resignApplyId) {
|
||
message.warning("该人员暂无离职申请记录");
|
||
return;
|
||
}
|
||
try {
|
||
const res = await props.staffResignationInfo({ id: record.resignApplyId });
|
||
setResignInfo(res?.data || {});
|
||
setViewResignOpen(true);
|
||
} catch {
|
||
message.error("获取离职申请详情失败");
|
||
}
|
||
};
|
||
|
||
const submitAudit = async (passed) => {
|
||
if (!passed && !rejectReason?.trim()) {
|
||
message.warning("请填写退回原因");
|
||
return;
|
||
}
|
||
try {
|
||
const res = await props.staffResignationAudit({
|
||
id: resignInfo.id,
|
||
auditStatusCode: passed ? 1 : 2,
|
||
auditStatusName: passed ? "已审核" : "已退回",
|
||
rejectReason: passed ? undefined : rejectReason,
|
||
});
|
||
if (res?.success !== false) {
|
||
message.success(passed ? "审核通过" : "已退回");
|
||
setAuditModalOpen(false);
|
||
handleSearch();
|
||
} else {
|
||
message.error(res?.message || "审核操作失败");
|
||
}
|
||
} catch {
|
||
message.error("审核操作失败");
|
||
}
|
||
};
|
||
|
||
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;
|
||
const label = RESIGN_AUDIT_STATUS_LABEL[code];
|
||
return label ? <Tag color={AUDIT_STATUS_COLOR[code]}>{label}</Tag> : "-";
|
||
},
|
||
},
|
||
{
|
||
title: "操作",
|
||
width: 200,
|
||
fixed: "right",
|
||
render: (_, record) => (
|
||
<TableAction>
|
||
<Button type="link" size="small" onClick={() => openResignView(record)}>
|
||
查看离职状态
|
||
</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 },
|
||
];
|
||
|
||
if (viewMode === "log") {
|
||
return (
|
||
<PageLayout title="人员变更次数">
|
||
<Button style={{ marginBottom: 16 }} onClick={() => setViewMode("list")}>
|
||
返回
|
||
</Button>
|
||
<div style={{ marginBottom: 8 }}>人员:{selectedStaff?.staffName || selectedStaff?.userName}</div>
|
||
<Table
|
||
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();
|
||
},
|
||
}}
|
||
/>
|
||
</PageLayout>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<PageLayout
|
||
title={
|
||
<div>
|
||
<span>人员变更管理</span>
|
||
<div className="pageLayout-extra">
|
||
机构管理员在人员信息管理页面进行相应的修改操作
|
||
</div>
|
||
</div>
|
||
}
|
||
>
|
||
<SearchForm
|
||
style={{ marginBottom: 24 }}
|
||
form={searchForm}
|
||
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>,
|
||
]}
|
||
onReset={(value) => {
|
||
router.query = { ...value, current: 1, size: 10 };
|
||
handleSearch();
|
||
}}
|
||
onFinish={(value) => {
|
||
router.query = { ...value, current: 1, size: 10 };
|
||
handleSearch();
|
||
}}
|
||
/>
|
||
|
||
<Table
|
||
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();
|
||
},
|
||
}}
|
||
/>
|
||
|
||
<Modal
|
||
open={auditModalOpen}
|
||
destroyOnHidden
|
||
title="审核离职申请"
|
||
width={720}
|
||
footer={
|
||
<Space>
|
||
<Button onClick={() => setAuditModalOpen(false)}>取消</Button>
|
||
<Button danger onClick={() => submitAudit(false)}>退回</Button>
|
||
<Button type="primary" onClick={() => submitAudit(true)}>通过</Button>
|
||
</Space>
|
||
}
|
||
onCancel={() => setAuditModalOpen(false)}
|
||
>
|
||
<Descriptions bordered column={1} labelStyle={{ width: 120 }}>
|
||
<Descriptions.Item label="申请人">{resignInfo.applicantName}</Descriptions.Item>
|
||
<Descriptions.Item label="申请时间">{resignInfo.applyTime}</Descriptions.Item>
|
||
<Descriptions.Item label="预计离职日期">{resignInfo.expectedResignDate}</Descriptions.Item>
|
||
<Descriptions.Item label="离职原因">{resignInfo.resignReason}</Descriptions.Item>
|
||
<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}
|
||
destroyOnHidden
|
||
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>
|
||
<Descriptions.Item label="预计离职日期">{resignInfo.expectedResignDate}</Descriptions.Item>
|
||
<Descriptions.Item label="离职原因">{resignInfo.resignReason}</Descriptions.Item>
|
||
<Descriptions.Item label="备注">{resignInfo.remark}</Descriptions.Item>
|
||
</Descriptions>
|
||
</Modal>
|
||
</PageLayout>
|
||
);
|
||
}
|
||
|
||
export default Connect([NS_STAFF_CHANGE_LOG, NS_STAFF_INFO], true)(AntdTableFuncControl(PersonnelChangePage)); |