import React, { useState, useMemo } from "react"; import { Button, Image, Input, Select, Table, Tabs, Tag, Space } from "antd"; import { Connect } from "@cqsjjb/jjb-dva-runtime"; import { NS_QUAL_REVIEW, NS_EQUIP_INFO } from "~/enumerate/namespace"; import StaffViewModal from "~/components/StaffViewModal"; import PreviewUrlButton from "~/components/PreviewUrlButton/index"; import { EquipViewModal } from "~/pages/Container/EnterpriseInfo/EquipInfo"; import { QUALIFICATION_INDUSTRY_OPTIONS, QUALIFICATION_INDUSTRY_OPTIONS_MAP, TITLE_LEVEL_MAP, } from "~/enumerate/enterpriseOptions"; import { CAPABILITY_MAP } from "~/enumerate/constant"; import { getCalibrationTag } from "../mockData"; const { TextArea } = Input; /** * 共享组件:资质备案初审 6 个标签页(详情 / 审核共用) * 对应原型 mod-qual-review-form / mod-qual-review-detail: * 1. 申请基本信息 2. 管理人员 3. 专职安全评价师 * 4. 申请材料 5. 设备清单 6. 机构负责人签字 * @param {Object} props * @param {Object} props.detail - 备案详情数据 * @param {boolean} [props.isReview=false] - 审核模式(材料表格开启"符合性"列) * @param {Object} [props.compliance={}] - 审核模式下的符合性状态 * @param {Function} [props.onComplianceChange] - 符合性变动回调 */ function calcAge(birthDate) { if (!birthDate) return "-"; const birth = new Date(birthDate); if (isNaN(birth.getTime())) return "-"; const now = new Date(); let age = now.getFullYear() - birth.getFullYear(); const m = now.getMonth() - birth.getMonth(); if (m < 0 || (m === 0 && now.getDate() < birth.getDate())) age--; return age >= 0 ? age : "-"; } /** * 职称名称:后端 QualFilingPersonnelInfoCO 返回 titleCodeArr(编码数组), * 转中文名称展示(高级/中级/初级)。变更时间:2026-08-10(对齐后端字段) */ function titleNames(titleCodeArr) { // 兼容:初审返回数组,备案变更返回字符串(可能为 "SENIOR" / "SENIOR,MIDDLE" / JSON 数组字符串)。变更时间:2026-08-10 let list = Array.isArray(titleCodeArr) ? titleCodeArr : []; if (!Array.isArray(titleCodeArr) && typeof titleCodeArr === "string") { try { const parsed = JSON.parse(titleCodeArr); list = Array.isArray(parsed) ? parsed : [titleCodeArr]; } catch { list = String(titleCodeArr) .split(/[,,、]/) .map((s) => s.trim()) .filter(Boolean); } } const names = list .map((item) => { const code = typeof item === "string" ? item : item?.titleCode || item?.title; return item?.titleName || TITLE_LEVEL_MAP[code] || code || ""; }) .filter(Boolean); // 空数组返回空字符串,便于调用方回退 titleName 等字段 return names.length ? names.join("、") : ""; } /** * 从业年限:后端返回 joinWorkDate(参加工作时间),按当前日期推算年数。 * 变更时间:2026-08-10(对齐后端字段) */ function workYearsText(joinWorkDate) { if (!joinWorkDate) return "-"; const d = new Date(String(joinWorkDate).replace(/-/g, "/")); if (Number.isNaN(d.getTime())) return "-"; const now = new Date(); let years = now.getFullYear() - d.getFullYear(); const m = now.getMonth() - d.getMonth(); if (m < 0 || (m === 0 && now.getDate() < d.getDate())) years--; return years >= 0 ? `${years}年` : "-"; } const gridStyle = { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0.6rem 1rem", }; const fieldStyle = { display: "flex", flexDirection: "column", gap: "0.3rem" }; const labelStyle = { fontSize: "0.8rem", color: "#64748b", fontWeight: 500 }; const inputStyle = { background: "#f8fafc" }; const fullSpan = { gridColumn: "1 / -1" }; /** 只读字段 */ function ReadonlyField({ label, value, span }) { return (
); } const FilingTabs = ({ detail = {}, isReview = false, compliance = {}, onComplianceChange, /** * 额外 Tab(如机构备案详情「7. 变更记录」),数组元素与 antd Tabs items 同构。 * 不传时保持原 6 Tab,不影响初审/确认/专家核验展示。变更时间:2026-08-10 */ extraTabs, equipInfoGet, }) => { const [viewId, setViewId] = useState(""); const [equipViewOpen, setEquipViewOpen] = useState(false); const [equipId, setEquipId] = useState(""); const personnelRows = useMemo( () => (detail.personnelList || []).map((item) => ({ ...item, age: item.age ?? calcAge(item.birthDate), })), [detail.personnelList], ); /** * 管理人员判定:technicalDirectorFlag(技术负责人) 或 processControlLeaderFlag(过程控制负责人) 为 true; * 法定代表人/负责人按岗位名兜底归入管理人员。 * 备案变更详情人员 CO(QualFilingPersonnelChangeInfoCO)暂未返回 flag 字段,靠岗位名兜底判断(待后端补充 flag)。 * 变更时间:2026-08-10(按后端人员标识字段拆分) */ const isManager = (item) => item.technicalDirectorFlag === true || item.processControlLeaderFlag === true || /法定代表人|负责人/.test(item.positionName || ""); const managerRows = useMemo(() => { return personnelRows.filter(isManager); }, [personnelRows]); /** 专职安全评价师:非管理人员的其余人员 */ const evaluatorRows = useMemo(() => { return personnelRows.filter((item) => !isManager(item)); }, [personnelRows]); const attachmentList = useMemo(() => { const v = detail.attachmentUrl; if (!v) return []; try { const p = JSON.parse(v); return Array.isArray(p) ? p : []; } catch { return []; } }, [detail.attachmentUrl]); const businessScope = useMemo(() => { const list = Array.isArray(detail.businessScope) ? detail.businessScope : []; return QUALIFICATION_INDUSTRY_OPTIONS.map((opt) => ({ ...opt, checked: list.includes(opt.value), })); }, [detail.businessScope]); /** 人员表格列(管理/评价师共用基础) */ const basePersonCols = (withScope) => [ { title: "序号", width: 60, render: (_, __, i) => i + 1 }, { title: "姓名", dataIndex: "personName", width: 110 }, { title: "岗位类别", dataIndex: "positionName", width: 140, ellipsis: true }, { title: "学历/专业", width: 160, // 后端字段:educationName(学历) / basicDisciplineMajorName(专业);变更时间:2026-08-10 render: (_, r) => [r.educationName, r.basicDisciplineMajorName].filter(Boolean).join(" / ") || "-", }, { title: "职称", width: 120, render: (_, r) => titleNames(r.titleCodeArr) || r.titleName || "-", }, { title: "从业年限", width: 100, render: (_, r) => r.workYears || r.yearsOfWorking || workYearsText(r.joinWorkDate), }, { title: "专业能力", width: 180, render: (_, r) => { // 能力编码:兼容 professionalCapabilityCodeList 与后端 capabilityAssessment;变更时间:2026-08-10 // 备案变更返回 capabilityAssessment 字符串(JSON 数组),需解析后映射 let capList = r.capabilityAssessment; if (typeof capList === "string") { try { const parsed = JSON.parse(capList); capList = Array.isArray(parsed) ? parsed : []; } catch { capList = []; } } const codes = r.professionalCapabilityCodeList || (Array.isArray(capList) ? capList.map((c) => (typeof c === "string" ? c : c?.professionalCapabilityCode)).filter(Boolean) : []) || []; return codes.length ? codes.map((code) => CAPABILITY_MAP[code] || code).join("、") : "-"; }, }, ...(withScope ? [ { title: "申请业务范围", width: 200, ellipsis: true, render: (_, r) => { const scopes = r.appliedScope || r.scopeList; if (Array.isArray(scopes)) { return scopes.map((s) => QUALIFICATION_INDUSTRY_OPTIONS_MAP[s] || s).join("、"); } return scopes || "-"; }, }, ] : []), { title: "操作", width: 80, fixed: "right", render: (_, record) => ( ), }, ]; const materialCols = isReview ? [ { title: "序号", width: 60, render: (_, __, i) => i + 1 }, { title: "申请材料", dataIndex: "materialContent", ellipsis: true }, { title: "格式", dataIndex: "materialFormat", width: 80 }, { title: "状态", width: 100, render: (_, record) => record.uploadStatusCode === 2 ? ( {record.uploadStatusName || "已上传"} ) : ( {record.uploadStatusName || "待上传"} ), }, { title: "符合性", width: 110, render: (_, record) => ( ), }, { title: "操作", width: 80, render: (_, record) => ( 预览 ), }, ] : [ { title: "序号", width: 60, render: (_, __, i) => i + 1 }, { title: "申请材料", dataIndex: "materialContent", ellipsis: true }, { title: "格式", dataIndex: "materialFormat", width: 80 }, { title: "操作", width: 80, render: (_, record) => ( 预览 ), }, ]; const commitment = detail.commitment || {}; const items = [ { key: "info", label: "1. 申请基本信息", children: (
{businessScope.map((opt) => ( ))}
初次申请无需填写,已有资质备案时填写
{/* 法定代表人:后端 CO 字段为 legalRepresentative(表 legal_representative);变更时间:2026-08-10 */}