import React, { useEffect, useState, useRef } from "react"; import { Tag, Button, Card, Row, Col, Table, Form, Input, Select, Radio, DatePicker, Flex, message, Spin, Modal, Popover, Image, } from "antd"; import dayjs from "dayjs"; import { Connect } from "@cqsjjb/jjb-dva-runtime"; import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace"; import {EVAL_TYPE_OPTIONS, EVAL_TYPE_MAP} from '~/enumerate/constant'; import { QUALIFICATION_INDUSTRY_OPTIONS } from "~/enumerate/enterpriseOptions"; import { tools } from "@cqsjjb/jjb-common-lib"; import AttachmentUpload from "~/components/AttachmentUpload"; import LayoutFooterPortal from "~/components/LayoutFooterPortal"; import { fillDocxTemplate } from "~/utils/fillDocxTemplate"; const { router } = tools; const { TextArea } = Input; /** 风险分析记录表 docx 模板 */ const RISK_TEMPLATE_URL = "https://test-dragon-yf-pub.oss-cn-hangzhou.aliyuncs.com/jjb/6a86d268e4b072649bfb8a84.docx"; /** 两选项单选回显:1 勾选前者,2 勾选后者 */ const twoCheck = (val, yes, no) => val === 1 ? `☑${yes} □${no}` : val === 2 ? `□${yes} ☑${no}` : `□${yes} □${no}`; const RISK_LEVEL_CHECK = { 1: "☑ 低度 □ 中度 □ 高度", 2: "□ 低度 ☑ 中度 □ 高度", 3: "□ 低度 □ 中度 ☑ 高度", }; const RiskAnalysisContent = ({ readOnly, ...props }) => { const [form] = Form.useForm(); const projectId = router.query?.id; const { safetyEvalBusiness, evalRiskAnalysisGet, evalRiskAnalysisSave, evalRiskAnalysisPeopleSave, evalSignTaskSave, } = props; const { riskAnalysisLoading, evalProjectDetailLoading, riskAnalysisSaveLoading, evalSignTaskSaveLoading, evalProjectDetailData, } = safetyEvalBusiness || {}; // 查询风险分析数据回显 const [participantModalOpen, setParticipantModalOpen] = useState(false); const [selectedParticipantIds, setSelectedParticipantIds] = useState([]); const [signingIndex, setSigningIndex] = useState(null); const addParticipantRef = useRef(null); const fetchData = async () => { if (!projectId) return; const res = await evalRiskAnalysisGet({ projectId }); if (res?.success !== false && res?.data) { form.setFieldsValue({ ...res.data, riskFileUrl: res.data.riskFileUrl? JSON.parse(res.data.riskFileUrl) :undefined, analysisDate: res.data.analysisDate ? dayjs(res.data.analysisDate) : undefined, }); } else { form.setFieldsValue({ evalTypeCode: evalProjectDetailData.evalTypeCode, projectName: evalProjectDetailData.projectName, industryName: evalProjectDetailData.industryCode, }); } }; useEffect(() => { if (evalProjectDetailData?.id) { fetchData(); } }, [projectId, evalProjectDetailData?.id]); // 保存 const handleSave = async (statusCode, noNeedfresh) => { const values = await form.validateFields(); const { analysisDate, ...rest } = values; // 检查是否有文件正在上传中 const fileList = rest.riskFileUrl || []; if (fileList.some((f) => f.status === "uploading")) { message.warning("文件上传中,请稍后再保存"); return; } if (statusCode === 2 && !fileList.length) { message.warning("请上传风险分析表附件"); return; } // if (statusCode === 2&&!rest.participants?.length) { // message.warning("请选择风险分析人员"); // return; // } const res = await evalRiskAnalysisSave({ ...rest, projectId, statusCode, riskFileUrl: rest.riskFileUrl? JSON.stringify(rest.riskFileUrl) :undefined, analysisDate: analysisDate ? analysisDate.format("YYYY-MM-DD") : undefined, }); if (res?.success) { let peopleSaved = true; if (res.data && rest.participants?.length) { // validateFields 仅返回已注册 Form.Item 的字段,personnelId 需从表单完整数据中取 const participantList = form.getFieldValue("participants") || []; const result = await evalRiskAnalysisPeopleSave( participantList.map((item) => { return { ...item, riskId: res.data.id, }; }), ); peopleSaved = result?.success; } if (!noNeedfresh&&peopleSaved) { message.success(statusCode === 2 ? "风险分析已完成" : "已暂存"); props.getDetail(); } } }; // 发起APP签字 const handleSignApp = async (fieldName) => { await handleSave(1, true); const participant = form.getFieldValue(["participants", fieldName]); if (!participant?.personnelId) { message.warning("该人员信息不完整,请先保存后再发起签字"); return; } setSigningIndex(fieldName); try { const res = await evalSignTaskSave({ projectId, nodeCode: "RISK_ANALYSIS", bizRefId: form.getFieldValue("id") || undefined, signerPersonnelId: participant.personnelId, taskTitle: "风险分析签字", taskStatusCode: 1, }); if (res?.success) { message.success("已发起APP签字"); form.setFieldValue(["participants", fieldName, "signStatusCode"], 1); } } finally { setSigningIndex(null); } }; // 导出Word:根据模板填充当前表单数据(已签字人员注入签字图片) const handleExport = async () => { const values = form.getFieldsValue(true); const industryText = String(values.industryName || "") .split(",") .filter(Boolean) .map( (code) => QUALIFICATION_INDUSTRY_OPTIONS.find((o) => o.value === code)?.label, ) .filter(Boolean) .join("、"); // 签字单元格仅内嵌已签字人员的签字图片,逐张换行展示 const images = []; const signTokens = []; for (const p of values.participants || []) { if (p.signStatusCode !== 2 || !p.signFileUrl) continue; try { const blob = await (await fetch(p.signFileUrl)).blob(); if (["image/png", "image/jpeg"].includes(blob.type)) { const token = `§SIGN_IMG_${images.length}§`; images.push({ token, blob }); signTokens.push(token); } } catch { // 图片加载失败时跳过 } } const data = { projectName: values.projectName || "", analysisDate: values.analysisDate ? values.analysisDate.format("YYYY年MM月DD日") : " 年 月 日", evalTypeText: EVAL_TYPE_MAP[values.evalTypeCode] || "", industryText, bizScopeCheck: twoCheck(values.inBizScopeFlag, "是", "否"), evalScope: values.evalScope || "", unitOverview: values.unitOverview || "", industryRiskDesc: values.industryRiskDesc || "", staffMatchCheck: twoCheck(values.staffMatchCode, "满足", "不满足"), needExpertCheck: values.needExpertCode === 1 ? "□不需要 ☑需要" : values.needExpertCode === 2 ? "☑不需要 □需要" : "□不需要 □需要", capabilityCheck: twoCheck(values.capabilityCode, "是", "否"), feasibleCheck: twoCheck(values.feasibleCode, "可行", "不可行"), economicCheck: twoCheck(values.economicCode, "有经济效益", "无经济效益"), riskLevelCheck: RISK_LEVEL_CHECK[values.riskLevelCode] || "□ 低度 □ 中度 □ 高度", signContractCheck: twoCheck(values.signContractCode, "签合同", "不签合同"), participantsText: signTokens.join(""), }; try { await fillDocxTemplate( RISK_TEMPLATE_URL, data, `安全评价风险分析记录表${values.projectName ? `-${values.projectName}` : ""}.docx`, { download: true, images }, ); message.success("导出成功"); } catch { message.error("导出失败,请重试"); } }; return (
市场部经办人 / 市场部经理 市场部组织前置条件调查和风险分析,相关职能部门参与;市场部经理依据分析结果决定是否签订技术服务合同。
({ value: value ? String(value).split(",") : [], })} getValueFromEvent={(value) => Array.isArray(value) ? value.join(",") : value } >