safety-eval-service-frontend/src/pages/Container/EnterpriseInfo/PersonnelInfo/StaffViewModal.js

234 lines
9.8 KiB
JavaScript
Raw Normal View History

2026-07-07 09:07:19 +08:00
import { Button, Descriptions, Modal, Table } from "antd";
import { useEffect, useRef, useState } from "react";
2026-06-26 17:28:06 +08:00
import FilePreviewModal, { FilePreviewContent } from "~/components/FilePreviewModal";
import { resolvePreviewSrc } from "~/components/CertPreviewImg";
2026-06-26 17:28:06 +08:00
import { fetchStaffCertDetail, fetchStaffCertListByPersonnelId } from "~/api/staffCertificate";
2026-07-02 16:58:07 +08:00
import { fetchOrgPersonnelDetail } from "~/api/qualFiling/personnelHelper";
2026-06-26 17:28:06 +08:00
const GENDER_MAP = { 1: "男", 2: "女" };
const REGISTER_ENGINEER_MAP = { 1: "是", 2: "否" };
export default function StaffViewModal({
open,
currentId,
2026-07-02 16:58:07 +08:00
requestDetails = fetchOrgPersonnelDetail,
2026-06-26 17:28:06 +08:00
requestCertList = fetchStaffCertListByPersonnelId,
requestCertDetails = fetchStaffCertDetail,
onCancel,
}) {
const [info, setInfo] = useState({});
const [certificates, setCertificates] = useState([]);
const [detailLoading, setDetailLoading] = useState(false);
const [attachmentPreview, setAttachmentPreview] = useState(null);
const [certPreview, setCertPreview] = useState(null);
const [certPreviewLoading, setCertPreviewLoading] = useState(false);
const [certPreviewInfo, setCertPreviewInfo] = useState(null);
const requestDetailsRef = useRef(requestDetails);
const requestCertListRef = useRef(requestCertList);
const requestCertDetailsRef = useRef(requestCertDetails);
requestDetailsRef.current = requestDetails;
requestCertListRef.current = requestCertList;
requestCertDetailsRef.current = requestCertDetails;
2026-06-26 17:28:06 +08:00
useEffect(() => {
if (!open || !currentId) {
setInfo({});
setCertificates([]);
return;
}
let cancelled = false;
setDetailLoading(true);
2026-07-07 09:07:19 +08:00
const loadCertList = requestCertListRef.current;
2026-06-26 17:28:06 +08:00
Promise.all([
2026-07-07 09:07:19 +08:00
Promise.resolve(requestDetailsRef.current({ id: currentId })).catch((err) => {
console.warn("[StaffViewModal] load detail failed:", err);
return { data: {} };
}),
typeof loadCertList === "function"
? Promise.resolve(loadCertList(currentId)).catch((err) => {
2026-06-26 17:28:06 +08:00
console.warn("[StaffViewModal] load certificates failed:", err);
return [];
})
: Promise.resolve([]),
]).then(([detailRes, certList]) => {
if (!cancelled) {
setInfo(detailRes?.data || {});
setCertificates(Array.isArray(certList) ? certList : []);
}
}).finally(() => {
if (!cancelled) {
setDetailLoading(false);
}
});
return () => {
cancelled = true;
};
}, [open, currentId]);
2026-06-26 17:28:06 +08:00
const openCertPreview = async (record) => {
setCertPreview(record);
setCertPreviewInfo(null);
if (typeof requestCertDetailsRef.current !== "function") {
2026-06-26 17:28:06 +08:00
setCertPreviewInfo(record);
return;
}
setCertPreviewLoading(true);
try {
2026-07-07 09:07:19 +08:00
const res = await requestCertDetailsRef.current({ id: record.id });
2026-06-26 17:28:06 +08:00
setCertPreviewInfo(res?.data || record);
2026-07-07 09:07:19 +08:00
} catch (err) {
console.warn("[StaffViewModal] load cert detail failed:", err);
setCertPreviewInfo(record);
} finally {
2026-06-26 17:28:06 +08:00
setCertPreviewLoading(false);
}
};
const proofFiles = info.proofMaterials || [];
const certPreviewFiles = certPreviewInfo?.certImgs?.length
? certPreviewInfo.certImgs
: certPreviewInfo?.certImgFiles || [];
const certPreviewUrl = resolvePreviewSrc(certPreviewFiles[0]);
2026-06-26 17:28:06 +08:00
const certPreviewName = certPreviewFiles[0]?.fileName || certPreviewFiles[0]?.name || certPreviewInfo?.certName;
return (
<>
<Modal
open={open}
2026-07-06 18:06:49 +08:00
destroyOnHidden
2026-06-26 17:28:06 +08:00
title="查看"
width={900}
loading={detailLoading}
cancelText="关闭"
okButtonProps={{ style: { display: "none" } }}
onCancel={onCancel}
>
<Descriptions bordered column={2} labelStyle={{ width: 120 }}>
<Descriptions.Item label="姓名">{info.staffName}</Descriptions.Item>
<Descriptions.Item label="性别">{GENDER_MAP[info.gender]}</Descriptions.Item>
<Descriptions.Item label="出生日期">{info.birthDate}</Descriptions.Item>
<Descriptions.Item label="账号">{info.account}</Descriptions.Item>
<Descriptions.Item label="部门">{info.deptName}</Descriptions.Item>
<Descriptions.Item label="岗位">{info.positionName}</Descriptions.Item>
<Descriptions.Item label="人员类型">{info.personType || "基础人员"}</Descriptions.Item>
<Descriptions.Item label="资质范围">{info.qualScope || "-"}</Descriptions.Item>
<Descriptions.Item label="职业等级">{info.professionalLevel || "-"}</Descriptions.Item>
<Descriptions.Item label="证书编号">{info.evaluatorCertNo || "-"}</Descriptions.Item>
<Descriptions.Item label="学历类型">{info.educationType || "-"}</Descriptions.Item>
<Descriptions.Item label="学历层次">{info.educationLevel || "-"}</Descriptions.Item>
<Descriptions.Item label="职称">{info.titleName || "-"}</Descriptions.Item>
<Descriptions.Item label="是否注册安全工程师">
{REGISTER_ENGINEER_MAP[info.registerEngineerFlag] ?? "-"}
</Descriptions.Item>
<Descriptions.Item label="身份证号">{info.idCardNo}</Descriptions.Item>
<Descriptions.Item label="学历">{info.education || "-"}</Descriptions.Item>
<Descriptions.Item label="现住地址" span={2}>{info.homeAddress}</Descriptions.Item>
<Descriptions.Item label="办公地址" span={2}>{info.officeAddress}</Descriptions.Item>
<Descriptions.Item label="毕业院校">{info.graduateSchool}</Descriptions.Item>
<Descriptions.Item label="专业">{info.major}</Descriptions.Item>
<Descriptions.Item label="出版学术专著、专利、获奖、发表学术论文等" span={2}>
{info.publications || "-"}
</Descriptions.Item>
<Descriptions.Item label="自我申报的专业能力及认定方式" span={2}>
{info.abilityDeclaration || "-"}
</Descriptions.Item>
<Descriptions.Item label="主要学习工作经历" span={2}>
{info.workExperience || "-"}
</Descriptions.Item>
<Descriptions.Item label="申报专业能力证明材料" span={2}>
{proofFiles.length ? (
2026-07-07 09:07:19 +08:00
<div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
2026-06-26 17:28:06 +08:00
{proofFiles.map((file, index) => {
const fileName = file.name || file.fileName || `专业能力证明${index + 1}.pdf`;
return (
2026-07-07 09:07:19 +08:00
<div key={`${fileName}-${index}`} style={{ display: "flex", alignItems: "center", gap: 8 }}>
2026-06-26 17:28:06 +08:00
<Button
type="link"
size="small"
style={{ padding: 0 }}
onClick={() => setAttachmentPreview({ url: file.url, fileName })}
>
查看附件
</Button>
<span>{fileName}</span>
2026-07-07 09:07:19 +08:00
</div>
2026-06-26 17:28:06 +08:00
);
})}
2026-07-07 09:07:19 +08:00
</div>
2026-06-26 17:28:06 +08:00
) : "-"}
</Descriptions.Item>
</Descriptions>
<div style={{ marginTop: 16, marginBottom: 8, fontWeight: 600 }}>证照信息</div>
<Table
size="small"
bordered
rowKey="id"
pagination={false}
dataSource={certificates}
locale={{ emptyText: "暂无证照信息" }}
columns={[
{ title: "证照名称", dataIndex: "certName" },
{ title: "证书编号", dataIndex: "certNo" },
{ title: "证书类别", dataIndex: "certCategory" },
{ title: "发证机关", dataIndex: "issueOrg" },
{ title: "有效开始日期", dataIndex: "validStartDate", width: 120 },
{ title: "有效结束日期", dataIndex: "validEndDate", width: 120 },
{
title: "操作",
width: 90,
render: (_, record) => (
<Button type="link" size="small" onClick={() => openCertPreview(record)}>查看证书</Button>
),
},
]}
/>
</Modal>
<FilePreviewModal
open={!!attachmentPreview}
title="附件预览"
fileName={attachmentPreview?.fileName}
url={attachmentPreview?.url}
onCancel={() => setAttachmentPreview(null)}
/>
<Modal
open={!!certPreview}
2026-07-06 18:06:49 +08:00
destroyOnHidden
2026-06-26 17:28:06 +08:00
title="证书预览"
width={720}
loading={certPreviewLoading}
cancelText="关闭"
okText={certPreviewUrl ? "新窗口打开" : "关闭"}
okButtonProps={{ style: certPreviewUrl ? undefined : { display: "none" } }}
onCancel={() => {
setCertPreview(null);
setCertPreviewInfo(null);
}}
onOk={() => {
if (certPreviewUrl) {
window.open(certPreviewUrl, "_blank");
}
setCertPreview(null);
setCertPreviewInfo(null);
}}
>
{certPreviewInfo && (
<div>
<Descriptions bordered column={1} size="small" style={{ marginBottom: 12 }}>
<Descriptions.Item label="证照名称">{certPreviewInfo.certName}</Descriptions.Item>
<Descriptions.Item label="证书编号">{certPreviewInfo.certNo}</Descriptions.Item>
<Descriptions.Item label="证书类别">{certPreviewInfo.certCategory || "-"}</Descriptions.Item>
<Descriptions.Item label="发证机关">{certPreviewInfo.issueOrg || "-"}</Descriptions.Item>
<Descriptions.Item label="有效开始日期">{certPreviewInfo.validStartDate || "-"}</Descriptions.Item>
<Descriptions.Item label="有效结束日期">{certPreviewInfo.validEndDate || "-"}</Descriptions.Item>
</Descriptions>
<FilePreviewContent url={certPreviewUrl} fileName={certPreviewName} />
</div>
)}
</Modal>
</>
);
2026-07-07 09:07:19 +08:00
}