import { formatNameList } from './hazardDetail.js'; export const PENDING_LABEL = '待处理'; /** completed 未传时视为已完成(兼容旧数据) */ export const isNodeCompleted = (node) => node?.completed !== false; /** 空值:已完成显示 -,未完成显示待处理 */ export const resolveFieldDisplay = (value, completed = true) => { if (value != null && value !== '') return value; return completed ? '-' : PENDING_LABEL; }; export const PROCESS_NODE_TYPES = { ADD: 'add', ASSIGN: 'assign', RECTIFY: 'rectify', RECTIFY_ASSIGN: 'rectifyAssign', VERIFY: 'verify', VERIFY_SUB: 'verify_sub', WRITEOFF_APPLY: 'writeoff_apply', WRITEOFF_APPROVE: 'writeoff_approve', WRITEOFF_SUB: 'writeoff_sub', APPROVAL: 'approval' }; const SUB_TYPE_SUFFIX_MAP = { verify: '验收', writeoff: '销号' }; const TITLE_PREFIX_MAP = { add: '提交', assign: '交办', rectify: '整改', rectifyAssign: '交办', verify: '验收', verify_sub: '审批', writeoff_apply: '销号申请', writeoff_approve: '销号审核', writeoff_sub: '审批' }; const APPROVAL_TASK_KEY_ICON = { department_review: 'bumenshenpi', section_chief_review: 'fenguanshenpi', supervising_executive_review: 'fenguanshenpi', supervising_leader_review_1: 'zhuguanshenpi', supervising_leader_review_2: 'zhuguanshenpi' }; const NODE_TYPE_ICON = { add: 'tijiao', assign: 'jiaoban', rectifyAssign: 'jiaoban', rectify: 'zhenggai', verify: 'yanshou', writeoff_apply: 'xiaohao', writeoff_approve: 'xiaohao' }; const resolveTaskKey = (node) => { return node?.taskKey || node?.subProcessApprovalInfo?.taskKey || ''; }; /** 未完成节点:从 currentHandler 解析当前执行人 */ export const resolveCurrentHandlerName = (currentHandler) => { if (!currentHandler || typeof currentHandler !== 'object') { return ''; } return toDisplayText(currentHandler.handlerNames) || toDisplayText(currentHandler.assigneeName) || ''; }; /** null/undefined 等非对象值统一转为 {},避免默认参数对 null 不生效 */ const toSafeObject = (value) => (value && typeof value === 'object' ? value : {}); /** null/undefined/空字符串展示为空 */ const toDisplayText = (value) => { if (value == null || value === '') return ''; return value; }; export const getProcessStepDisplayName = (node) => { if (!node) return ''; const nodeType = node.nodeType; if (nodeType === 'verify_sub' || nodeType === 'writeoff_sub') { const subType = node.subProcessApprovalInfo?.subType; const suffix = SUB_TYPE_SUFFIX_MAP[subType]; return suffix ? `${node.nodeName}(${suffix})` : node.nodeName; } return node.nodeName || ''; }; export const getProcessStepIconPath = (item, active = false) => { const type = item?.type; const taskKey = item?.taskKey || ''; const state = active ? 'selected' : 'unselected'; if (type === PROCESS_NODE_TYPES.APPROVAL) { const iconBase = APPROVAL_TASK_KEY_ICON[taskKey] || 'bumenshenpi'; return `/static/yinhuan_detail/${iconBase}_${state}.png`; } const base = NODE_TYPE_ICON[item?.rawType] || NODE_TYPE_ICON[type] || 'tijiao'; if (base === 'zhenggai') { return active ? '/static/yinhuan_detail/zhenggai_selected.png' : '/static/yinhuan_detail/zhenggai__unselected.png'; } return `/static/yinhuan_detail/${base}__${state}.png`; }; const resolveOperator = (node, nodeType) => { const completed = isNodeCompleted(node); const fallback = completed ? '-' : ''; if (nodeType === PROCESS_NODE_TYPES.ADD) { return node.hazardInfo?.reporterName || fallback; } if (nodeType === PROCESS_NODE_TYPES.ASSIGN) { return node.assignInfo?.assignerName || fallback; } if (nodeType === PROCESS_NODE_TYPES.RECTIFY) { return node.rectifyInfo?.rectifierName || fallback; } if (nodeType === PROCESS_NODE_TYPES.VERIFY || nodeType === PROCESS_NODE_TYPES.WRITEOFF_APPROVE) { return node.verifyInfo?.verifierName || fallback; } if (nodeType === PROCESS_NODE_TYPES.WRITEOFF_APPLY) { return node.writeOffApplyInfo?.applicantName || fallback; } if (nodeType === PROCESS_NODE_TYPES.APPROVAL) { const info = node.subProcessApprovalInfo || {}; return info.operatorName || info.assigneeName || fallback; } return fallback; }; const resolveTime = (node, nodeType) => { const completed = isNodeCompleted(node); const fallback = completed ? '-' : ''; if (nodeType === PROCESS_NODE_TYPES.ADD) { return node.hazardInfo?.createdAt || node.completedAt || node.occurredAt || fallback; } if (nodeType === PROCESS_NODE_TYPES.ASSIGN) { return node.assignInfo?.assignTime || node.completedAt || fallback; } if (nodeType === PROCESS_NODE_TYPES.RECTIFY) { return node.rectifyInfo?.rectifyTime || node.completedAt || fallback; } if (nodeType === PROCESS_NODE_TYPES.VERIFY || nodeType === PROCESS_NODE_TYPES.WRITEOFF_APPROVE) { return node.verifyInfo?.verifyTime || node.completedAt || fallback; } if (nodeType === PROCESS_NODE_TYPES.WRITEOFF_APPLY) { return node.writeOffApplyInfo?.applyTime || node.completedAt || fallback; } if (nodeType === PROCESS_NODE_TYPES.APPROVAL) { return node.subProcessApprovalInfo?.endTime || node.completedAt || fallback; } return node.completedAt || node.occurredAt || fallback; }; const mapAddContent = (info) => { const data = toSafeObject(info); return { code: toDisplayText(data.code), title: toDisplayText(data.title), source: toDisplayText(data.source), hazardSourceName: toDisplayText(data.hazardSourceName), areaName: toDisplayText(data.areaName), address: toDisplayText(data.address), level: data.level ?? null, levelName: toDisplayText(data.levelName), tagName: toDisplayText(data.tagName), description: toDisplayText(data.description), attachments: Array.isArray(data.attachments) ? data.attachments : [], legalBasis: toDisplayText(data.legalBasis) }; }; const mapAssignContent = (info) => { const data = toSafeObject(info); return { assigneeName: toDisplayText(data.assigneeName), deadline: toDisplayText(data.deadline), assignRemark: toDisplayText(data.assignRemark), assignStatusName: toDisplayText(data.assignStatusName) }; }; const mapRectifyContent = (info) => { const data = toSafeObject(info); return { rectifyStatusName: toDisplayText(data.rectifyStatusName), rectifyPlan: toDisplayText(data.rectifyPlan), rectifyResult: toDisplayText(data.rectifyResult), rectificationMeasures: toDisplayText(data.rectificationMeasures), controlMeasures: toDisplayText(data.controlMeasures), rectifierName: toDisplayText(data.rectifierName), managerNames: formatNameList(data.managerNames, ''), memberNames: formatNameList(data.memberNames, ''), planCost: data.planCost ?? null, actualCost: data.actualCost ?? null, attachments: Array.isArray(data.attachments) ? data.attachments : [], signPath: toDisplayText(data.signPath) }; }; const mapVerifyContent = (info) => { const data = toSafeObject(info); return { resultName: toDisplayText(data.resultName), remark: toDisplayText(data.remark), attachments: Array.isArray(data.attachments) ? data.attachments : [], signPath: toDisplayText(data.signPath) }; }; const mapApprovalContent = (info) => { const data = toSafeObject(info); return { approveTypeName: toDisplayText(data.approveTypeName), pass: data.pass ?? null, comment: toDisplayText(data.comment), nextStepName: toDisplayText(data.nextStepName), nextAssigneeName: toDisplayText(data.nextAssigneeName), sendMsgFlag: data.sendMsgFlag ?? null, signPath: toDisplayText(data.signPath) }; }; const mapWriteoffApplyContent = (info) => { const data = toSafeObject(info); return { rectifyDeadline: toDisplayText(data.rectifyDeadline), responsibleDeptName: toDisplayText(data.responsibleDeptName), responsiblePerson: toDisplayText(data.responsiblePerson), mainTreatmentContent: toDisplayText(data.mainTreatmentContent), treatmentResult: toDisplayText(data.treatmentResult), selfVerifyContent: toDisplayText(data.selfVerifyContent), signPath: toDisplayText(data.signPath) }; }; const resolveNodeType = (node) => { const nodeType = node?.nodeType; if (nodeType === 'verify_sub' || nodeType === 'writeoff_sub') { return PROCESS_NODE_TYPES.APPROVAL; } return nodeType || PROCESS_NODE_TYPES.ADD; }; const hasRectifyData = (rectifyInfo) => { if (!rectifyInfo || typeof rectifyInfo !== 'object') { return false; } return Boolean( rectifyInfo.rectifyId || rectifyInfo.rectifyPlan || rectifyInfo.rectifyResult || rectifyInfo.rectifyTime || rectifyInfo.rectifierName ); }; const hasAssignData = (assignInfo) => { if (!assignInfo || typeof assignInfo !== 'object') { return false; } return Boolean( assignInfo.assignId || assignInfo.assigneeName || assignInfo.assignerName || assignInfo.assignTime ); }; /** 交办 / 整改转派节点 */ const isAssignLikeNodeType = (nodeType) => ( nodeType === PROCESS_NODE_TYPES.ASSIGN || nodeType === PROCESS_NODE_TYPES.RECTIFY_ASSIGN ); /** 交办/整改节点:有整改数据展示整改,否则有交办数据展示交办 */ export const resolveAssignRectifyDisplayType = (node) => { if (hasRectifyData(node?.rectifyInfo)) { return PROCESS_NODE_TYPES.RECTIFY; } if (hasAssignData(node?.assignInfo)) { return PROCESS_NODE_TYPES.ASSIGN; } return null; }; const resolveDisplayType = (node, nodeType) => { // assign:隐患交办 → assignInfo // rectifyAssign:整改转派 → assignInfo(若同节点附带整改数据则展示整改) if (isAssignLikeNodeType(nodeType)) { return resolveAssignRectifyDisplayType(node) || PROCESS_NODE_TYPES.ASSIGN; } // rectify:隐患整改 → rectifyInfo;未整改前可能只有转派信息 if (nodeType === PROCESS_NODE_TYPES.RECTIFY) { return resolveAssignRectifyDisplayType(node) || PROCESS_NODE_TYPES.RECTIFY; } return nodeType; }; const resolveTitlePrefix = (rawType, displayType, node) => { if (displayType === PROCESS_NODE_TYPES.ASSIGN) { return TITLE_PREFIX_MAP[rawType] || TITLE_PREFIX_MAP.assign; } if (displayType === PROCESS_NODE_TYPES.RECTIFY) { return TITLE_PREFIX_MAP.rectify; } return TITLE_PREFIX_MAP[displayType] || TITLE_PREFIX_MAP[rawType] || node.nodeName || '处理'; }; const mapNodeContent = (node, displayType) => { switch (displayType) { case PROCESS_NODE_TYPES.ADD: return mapAddContent(node.hazardInfo); case PROCESS_NODE_TYPES.ASSIGN: return mapAssignContent(node.assignInfo); case PROCESS_NODE_TYPES.RECTIFY: return mapRectifyContent(node.rectifyInfo); case PROCESS_NODE_TYPES.VERIFY: case PROCESS_NODE_TYPES.WRITEOFF_APPROVE: return mapVerifyContent(node.verifyInfo); case PROCESS_NODE_TYPES.WRITEOFF_APPLY: return mapWriteoffApplyContent(node.writeOffApplyInfo); case PROCESS_NODE_TYPES.APPROVAL: return mapApprovalContent(node.subProcessApprovalInfo); default: return {}; } }; export const mapProcessNodeToHistoryItem = (node) => { if (!node || typeof node !== 'object') { return { type: PROCESS_NODE_TYPES.ADD, rawType: '', taskKey: '', nodeName: '', titlePrefix: '处理', operator: '', time: '', currentHandlerName: '', content: {}, flowTaskId: '', completed: true }; } const nodeType = resolveNodeType(node); const rawType = node.nodeType || nodeType; const displayType = resolveDisplayType(node, nodeType); return { type: displayType, rawType, taskKey: resolveTaskKey(node), nodeName: getProcessStepDisplayName(node), titlePrefix: resolveTitlePrefix(rawType, displayType, node), operator: resolveOperator(node, displayType), time: resolveTime(node, displayType), currentHandlerName: resolveCurrentHandlerName(node.currentHandler), content: mapNodeContent(node, displayType), flowTaskId: node.flowTaskId || '', completed: isNodeCompleted(node) }; }; export const mapProcessChainNodes = (nodes = []) => { if (!Array.isArray(nodes) || nodes.length === 0) return []; return nodes.map((node) => mapProcessNodeToHistoryItem(node)); }; export const resolveProcessChainSummary = (data) => { if (!data) { return { statusName: '-', createdAt: '-' }; } const addNode = (data.nodes || []).find((item) => item.nodeType === 'add'); const createdAt = addNode?.hazardInfo?.createdAt || '-'; return { statusName: data.statusName || '-', createdAt }; };