277 lines
9.3 KiB
JavaScript
277 lines
9.3 KiB
JavaScript
import { Button, Modal, message } from "antd";
|
||
import { useEffect, useRef, useState } from "react";
|
||
import { fetchOrgPersonnelDetail } from "~/utils/qualFiling/personnelHelper";
|
||
import { fillDocxTemplate } from "~/utils/fillDocxTemplate";
|
||
import { ABILITY_SOURCE_MAP } from "~/enumerate/enterpriseOptions";
|
||
import {
|
||
CERT_LEVEL_LABEL_BY_TYPE,
|
||
CAPABILITY_MAP,
|
||
} from "~/enumerate/constant";
|
||
import "./index.less";
|
||
|
||
const RESUME_TEMPLATE_URL = "https://test-dragon-yf-pub.oss-cn-hangzhou.aliyuncs.com/jjb/6a87b61be4b063db1579e790.docx";
|
||
|
||
const GENDER_MAP = { 1: "男", 2: "女" };
|
||
|
||
const parseFileList = (raw) => {
|
||
if (!raw) return [];
|
||
if (Array.isArray(raw)) return raw;
|
||
try {
|
||
const parsed = JSON.parse(raw);
|
||
return Array.isArray(parsed) ? parsed : [];
|
||
} catch {
|
||
return [];
|
||
}
|
||
};
|
||
|
||
const maskIdCard = (val) => {
|
||
if (!val || String(val).length < 8) return val || "-";
|
||
const s = String(val);
|
||
return `${s.slice(0, 14)}****`;
|
||
};
|
||
|
||
const maskPhone = (val) => {
|
||
if (!val || String(val).length < 7) return val || "-";
|
||
const s = String(val);
|
||
return `${s.slice(0, 3)}****${s.slice(-4)}`;
|
||
};
|
||
|
||
const display = (val) => {
|
||
if (val === 0) return "0";
|
||
if (val == null || val === "") return "-";
|
||
return val;
|
||
};
|
||
|
||
export default function StaffResumeModal({
|
||
open,
|
||
currentId,
|
||
requestDetails = fetchOrgPersonnelDetail,
|
||
onCancel,
|
||
}) {
|
||
const [info, setInfo] = useState({});
|
||
const [detailLoading, setDetailLoading] = useState(false);
|
||
const [downloading, setDownloading] = useState(false);
|
||
const requestDetailsRef = useRef(requestDetails);
|
||
requestDetailsRef.current = requestDetails;
|
||
|
||
useEffect(() => {
|
||
if (!open || !currentId) {
|
||
setInfo({});
|
||
return;
|
||
}
|
||
let cancelled = false;
|
||
setDetailLoading(true);
|
||
|
||
Promise.resolve(requestDetailsRef.current({ id: currentId }))
|
||
.catch((err) => {
|
||
console.warn("[StaffResumeModal] load detail failed:", err);
|
||
return { data: {} };
|
||
})
|
||
.then((detailRes) => {
|
||
if (!cancelled) {
|
||
setInfo(detailRes?.data || {});
|
||
}
|
||
})
|
||
.finally(() => {
|
||
if (!cancelled) {
|
||
setDetailLoading(false);
|
||
}
|
||
});
|
||
return () => {
|
||
cancelled = true;
|
||
};
|
||
}, [open, currentId]);
|
||
|
||
const evalCert = info.evaluatorCert;
|
||
const evalLevelMap = CERT_LEVEL_LABEL_BY_TYPE.evaluator;
|
||
const evalLevelName = evalLevelMap[evalCert?.certLevel] || "";
|
||
const qualificationText =
|
||
evalLevelName || evalCert?.certNo
|
||
? [evalLevelName, evalCert?.certNo].filter(Boolean).join(" / ")
|
||
: "-";
|
||
|
||
const regCert = info.registeredSafetyEngineerCert;
|
||
const regCertFiles = parseFileList(regCert?.certAttachmentUrl);
|
||
|
||
const isZyEducation = info.educationTypeName === "在职教育";
|
||
|
||
const educationText = [info.educationTypeName, info.educationLevelName]
|
||
.filter(Boolean)
|
||
.join("") || "-";
|
||
|
||
const schoolMajorText = [info.graduateSchool, info.basicDisciplineMajorName]
|
||
.filter(Boolean)
|
||
.join(" / ") || "-";
|
||
|
||
const capabilityText = Array.isArray(info.capabilityAssessment)
|
||
? info.capabilityAssessment
|
||
.map((item) => {
|
||
const name =
|
||
CAPABILITY_MAP[item.professionalCapabilityCode] ||
|
||
item.professionalCapabilityCode ||
|
||
"";
|
||
const source =
|
||
ABILITY_SOURCE_MAP[item.professionalCapabilitySourceCode] ||
|
||
item.professionalCapabilitySourceCode ||
|
||
"";
|
||
if (!name && !source) return "";
|
||
return [name, source].filter(Boolean).join(" / ");
|
||
})
|
||
.filter(Boolean)
|
||
.join(";") || "-"
|
||
: "-";
|
||
|
||
const handleDownload = async () => {
|
||
setDownloading(true);
|
||
try {
|
||
const data = {
|
||
userName: display(info.userName),
|
||
gender: GENDER_MAP[info.genderCode] || "-",
|
||
birthDate: display(info.birthDate),
|
||
currentAddress: display(info.currentAddress),
|
||
officeAddress: display(info.officeAddress),
|
||
qualificationText,
|
||
certNo: display(regCert?.certNo),
|
||
idCardNo: maskIdCard(info.idCardNo),
|
||
phone: maskPhone(info.account),
|
||
// 全日制填 education/schoolMajor,在职教育填 ZYeducation/ZYschoolMajor
|
||
education: isZyEducation ? "" : info.educationLevelName,
|
||
schoolMajor: isZyEducation ? "" : schoolMajorText,
|
||
ZYeducation: isZyEducation ? info.educationLevelName : "",
|
||
ZYschoolMajor: isZyEducation ? schoolMajorText : "",
|
||
publications: info.publications || "无",
|
||
capability: capabilityText,
|
||
certFiles:
|
||
regCertFiles
|
||
.map(
|
||
(item) =>
|
||
item.fileName || item.name || "查看注册安全工程师资格证",
|
||
)
|
||
.join("\n") || "-",
|
||
workExperience: display(info.workExperience),
|
||
};
|
||
await fillDocxTemplate(
|
||
RESUME_TEMPLATE_URL,
|
||
data,
|
||
`安全评价师简历表_${info.userName || currentId || ""}.docx`,
|
||
{ download: true },
|
||
);
|
||
message.success("简历下载成功");
|
||
} catch (err) {
|
||
console.warn("[StaffResumeModal] download word failed:", err);
|
||
message.error("简历下载失败");
|
||
} finally {
|
||
setDownloading(false);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<Modal
|
||
open={open}
|
||
destroyOnHidden
|
||
title={'安全评价师简历表'}
|
||
width={860}
|
||
loading={detailLoading}
|
||
className="staff-resume-modal"
|
||
onCancel={onCancel}
|
||
footer={[
|
||
<Button key="download" type="primary" loading={downloading} onClick={handleDownload}>
|
||
下载简历
|
||
</Button>,
|
||
<Button key="close" onClick={onCancel}>
|
||
关闭
|
||
</Button>,
|
||
]}
|
||
>
|
||
<div style={{ background: "#fff", padding: 8 }}>
|
||
|
||
<table className="staff-resume-table">
|
||
<tbody>
|
||
<tr>
|
||
<td className="resume-label">姓名</td>
|
||
<td className="resume-value">{display(info.userName)}</td>
|
||
<td className="resume-label">性别</td>
|
||
<td className="resume-value">
|
||
{GENDER_MAP[info.genderCode] || "-"}
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td className="resume-label">出生日期</td>
|
||
<td className="resume-value">{display(info.birthDate)}</td>
|
||
<td className="resume-label">现住址</td>
|
||
<td className="resume-value">{display(info.currentAddress)}</td>
|
||
</tr>
|
||
<tr>
|
||
<td className="resume-label">办公地址</td>
|
||
<td className="resume-value">{display(info.officeAddress)}</td>
|
||
<td className="resume-label">职业资格等级及证书号码</td>
|
||
<td className="resume-value">{qualificationText}</td>
|
||
</tr>
|
||
<tr>
|
||
<td className="resume-label">注册安全工程师证书编号</td>
|
||
<td className="resume-value">{display(regCert?.certNo)}</td>
|
||
<td className="resume-label">身份证件号码</td>
|
||
<td className="resume-value">{maskIdCard(info.idCardNo)}</td>
|
||
</tr>
|
||
<tr>
|
||
<td className="resume-label">联系电话</td>
|
||
<td className="resume-value">{maskPhone(info.account)}</td>
|
||
<td className="resume-label">学历学位</td>
|
||
<td className="resume-value">{educationText}</td>
|
||
</tr>
|
||
<tr>
|
||
<td className="resume-label">毕业院校及专业</td>
|
||
<td className="resume-value">{schoolMajorText}</td>
|
||
<td className="resume-label">
|
||
出版学术专著、专利、科技发明及获奖情况
|
||
</td>
|
||
<td className="resume-value">
|
||
{info.publications ? info.publications : "无"}
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td className="resume-label-wide">
|
||
自我申报的专业能力及认定方式
|
||
</td>
|
||
<td className="resume-value-full" colSpan={3}>
|
||
{capabilityText}
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td className="resume-label-wide">申报专业能力证明材料</td>
|
||
<td className="resume-value-full" colSpan={3}>
|
||
{regCertFiles.length
|
||
? regCertFiles.map((item) => (
|
||
<div key={item.uid || item.url}>
|
||
<a
|
||
className="resume-link"
|
||
href={item.url}
|
||
target="_blank"
|
||
rel="noreferrer"
|
||
>
|
||
{item.fileName || item.name || "查看注册安全工程师资格证"}
|
||
</a>
|
||
</div>
|
||
))
|
||
: "-"}
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td className="resume-label-wide">主要学习工作经历</td>
|
||
<td className="resume-value-full" colSpan={3}>
|
||
{display(info.workExperience)}
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td className="resume-label">本人签字</td>
|
||
<td className="resume-sign"></td>
|
||
<td className="resume-label">从业机构确认</td>
|
||
<td className="resume-sign"></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</Modal>
|
||
);
|
||
}
|