2026-06-23 18:07:30 +08:00
|
|
|
|
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
|
|
|
|
import { Button, DatePicker, Descriptions, Form, Input, message, Modal, Select } from "antd";
|
|
|
|
|
|
import { useEffect, useState } from "react";
|
|
|
|
|
|
import AddIcon from "zy-react-library/components/Icon/AddIcon";
|
|
|
|
|
|
import Page from "zy-react-library/components/Page";
|
|
|
|
|
|
import Search from "zy-react-library/components/Search";
|
|
|
|
|
|
import Table from "zy-react-library/components/Table";
|
|
|
|
|
|
import Upload from "zy-react-library/components/Upload";
|
|
|
|
|
|
import useTable from "zy-react-library/hooks/useTable";
|
2026-06-25 16:30:37 +08:00
|
|
|
|
import { asId } from "~/api/enterpriseInfo/idUtil";
|
2026-06-23 18:07:30 +08:00
|
|
|
|
import { NS_STAFF_INFO, NS_STAFF_RESIGNATION_APPLY } from "~/enumerate/namespace";
|
|
|
|
|
|
import { safeListRequest, safeRequest } from "~/utils";
|
|
|
|
|
|
import { formSelectField, getResignAuditStatusLabel } from "~/utils/enterpriseForm";
|
|
|
|
|
|
import { DEFAULT_UPLOAD_FILE_URL, mockUploadFileList, resolveUploadFileId } from "~/utils/mockUpload";
|
|
|
|
|
|
import PageHeader from "../components/PageHeader";
|
|
|
|
|
|
|
|
|
|
|
|
const RESIGN_AUDIT_STATUS = { 0: "未审核", 1: "已审核", 2: "已退回" };
|
|
|
|
|
|
|
|
|
|
|
|
function ResignationApplyPage(props) {
|
|
|
|
|
|
const [addModalOpen, setAddModalOpen] = useState(false);
|
|
|
|
|
|
const [viewModalOpen, setViewModalOpen] = useState(false);
|
|
|
|
|
|
const [currentId, setCurrentId] = useState("");
|
|
|
|
|
|
const [staffOptions, setStaffOptions] = useState([]);
|
|
|
|
|
|
const [searchForm] = Form.useForm();
|
|
|
|
|
|
|
|
|
|
|
|
const { tableProps, getData } = useTable(safeListRequest(props.staffResignationApplyList), { form: searchForm });
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
getData();
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
let cancelled = false;
|
|
|
|
|
|
props.staffInfoList?.({ pageIndex: 1, pageSize: 500 }).then((res) => {
|
|
|
|
|
|
if (!cancelled) {
|
|
|
|
|
|
setStaffOptions((res?.data || []).map((s) => ({
|
|
|
|
|
|
label: `${s.staffName}(${s.account})`,
|
2026-06-25 16:30:37 +08:00
|
|
|
|
value: asId(s.id),
|
2026-06-23 18:07:30 +08:00
|
|
|
|
staffName: s.staffName,
|
|
|
|
|
|
account: s.account,
|
|
|
|
|
|
})));
|
|
|
|
|
|
}
|
|
|
|
|
|
}).catch((err) => {
|
|
|
|
|
|
console.warn("[ResignationApply] load staff options failed:", err);
|
|
|
|
|
|
});
|
|
|
|
|
|
return () => {
|
|
|
|
|
|
cancelled = true;
|
|
|
|
|
|
};
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<Page isShowAllAction={false}>
|
|
|
|
|
|
<PageHeader
|
|
|
|
|
|
title="人员离职申请"
|
|
|
|
|
|
subTitle="机构管理员在人员信息管理页面进行相应的修改操作"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<Search
|
|
|
|
|
|
form={searchForm}
|
|
|
|
|
|
options={[
|
|
|
|
|
|
{ name: "likeStaffName", label: "姓名", placeholder: "请输入姓名", colProps: { xs: 24, sm: 12, md: 8, lg: 6 } },
|
|
|
|
|
|
formSelectField(
|
|
|
|
|
|
"auditStatus",
|
|
|
|
|
|
"离职申请审核状态",
|
|
|
|
|
|
Object.entries(RESIGN_AUDIT_STATUS).map(([value, label]) => ({ label, value: Number(value) })),
|
|
|
|
|
|
{ colProps: { xs: 24, sm: 12, md: 8, lg: 8 }, placeholder: "请选择审核状态" },
|
|
|
|
|
|
),
|
|
|
|
|
|
]}
|
|
|
|
|
|
onFinish={getData}
|
|
|
|
|
|
/>
|
|
|
|
|
|
<Table
|
|
|
|
|
|
toolBarRender={() => (
|
|
|
|
|
|
<Button
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
icon={<AddIcon />}
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
setCurrentId("");
|
|
|
|
|
|
setAddModalOpen(true);
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
新增离职申请
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
)}
|
|
|
|
|
|
columns={[
|
|
|
|
|
|
{ title: "账户", dataIndex: "account" },
|
|
|
|
|
|
{ title: "姓名", dataIndex: "applicantName" },
|
|
|
|
|
|
{ title: "部门", dataIndex: "deptName" },
|
|
|
|
|
|
{ title: "申请时间", dataIndex: "applyTime" },
|
|
|
|
|
|
{
|
|
|
|
|
|
title: "离职申请审核状态",
|
|
|
|
|
|
dataIndex: "auditStatus",
|
|
|
|
|
|
render: (_, record) => getResignAuditStatusLabel(record),
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: "操作",
|
|
|
|
|
|
width: 100,
|
|
|
|
|
|
render: (_, record) => (
|
|
|
|
|
|
<Button
|
|
|
|
|
|
type="link"
|
|
|
|
|
|
onClick={() => {
|
2026-06-25 16:30:37 +08:00
|
|
|
|
setCurrentId(asId(record.id));
|
2026-06-23 18:07:30 +08:00
|
|
|
|
setViewModalOpen(true);
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
查看
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
),
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
{...tableProps}
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
|
|
{addModalOpen && (
|
|
|
|
|
|
<AddModal
|
|
|
|
|
|
open={addModalOpen}
|
|
|
|
|
|
staffOptions={staffOptions}
|
|
|
|
|
|
requestAdd={props.staffResignationApplyAdd}
|
|
|
|
|
|
onCancel={() => setAddModalOpen(false)}
|
|
|
|
|
|
onSuccess={getData}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
{viewModalOpen && (
|
|
|
|
|
|
<ViewModal
|
|
|
|
|
|
open={viewModalOpen}
|
|
|
|
|
|
currentId={currentId}
|
|
|
|
|
|
requestDetails={props.staffResignationApplyInfo}
|
|
|
|
|
|
onCancel={() => {
|
|
|
|
|
|
setViewModalOpen(false);
|
|
|
|
|
|
setCurrentId("");
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</Page>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function AddModal({ open, staffOptions, requestAdd, onCancel, onSuccess }) {
|
|
|
|
|
|
const [form] = Form.useForm();
|
|
|
|
|
|
const [submitting, setSubmitting] = useState(false);
|
|
|
|
|
|
|
|
|
|
|
|
const handleCancel = () => {
|
|
|
|
|
|
form.resetFields();
|
|
|
|
|
|
onCancel();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const onApplicantChange = (personnelId) => {
|
|
|
|
|
|
const staff = staffOptions.find((s) => String(s.value) === String(personnelId));
|
|
|
|
|
|
form.setFieldsValue({
|
|
|
|
|
|
applicantName: staff?.staffName || "",
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleSubmit = async (values) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
setSubmitting(true);
|
2026-06-26 14:27:49 +08:00
|
|
|
|
const staff = staffOptions.find((s) => String(s.value) === String(values.personnelId));
|
|
|
|
|
|
values.applicantName = staff?.staffName || values.applicantName;
|
2026-06-23 18:07:30 +08:00
|
|
|
|
values.attachmentId = resolveUploadFileId(values.resignReport);
|
|
|
|
|
|
const res = await requestAdd(values);
|
|
|
|
|
|
if (res?.success !== false) {
|
|
|
|
|
|
message.success("提交成功");
|
|
|
|
|
|
handleCancel();
|
|
|
|
|
|
onSuccess();
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
message.error(res?.message || "提交失败");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
finally {
|
|
|
|
|
|
setSubmitting(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<Modal
|
|
|
|
|
|
open={open}
|
|
|
|
|
|
destroyOnClose
|
|
|
|
|
|
title="添加离职申请"
|
|
|
|
|
|
width={720}
|
|
|
|
|
|
confirmLoading={submitting}
|
|
|
|
|
|
onCancel={handleCancel}
|
|
|
|
|
|
onOk={form.submit}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Form form={form} layout="vertical" onFinish={handleSubmit}>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="personnelId"
|
|
|
|
|
|
label="申请人"
|
|
|
|
|
|
rules={[{ required: true, message: "请选择申请人" }]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Select
|
|
|
|
|
|
showSearch
|
|
|
|
|
|
placeholder="请选择申请人"
|
|
|
|
|
|
options={staffOptions}
|
|
|
|
|
|
optionFilterProp="label"
|
|
|
|
|
|
onChange={onApplicantChange}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
<Form.Item name="applicantName" hidden>
|
|
|
|
|
|
<Input />
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="applyTime"
|
|
|
|
|
|
label="申请时间"
|
|
|
|
|
|
rules={[{ required: true, message: "请选择申请时间" }]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<DatePicker showTime style={{ width: "100%" }} />
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="expectedLeaveDate"
|
|
|
|
|
|
label="预计离职日期"
|
|
|
|
|
|
rules={[{ required: true, message: "请选择预计离职日期" }]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<DatePicker style={{ width: "100%" }} />
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="leaveReason"
|
|
|
|
|
|
label="离职原因"
|
|
|
|
|
|
rules={[{ required: true, message: "请输入离职原因" }]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Input.TextArea rows={3} placeholder="请输入离职原因" />
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
<Form.Item name="remark" label="备注">
|
|
|
|
|
|
<Input.TextArea rows={2} placeholder="请输入备注" />
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="resignReport"
|
|
|
|
|
|
label="离职通知报告"
|
|
|
|
|
|
rules={[{ required: true, message: "请上传离职通知报告" }]}
|
|
|
|
|
|
valuePropName="fileList"
|
|
|
|
|
|
getValueFromEvent={(e) => e?.fileList}
|
|
|
|
|
|
initialValue={mockUploadFileList("离职通知报告.pdf")}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Upload
|
|
|
|
|
|
accept=".pdf"
|
|
|
|
|
|
maxCount={1}
|
|
|
|
|
|
tip="联调阶段默认通过,使用固定文件地址"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
</Form>
|
|
|
|
|
|
</Modal>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function ViewModal({ open, currentId, requestDetails, onCancel }) {
|
|
|
|
|
|
const [info, setInfo] = useState({});
|
|
|
|
|
|
const [detailLoading, setDetailLoading] = useState(false);
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
if (!open || !currentId) {
|
|
|
|
|
|
setInfo({});
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
let cancelled = false;
|
|
|
|
|
|
setDetailLoading(true);
|
|
|
|
|
|
safeRequest(requestDetails, { id: currentId }).then((res) => {
|
|
|
|
|
|
if (!cancelled) {
|
|
|
|
|
|
const data = res?.data || {};
|
|
|
|
|
|
setInfo({
|
|
|
|
|
|
...data,
|
|
|
|
|
|
resignReport: data.attachmentId
|
|
|
|
|
|
? [{ name: "离职通知报告.pdf", fileName: "离职通知报告.pdf", url: data.attachmentId || DEFAULT_UPLOAD_FILE_URL }]
|
|
|
|
|
|
: [],
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}).finally(() => {
|
|
|
|
|
|
if (!cancelled) {
|
|
|
|
|
|
setDetailLoading(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
return () => {
|
|
|
|
|
|
cancelled = true;
|
|
|
|
|
|
};
|
|
|
|
|
|
}, [open, currentId]);
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<Modal
|
|
|
|
|
|
open={open}
|
|
|
|
|
|
destroyOnClose
|
|
|
|
|
|
title="查看离职申请"
|
|
|
|
|
|
width={720}
|
|
|
|
|
|
loading={detailLoading}
|
|
|
|
|
|
cancelText="返回"
|
|
|
|
|
|
okButtonProps={{ style: { display: "none" } }}
|
|
|
|
|
|
onCancel={onCancel}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Descriptions bordered column={1} labelStyle={{ width: 120 }}>
|
|
|
|
|
|
<Descriptions.Item label="申请人">{info.applicantName}</Descriptions.Item>
|
|
|
|
|
|
<Descriptions.Item label="申请时间">{info.applyTime}</Descriptions.Item>
|
|
|
|
|
|
<Descriptions.Item label="预计离职日期">{info.expectedLeaveDate}</Descriptions.Item>
|
|
|
|
|
|
<Descriptions.Item label="离职原因">{info.leaveReason}</Descriptions.Item>
|
|
|
|
|
|
<Descriptions.Item label="备注">{info.remark}</Descriptions.Item>
|
|
|
|
|
|
<Descriptions.Item label="离职通知报告">
|
|
|
|
|
|
{info.resignReport?.[0]?.fileName || info.resignReport?.[0]?.name || "-"}
|
|
|
|
|
|
</Descriptions.Item>
|
|
|
|
|
|
</Descriptions>
|
|
|
|
|
|
</Modal>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default Connect([NS_STAFF_RESIGNATION_APPLY, NS_STAFF_INFO], true)(ResignationApplyPage);
|