import { parseTime } from "@/utils/ruoyi"; import { mapApprovalRecords, mapRecordResult, mapTasksToFlowNodes, } from "../../_utils/approveListUtils.js"; function formatDisplayTime(val) { if (!val) return ""; const s = parseTime(val, "{y}-{m}-{d} {h}:{i}"); return s || String(val).replace("T", " ").slice(0, 16); } function taskStatusToNodeStatus(taskStatus) { const s = String(taskStatus ?? "").toUpperCase(); if (["APPROVED", "COMPLETED", "FINISHED", "PASSED", "AGREE"].includes(s)) { return "finish"; } if (["REJECTED", "REJECT", "REFUSE", "REFUSED"].includes(s)) { return "error"; } if (["PENDING", "IN_APPROVAL", "PROCESS", "PROCESSING"].includes(s)) { return "process"; } return "wait"; } /** storageBlobVOList → 页面附件 */ export function mapReimbursementAttachments(source = {}) { const list = source.storageBlobVOList || source.storageBlobDTOs || source.storageBlobDTOS || source.attachmentList || source.invoiceAttachments || []; if (!Array.isArray(list)) return []; return list.map((b, i) => ({ ...b, id: b.id ?? b.blobId ?? `att_${i}`, name: b.fileName || b.originalFilename || b.originalFileName || b.blobName || b.name || "附件", url: b.url || b.fileUrl || b.downloadUrl || b.downloadURL || b.previewUrl || b.previewURL || b.link || "", })); } /** 审批记录在 tasks */ export function mapTasksToApprovalRecords(tasks) { const list = Array.isArray(tasks) ? tasks : []; return list .map((t, index) => ({ id: t.id ?? index, operatorName: t.approverName || t.operatorName || t.createUserName || "—", result: mapRecordResult(t.approveAction ?? t.taskStatus ?? t.status), opinion: t.approveComment || t.comment || t.opinion || "", time: formatDisplayTime( t.approveTime || t.finishTime || t.updateTime || t.createTime || "" ), levelNo: t.levelNo ?? t.taskLevel, })) .sort((a, b) => { const la = Number(a.levelNo ?? 0); const lb = Number(b.levelNo ?? 0); if (la !== lb) return la - lb; return String(a.time).localeCompare(String(b.time)); }); } export function mapTasksToApprovalFlowNodes(tasks) { const grouped = mapTasksToFlowNodes(tasks); return grouped.map((node, i) => { const approvers = node.approvers || []; const statuses = approvers.map(a => taskStatusToNodeStatus(a.taskStatus ?? a.status) ); let nodeStatus = "wait"; if (statuses.includes("error")) nodeStatus = "error"; else if (statuses.length && statuses.every(s => s === "finish")) { nodeStatus = "finish"; } else if (statuses.includes("process")) nodeStatus = "process"; const names = approvers.map(a => a.approverName).filter(Boolean).join("、"); const opinions = approvers .map(a => a.approveComment) .filter(Boolean) .join(";"); return { nodeOrder: node.levelNo ?? i + 1, levelNo: node.levelNo ?? i + 1, approveType: node.approveType || "AND", approveTypeLabel: node.approveType === "OR" ? "或签" : "会签", approvers, approverName: names || "—", approveOpinion: opinions, nodeStatus, }; }); } export function computeApprovalFlowCurrentIndex(approvalFlowNodes = []) { const list = approvalFlowNodes || []; const processing = list.findIndex(n => n.nodeStatus === "process"); if (processing >= 0) return processing; const errorIdx = list.findIndex(n => n.nodeStatus === "error"); if (errorIdx >= 0) return errorIdx; return list.filter(n => n.nodeStatus === "finish").length; } export function applyFinReimbursementDetailEnrichment(mapped, raw = {}) { if (!mapped || typeof mapped !== "object") return mapped; const source = { ...raw, ...mapped }; const tasks = Array.isArray(source.tasks) ? source.tasks : []; const attachments = mapReimbursementAttachments(source); const approvalRecords = tasks.length ? mapTasksToApprovalRecords(tasks) : mapApprovalRecords(source.records || source.approvalRecords); const approvalFlowNodes = Array.isArray(mapped.approvalFlowNodes) ? mapped.approvalFlowNodes : []; const approvalFlowProgressNodes = tasks.length ? mapTasksToApprovalFlowNodes(tasks) : approvalFlowNodes; const flowNodes = tasks.length ? mapTasksToFlowNodes(tasks) : mapped.flowNodes || mapped.nodes || []; return { ...mapped, tasks, storageBlobVOList: attachments, attachmentList: attachments, invoiceAttachments: attachments, approvalRecords, approvalFlowNodes, approvalFlowProgressNodes, currentNodeIndex: computeApprovalFlowCurrentIndex( approvalFlowProgressNodes.length ? approvalFlowProgressNodes : approvalFlowNodes ), rejectReason: approvalRecords.find(r => r.result === "rejected")?.opinion || source.rejectReason || "", flowNodes, }; }