feat
parent
15847d7933
commit
b8dfddebe5
|
|
@ -32,8 +32,8 @@
|
|||
"docxtemplater": "latest",
|
||||
"echarts": "^6.1.0",
|
||||
"history": "^4.10.1",
|
||||
"html2canvas": "^1.4.1",
|
||||
"jspdf": "^2.5.2",
|
||||
|
||||
|
||||
"lodash-es": "^4.17.21",
|
||||
"pizzip": "latest",
|
||||
"react": "^18.2.0",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
姓名
|
||||
{userName}
|
||||
性别
|
||||
{gender}
|
||||
出生日期
|
||||
{birthDate}
|
||||
现住址
|
||||
{currentAddress}
|
||||
办公地址
|
||||
{officeAddress}
|
||||
职业资格等级及证书号码
|
||||
{qualificationText}
|
||||
注册安全工程师证书编号
|
||||
{certNo}
|
||||
身份证件号码
|
||||
{idCardNo}
|
||||
联系电话
|
||||
{phone}
|
||||
学历学位
|
||||
{education}
|
||||
毕业院校及专业
|
||||
{schoolMajor}
|
||||
出版学术专著、专利、科技发明及获奖情况
|
||||
{publications}
|
||||
自我申报的专业能力及认定方式
|
||||
{capability}
|
||||
申报专业能力证明材料
|
||||
{certFiles}
|
||||
主要学习工作经历
|
||||
{workExperience}
|
||||
本人签字
|
||||
|
||||
从业机构确认
|
||||
|
||||
|
||||
|
|
@ -5,3 +5,4 @@
|
|||
|
||||
部门经理或负责人:
|
||||
年 月 日
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import { Button, Modal, message } from "antd";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import html2canvas from "html2canvas";
|
||||
import { jsPDF } from "jspdf";
|
||||
import { fetchOrgPersonnelDetail } from "~/utils/qualFiling/personnelHelper";
|
||||
import { fillDocxTemplate } from "~/utils/fillDocxTemplate";
|
||||
import { ABILITY_SOURCE_MAP } from "~/enumerate/enterpriseOptions";
|
||||
import {
|
||||
CERT_LEVEL_LABEL_BY_TYPE,
|
||||
|
|
@ -10,6 +9,8 @@ import {
|
|||
} from "~/enumerate/constant";
|
||||
import "./index.less";
|
||||
|
||||
const RESUME_TEMPLATE_URL = "/安全评价师简历表模板.docx";
|
||||
|
||||
const GENDER_MAP = { 1: "男", 2: "女" };
|
||||
|
||||
const parseFileList = (raw) => {
|
||||
|
|
@ -50,7 +51,6 @@ export default function StaffResumeModal({
|
|||
const [info, setInfo] = useState({});
|
||||
const [detailLoading, setDetailLoading] = useState(false);
|
||||
const [downloading, setDownloading] = useState(false);
|
||||
const resumeRef = useRef(null);
|
||||
const requestDetailsRef = useRef(requestDetails);
|
||||
requestDetailsRef.current = requestDetails;
|
||||
|
||||
|
|
@ -120,45 +120,40 @@ export default function StaffResumeModal({
|
|||
: "-";
|
||||
|
||||
const handleDownload = async () => {
|
||||
if (!resumeRef.current) return;
|
||||
setDownloading(true);
|
||||
try {
|
||||
const canvas = await html2canvas(resumeRef.current, {
|
||||
scale: 2,
|
||||
useCORS: true,
|
||||
backgroundColor: "#ffffff",
|
||||
logging: false,
|
||||
});
|
||||
const imgData = canvas.toDataURL("image/jpeg", 0.95);
|
||||
const pdf = new jsPDF({
|
||||
orientation: "portrait",
|
||||
unit: "mm",
|
||||
format: "a4",
|
||||
});
|
||||
const pageWidth = pdf.internal.pageSize.getWidth();
|
||||
const pageHeight = pdf.internal.pageSize.getHeight();
|
||||
const margin = 10;
|
||||
const contentWidth = pageWidth - margin * 2;
|
||||
const contentHeight = (canvas.height * contentWidth) / canvas.width;
|
||||
|
||||
let heightLeft = contentHeight;
|
||||
let position = margin;
|
||||
|
||||
pdf.addImage(imgData, "JPEG", margin, position, contentWidth, contentHeight);
|
||||
heightLeft -= pageHeight - margin * 2;
|
||||
|
||||
while (heightLeft > 0) {
|
||||
position = margin - (contentHeight - heightLeft);
|
||||
pdf.addPage();
|
||||
pdf.addImage(imgData, "JPEG", margin, position, contentWidth, contentHeight);
|
||||
heightLeft -= pageHeight - margin * 2;
|
||||
}
|
||||
|
||||
const fileName = `安全评价师简历表_${info.userName || currentId || ""}.pdf`;
|
||||
pdf.save(fileName);
|
||||
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: educationText,
|
||||
schoolMajor: 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 pdf failed:", err);
|
||||
console.warn("[StaffResumeModal] download word failed:", err);
|
||||
message.error("简历下载失败");
|
||||
} finally {
|
||||
setDownloading(false);
|
||||
|
|
@ -183,7 +178,7 @@ export default function StaffResumeModal({
|
|||
</Button>,
|
||||
]}
|
||||
>
|
||||
<div ref={resumeRef} style={{ background: "#fff", padding: 8 }}>
|
||||
<div style={{ background: "#fff", padding: 8 }}>
|
||||
|
||||
<table className="staff-resume-table">
|
||||
<tbody>
|
||||
|
|
|
|||
|
|
@ -22,6 +22,12 @@ import { tools } from "@cqsjjb/jjb-common-lib";
|
|||
import { EVAL_TYPE_MAP, ROLE_DEFINITIONS_MAP } from "~/enumerate/constant";
|
||||
import { PROJECT_TYPE_MAP } from "~/enumerate/constant";
|
||||
import WpsEditor from "~/pages/Container/WpsEditor";
|
||||
import RiskAnalysisContent from "~/pages/Container/SafetyEvalBusiness/ProjectFlow/RiskAnalysisContent";
|
||||
import InternalReviewContent from "~/pages/Container/SafetyEvalBusiness/ProjectFlow/InternalReviewContent";
|
||||
import TechnicalReviewContent from "~/pages/Container/SafetyEvalBusiness/ProjectFlow/TechnicalReviewContent";
|
||||
import ControlContent from "~/pages/Container/SafetyEvalBusiness/ProjectFlow/ControlContent";
|
||||
import ArchiveContent from "~/pages/Container/SafetyEvalBusiness/ProjectFlow/ArchiveContent";
|
||||
import "~/pages/Container/SafetyEvalBusiness/ProjectFlow/index.less";
|
||||
import "./index.less";
|
||||
|
||||
const { router } = tools;
|
||||
|
|
@ -453,6 +459,36 @@ const EvalProjectMonitorDetail = (props) => {
|
|||
);
|
||||
};
|
||||
|
||||
/** 可锁定 tab 的标签:前置未完成时展示警告态 */
|
||||
const renderLockableTabLabel = (label, done, locked) => (
|
||||
<span>
|
||||
{label}
|
||||
<Tag
|
||||
color={locked ? "warning" : done ? "success" : "default"}
|
||||
style={{ marginLeft: 6 }}
|
||||
>
|
||||
{locked ? "前置未完成" : done ? "已完成" : "待办理"}
|
||||
</Tag>
|
||||
</span>
|
||||
);
|
||||
|
||||
const NODE_TYPES_BEFORE_CONTROL = [
|
||||
"RISK_ANALYSIS",
|
||||
"BUSINESS_CONTRACT",
|
||||
"PROJECT_GROUP",
|
||||
"SITE_SURVEY",
|
||||
"REPORT_PREPARATION",
|
||||
"INTERNAL_REVIEW",
|
||||
"TECHNICAL_REVIEW",
|
||||
];
|
||||
// 过程控制:前 7 个节点全部完成才解锁
|
||||
const controlLocked = !NODE_TYPES_BEFORE_CONTROL.every(
|
||||
(type) => nodeMap[type]?.state === 1,
|
||||
);
|
||||
// 项目归档:前 8 个节点(含过程控制)全部完成才解锁
|
||||
const archiveLocked =
|
||||
controlLocked || nodeMap["PROCESS_CONTROL"]?.state !== 1;
|
||||
|
||||
const projectInfo = (
|
||||
<div className="epm-detail-band">
|
||||
<div className="epm-detail-band-item">
|
||||
|
|
@ -501,6 +537,11 @@ const EvalProjectMonitorDetail = (props) => {
|
|||
setActiveKey(key);
|
||||
}}
|
||||
items={[
|
||||
{
|
||||
key: "RISK_ANALYSIS",
|
||||
label: renderTabLabel("风险分析", "RISK_ANALYSIS"),
|
||||
children: <RiskAnalysisContent readOnly />,
|
||||
},
|
||||
{
|
||||
key: "BUSINESS_CONTRACT",
|
||||
label: renderTabLabel("项目合同", "BUSINESS_CONTRACT"),
|
||||
|
|
@ -530,6 +571,36 @@ const EvalProjectMonitorDetail = (props) => {
|
|||
label: renderTabLabel("报告编制", "REPORT_PREPARATION"),
|
||||
children: null,
|
||||
},
|
||||
{
|
||||
key: "INTERNAL_REVIEW",
|
||||
label: renderTabLabel("内部审核", "INTERNAL_REVIEW"),
|
||||
children: <InternalReviewContent readOnly />,
|
||||
},
|
||||
{
|
||||
key: "TECHNICAL_REVIEW",
|
||||
label: renderTabLabel("技术审核", "TECHNICAL_REVIEW"),
|
||||
children: <TechnicalReviewContent readOnly />,
|
||||
},
|
||||
{
|
||||
key: "PROCESS_CONTROL",
|
||||
label: renderLockableTabLabel(
|
||||
"过程控制",
|
||||
nodeMap["PROCESS_CONTROL"]?.state === 1,
|
||||
controlLocked,
|
||||
),
|
||||
disabled: controlLocked,
|
||||
children: <ControlContent readOnly />,
|
||||
},
|
||||
{
|
||||
key: "ARCHIVE",
|
||||
label: renderLockableTabLabel(
|
||||
"项目归档",
|
||||
evalProjectDetailData?.archiveFlag === 1,
|
||||
archiveLocked,
|
||||
),
|
||||
disabled: archiveLocked,
|
||||
children: <ArchiveContent readOnly />,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
{wpsVisible && (
|
||||
|
|
|
|||
Loading…
Reference in New Issue