import dayjs from "dayjs"; import { TEMPLATE_TYPE_CUSTOM, TEMPLATE_TYPE_OPTIONS, } from "@/api/officeProcessAutomation/approvalTemplate.js"; import { APPROVAL_TYPE_OPTIONS } from "../approve-list/approveListConstants.js"; import { buildFormConfigJson, createEmptyFormConfigData, parseFormConfigToData, validateFormConfigData, } from "./formConfigUtils.js"; export { TEMPLATE_TYPE_OPTIONS }; export function templateTypeLabel(type) { if (type == null || type === "") return "—"; const n = Number(type); return TEMPLATE_TYPE_OPTIONS.find((x) => x.value === n)?.label || "—"; } /** 节点内审批方式:会签 / 或签 */ export const NODE_SIGN_MODE_OPTIONS = [ { value: "countersign", label: "会签", desc: "本节点所有审批人均需通过" }, { value: "or_sign", label: "或签", desc: "本节点任一审批人通过即可" }, ]; function parseFormConfig(formConfig) { if (!formConfig) return {}; if (typeof formConfig === "object") return formConfig; try { return JSON.parse(formConfig); } catch { return {}; } } function resolveDefaultMode(row, cfg, nodes) { let mode = cfg.approvalMode || cfg.defaultMode; if (!mode && nodes.length) { const t = String(nodes[0]?.approveType || "").toUpperCase(); mode = t === "OR" ? "or_sign" : "parallel"; } const m = String(mode || "").toLowerCase(); if (m === "or" || m === "or_sign") return "or_sign"; return "parallel"; } /** 将接口返回的模板转为「系统常用审批」卡片数据 */ export function mapBuiltinCardFromApi(row) { const cfg = parseFormConfig(row?.formConfig); const fields = cfg.fields || cfg.formFields || []; const nodes = row?.nodes || row?.flowNodes || []; return { key: String(row?.id ?? row?.templateName ?? ""), id: row?.id, approvalType: cfg.approvalType || row?.approvalType || "", label: row?.templateName || row?.name || "—", summary: (row?.description || "").trim() || cfg.summaryPlaceholder || "系统预置填报字段", fieldCount: fields.length, defaultMode: resolveDefaultMode(row, cfg, nodes), }; } export function unwrapTemplateList(payload) { const data = payload?.data ?? payload; if (Array.isArray(data)) return data; if (Array.isArray(data?.records)) return data.records; if (Array.isArray(data?.list)) return data.list; return []; } /** 后端 approveType → 页面 signMode */ export function mapSignModeFromApi(approveType) { const t = String(approveType || "").toUpperCase(); return t === "OR" ? "or_sign" : "countersign"; } /** 页面 signMode → 后端 approveType */ export function mapSignModeToApi(signMode) { return signMode === "or_sign" ? "OR" : "AND"; } /** 页面 enabled → 后端 enabled(1 启用,0 停用) */ export function mapEnabledToApi(enabled) { return enabled !== false ? "1" : "0"; } /** 后端 nodes → 页面 flowNodes(保留 id 供修改提交) */ export function mapNodesFromApi(nodes) { const list = Array.isArray(nodes) ? nodes : []; return list.map((n, i) => ({ id: n.id, templateId: n.templateId, nodeOrder: n.levelNo ?? i + 1, signMode: mapSignModeFromApi(n.approveType ?? n.signMode), approvers: (n.approvers || []) .filter((a) => a?.approverId != null && a.approverId !== "") .map((a) => ({ id: a.id, nodeId: a.nodeId, templateId: a.templateId, approverId: a.approverId, approverName: a.approverName || "", })), })); } /** enabled:1 启用,0 停用 */ export function mapEnabledFromApi(enabled) { return enabled === "1" || enabled === 1 || enabled === true; } /** 兼容多种后端时间字段名并格式化展示 */ export function pickTemplateTimes(row) { const rawCreated = row?.createdTime ?? row?.createTime ?? row?.gmtCreate ?? row?.created_at ?? ""; const rawUpdated = row?.updatedTime ?? row?.updateTime ?? row?.gmtModified ?? row?.modifyTime ?? row?.updated_at ?? ""; const createdTime = normalizeTimeValue(rawCreated); const updatedTime = normalizeTimeValue(rawUpdated); return { createdTime, updatedTime, createTime: createdTime, updateTime: updatedTime }; } function normalizeTimeValue(val) { if (val == null || val === "") return ""; if (Array.isArray(val) && val.length >= 3) { const [y, m, d, h = 0, min = 0, s = 0] = val; return dayjs(new Date(y, m - 1, d, h, min, s)).format("YYYY-MM-DD HH:mm:ss"); } if (typeof val === "number") { const d = val > 1e12 ? dayjs(val) : dayjs.unix(val); return d.isValid() ? d.format("YYYY-MM-DD HH:mm:ss") : ""; } const s = String(val).trim(); if (!s) return ""; const parsed = dayjs(s.includes("T") ? s : s.replace(/-/g, "/")); return parsed.isValid() ? parsed.format("YYYY-MM-DD HH:mm:ss") : s; } export function formatDisplayTime(val) { const t = normalizeTimeValue(val); return t || "—"; } /** 详情接口 data 解包 */ export function unwrapTemplateDetail(res) { const data = res?.data ?? res; if (!data || typeof data !== "object") return {}; if (data.templateName != null || data.id != null) return data; if (data.approvalTemplateVo) return data.approvalTemplateVo; if (data.records && data.records[0]) return data.records[0]; return data; } /** 分页列表项 → 页面行数据(主表 + 节点) */ export function mapTemplateFromApi(row) { if (!row) return {}; const flowNodes = mapNodesFromApi(row.nodes || row.flowNodes); const times = pickTemplateTimes(row); return { id: row.id, templateName: row.templateName || "", description: row.description || "", enabled: mapEnabledFromApi(row.enabled), enabledRaw: row.enabled, templateType: row.templateType != null ? Number(row.templateType) : undefined, formConfig: row.formConfig, formConfigData: parseFormConfigToData(row.formConfig), createdUser: row.createdUser, createdUserName: row.createdUserName, ...times, flowNodes, nodes: row.nodes || row.flowNodes, }; } /** 表单数据 → 提交 DTO(ApprovalTemplateDto) */ export function mapTemplateToApi(form) { const nodes = normalizeFlowNodes(form.flowNodes); const templateId = form.id || null; const dto = { templateName: (form.templateName || "").trim(), description: (form.description || "").trim(), enabled: mapEnabledToApi(form.enabled), templateType: form.templateType ?? TEMPLATE_TYPE_CUSTOM, formConfig: buildFormConfigJson(form.formConfigData), nodes: nodes.map((n, i) => { const node = { levelNo: n.nodeOrder ?? i + 1, approveType: mapSignModeToApi(n.signMode), approvers: n.approvers.map((a, idx) => { const approver = { approverId: a.approverId, approverName: a.approverName || "", sortNo: idx + 1, }; if (a.id != null) approver.id = a.id; if (a.nodeId != null) approver.nodeId = a.nodeId; if (a.templateId != null) approver.templateId = a.templateId; else if (templateId) approver.templateId = templateId; return approver; }), }; if (n.id != null) node.id = n.id; if (n.templateId != null) node.templateId = n.templateId; else if (templateId) node.templateId = templateId; return node; }), }; if (templateId) dto.id = templateId; return dto; } export function buildApprovalTemplateListParams({ page, searchForm, templateType = TEMPLATE_TYPE_CUSTOM }) { const params = { current: page.current, size: page.size, templateType: searchForm?.templateType != null && searchForm.templateType !== "" ? searchForm.templateType : templateType, }; const kw = (searchForm?.keyword || "").trim(); if (kw) params.templateName = kw; if (searchForm?.enabledOnly) params.enabled = "1"; return params; } export function nodeSignModeLabel(mode) { return NODE_SIGN_MODE_OPTIONS.find((x) => x.value === mode)?.label || "—"; } export function approvalTypeLabel(type) { return APPROVAL_TYPE_OPTIONS.find((x) => x.value === type)?.label || type || "—"; } export function createEmptyNode(order = 1) { return { nodeOrder: order, signMode: "countersign", approvers: [], }; } export function createEmptyTemplateForm() { return { id: "", templateName: "", description: "", templateType: TEMPLATE_TYPE_CUSTOM, formConfig: "", formConfigData: createEmptyFormConfigData(), enabled: true, flowNodes: [createEmptyNode(1)], }; } export function normalizeFlowNodes(nodes) { const list = Array.isArray(nodes) ? nodes : []; return list.map((n, i) => ({ id: n.id, templateId: n.templateId, nodeOrder: i + 1, signMode: n.signMode === "or_sign" ? "or_sign" : "countersign", approvers: (n.approvers || []) .filter((a) => a?.approverId != null && a.approverId !== "") .map((a) => ({ id: a.id, nodeId: a.nodeId, templateId: a.templateId, approverId: a.approverId, approverName: a.approverName || "", })), })); } export function validateTemplateForm(form) { const name = (form.templateName || "").trim(); if (!name) return { ok: false, message: "请填写模板名称" }; const nodes = normalizeFlowNodes(form.flowNodes); if (!nodes.length) return { ok: false, message: "请至少配置一个审批节点" }; for (let i = 0; i < nodes.length; i++) { if (!nodes[i].approvers.length) { return { ok: false, message: `请为第 ${i + 1} 个节点选择至少一名审批人` }; } } const cfgCheck = validateFormConfigData(form.formConfigData); if (!cfgCheck.ok) return cfgCheck; return { ok: true, nodes, name }; } export function flowNodesSummary(nodes) { const list = normalizeFlowNodes(nodes); if (!list.length) return "—"; return list .map((n, i) => { const names = n.approvers.map((a) => a.approverName || "未命名").join("、") || "未配置"; return `节点${i + 1}(${nodeSignModeLabel(n.signMode)}:${names})`; }) .join(" → "); }