| | |
| | | import { |
| | | createEmptyNode, |
| | | formatDisplayTime, |
| | | mapNodesFromApi, |
| | | mapSignModeFromApi, |
| | | mapSignModeToApi, |
| | | normalizeFlowNodes, |
| | | nodeSignModeLabel, |
| | | } from "../approve-template/approveTemplateConstants.js"; |
| | | import { createEmptyNode, formatDisplayTime, mapNodesFromApi, mapSignModeFromApi, mapSignModeToApi, normalizeFlowNodes, nodeSignModeLabel } from "../approve-template/approveTemplateConstants.js"; |
| | | import { buildFormPayloadFromFields, parseFormConfigToData } from "../approve-template/formConfigUtils.js"; |
| | | import { |
| | | isDynamicOptionSource, |
| | | resolveSelectDisplayLabel, |
| | | } from "../approve-template/selectOptionSource.js"; |
| | | import { |
| | | appendDotNotationQuery, |
| | | buildApprovalInstanceSearchDto, |
| | | } from "../approve-shared/approvalInstanceListSearch.js"; |
| | | import { isDynamicOptionSource, resolveSelectDisplayLabel } from "../approve-template/selectOptionSource.js"; |
| | | import { appendDotNotationQuery, buildApprovalInstanceSearchDto } from "../approve-shared/approvalInstanceListSearch.js"; |
| | | |
| | | /** 审批类型(与后端字段 approvalType 对齐,后期可同步) */ |
| | | export const APPROVAL_TYPE_OPTIONS = [ |
| | |
| | | if (upper === "APPROVED" || upper === "APPROVE" || upper === "PASS" || upper === "AGREE") { |
| | | return "approved"; |
| | | } |
| | | if ( |
| | | upper === "REJECTED" || |
| | | upper === "REJECT" || |
| | | upper === "REFUSE" || |
| | | upper === "REFUSED" || |
| | | upper === "DENIED" |
| | | ) { |
| | | if (upper === "REJECTED" || upper === "REJECT" || upper === "REFUSE" || upper === "REFUSED" || upper === "DENIED") { |
| | | return "rejected"; |
| | | } |
| | | if (upper === "CANCELLED" || upper === "CANCEL" || upper === "REVOKED") return "cancelled"; |
| | | if ( |
| | | upper === "PENDING" || |
| | | upper === "IN_PROGRESS" || |
| | | upper === "PROCESSING" || |
| | | upper === "RUNNING" || |
| | | upper === "WAIT" || |
| | | upper === "WAITING" |
| | | ) { |
| | | if (upper === "PENDING" || upper === "IN_PROGRESS" || upper === "PROCESSING" || upper === "RUNNING" || upper === "WAIT" || upper === "WAITING") { |
| | | return "pending"; |
| | | } |
| | | if (s.includes("草稿")) return "draft"; |
| | |
| | | } |
| | | const tasks = row.tasks; |
| | | if (Array.isArray(tasks) && tasks.length) { |
| | | const rejected = tasks.some((t) => |
| | | normalizeApprovalStatusKey(t?.status ?? t?.taskStatus) === "rejected" |
| | | ); |
| | | const rejected = tasks.some(t => normalizeApprovalStatusKey(t?.status ?? t?.taskStatus) === "rejected"); |
| | | if (rejected) return "REJECTED"; |
| | | const allApproved = tasks.every((t) => |
| | | normalizeApprovalStatusKey(t?.status ?? t?.taskStatus) === "approved" |
| | | ); |
| | | const allApproved = tasks.every(t => normalizeApprovalStatusKey(t?.status ?? t?.taskStatus) === "approved"); |
| | | if (allApproved) return "APPROVED"; |
| | | } |
| | | return ""; |
| | |
| | | /** 后端 records → 时间线展示结构 */ |
| | | export function mapRecordsFromApi(records) { |
| | | const list = Array.isArray(records) ? records : []; |
| | | return list.map((r) => ({ |
| | | return list.map(r => ({ |
| | | id: r.id, |
| | | operatorName: r.approverName || r.operatorName || r.createUserName || "", |
| | | result: mapRecordResultFromApi(r.approveAction ?? r.action ?? r.status), |
| | |
| | | const list = Array.isArray(tasks) ? tasks : []; |
| | | if (!list.length) return []; |
| | | const byLevel = new Map(); |
| | | list.forEach((t) => { |
| | | list.forEach(t => { |
| | | const level = Number(t.levelNo ?? t.taskLevel ?? t.nodeOrder ?? 1); |
| | | if (!byLevel.has(level)) { |
| | | byLevel.set(level, { |
| | |
| | | node.signMode = mapSignModeFromApi(t.approveType); |
| | | } |
| | | }); |
| | | return [...byLevel.entries()] |
| | | .sort(([a], [b]) => a - b) |
| | | .map(([, node]) => node); |
| | | return [...byLevel.entries()].sort(([a], [b]) => a - b).map(([, node]) => node); |
| | | } |
| | | |
| | | /** 页面 flowNodes → 后端 tasks */ |
| | | export function mapFlowNodesToTasks(flowNodes, { instanceId, templateId } = {}) { |
| | | const nodes = normalizeFlowNodes(flowNodes); |
| | | const tasks = []; |
| | | nodes.forEach((n) => { |
| | | nodes.forEach(n => { |
| | | const levelNo = n.nodeOrder ?? 1; |
| | | const approveType = mapSignModeToApi(n.signMode); |
| | | n.approvers.forEach((a, idx) => { |
| | |
| | | return String(val); |
| | | } |
| | | if (field?.type === "select" && field.options?.length) { |
| | | const hit = field.options.find((o) => String(o.value) === String(val)); |
| | | const hit = field.options.find(o => String(o.value) === String(val)); |
| | | return hit?.label || String(val); |
| | | } |
| | | if (Array.isArray(val)) return val.join(" 至 "); |
| | |
| | | }; |
| | | if (!fields.length && Object.keys(formPayload).length) { |
| | | fields = Object.keys(formPayload) |
| | | .filter((k) => k && k !== "summary") |
| | | .map((k) => ({ |
| | | .filter(k => k && k !== "summary") |
| | | .map(k => ({ |
| | | key: k, |
| | | label: k, |
| | | type: guessFieldTypeFromValue(formPayload[k]), |
| | |
| | | export function buildInstanceDto({ submitForm, activeTemplate, userStore, flowNodes, existingRow }) { |
| | | const payload = submitForm?.formPayload || {}; |
| | | const tpl = activeTemplate || {}; |
| | | const title = |
| | | String(payload.summary || payload.title || "").trim() || |
| | | tpl.label || |
| | | submitForm?.templateName || |
| | | "审批申请"; |
| | | const title = String(payload.summary || payload.title || "").trim() || tpl.label || submitForm?.templateName || "审批申请"; |
| | | const templateId = submitForm?.templateId || tpl.templateId; |
| | | const instanceId = existingRow?.id ?? submitForm?.instanceId; |
| | | const taskList = mapFlowNodesToTasks(flowNodes || submitForm?.flowNodes, { |
| | |
| | | tasks: taskList, |
| | | }; |
| | | |
| | | const attachments = |
| | | (Array.isArray(submitForm?.storageBlobDTOs) && submitForm.storageBlobDTOs.length |
| | | ? submitForm.storageBlobDTOs |
| | | : null) || tpl.storageBlobDTOs; |
| | | const attachments = (Array.isArray(submitForm?.storageBlobDTOs) && submitForm.storageBlobDTOs.length ? submitForm.storageBlobDTOs : null) || tpl.storageBlobDTOs; |
| | | if (attachments?.length) dto.storageBlobDTOs = attachments; |
| | | |
| | | if (isUpdate) { |
| | | dto.id = existingRow?.id ?? submitForm?.instanceId; |
| | | dto.instanceNo = existingRow?.instanceNo ?? submitForm?.instanceNo ?? ""; |
| | | dto.status = |
| | | submitForm?.saveStatusApi || |
| | | existingRow?.statusRaw || |
| | | mapInstanceStatusToApi(existingRow?.approvalStatus) || |
| | | "PENDING"; |
| | | dto.status = submitForm?.saveStatusApi || existingRow?.statusRaw || mapInstanceStatusToApi(existingRow?.approvalStatus) || "PENDING"; |
| | | dto.currentLevel = existingRow?.currentLevel ?? submitForm?.currentLevel ?? 1; |
| | | dto.applicantId = existingRow?.applicantId ?? existingRow?.applicantNo; |
| | | dto.applicantName = existingRow?.applicantName || ""; |
| | |
| | | /** 页面 approvalStatus → 后端 status */ |
| | | export function mapInstanceStatusToApi(approvalStatus) { |
| | | const key = normalizeApprovalStatusKey(approvalStatus); |
| | | const hit = APPROVAL_STATUS_OPTIONS.find((x) => x.value === key); |
| | | const hit = APPROVAL_STATUS_OPTIONS.find(x => x.value === key); |
| | | return hit?.api || "PENDING"; |
| | | } |
| | | |
| | |
| | | const resolved = resolveInstanceFormFields(row); |
| | | const { fields, formPayload, templateSnapshot } = resolved; |
| | | const tasks = Array.isArray(row.tasks) ? row.tasks : []; |
| | | const flowNodes = tasks.length |
| | | ? mapTasksToFlowNodes(tasks) |
| | | : mapNodesFromApi(row.nodes || row.flowNodes); |
| | | const flowNodes = tasks.length ? mapTasksToFlowNodes(tasks) : mapNodesFromApi(row.nodes || row.flowNodes); |
| | | const approvalRecords = mapRecordsFromApi(row.records); |
| | | return { |
| | | id: row.id, |
| | |
| | | tasks, |
| | | records: Array.isArray(row.records) ? row.records : [], |
| | | storageBlobVOList: row.storageBlobVOList || [], |
| | | storageBlobDTOs: row.storageBlobVOList || row.storageBlobDTOs || [], |
| | | flowNodes, |
| | | approvalFlowNodes: [], |
| | | currentNodeIndex: 0, |
| | | approvalRecords, |
| | | rejectReason: |
| | | approvalRecords.find((r) => r.result === "rejected")?.opinion || "", |
| | | rejectReason: approvalRecords.find(r => r.result === "rejected")?.opinion || "", |
| | | }; |
| | | } |
| | | |
| | |
| | | }; |
| | | } |
| | | |
| | | export function buildApprovalInstanceListParams({ |
| | | page, |
| | | searchForm, |
| | | businessType, |
| | | extraParams, |
| | | }) { |
| | | export function buildApprovalInstanceListParams({ page, searchForm, businessType, extraParams }) { |
| | | const dto = buildApprovalInstanceSearchDto(searchForm, extraParams); |
| | | const bizType = businessType ?? searchForm?.businessType; |
| | | if (bizType != null && bizType !== "") { |
| | |
| | | } |
| | | |
| | | export function approvalTypeLabel(v) { |
| | | return APPROVAL_TYPE_OPTIONS.find((x) => x.value === v)?.label || v || "—"; |
| | | return APPROVAL_TYPE_OPTIONS.find(x => x.value === v)?.label || v || "—"; |
| | | } |
| | | |
| | | export function approvalTypeStyle(v) { |
| | | const hit = APPROVAL_TYPE_OPTIONS.find((x) => x.value === v); |
| | | const hit = APPROVAL_TYPE_OPTIONS.find(x => x.value === v); |
| | | if (!hit) return {}; |
| | | return { |
| | | backgroundColor: hit.cellBg, |
| | |
| | | |
| | | export function approvalStatusLabel(v) { |
| | | const key = normalizeApprovalStatusKey(v); |
| | | return APPROVAL_STATUS_OPTIONS.find((x) => x.value === key)?.label || "—"; |
| | | return APPROVAL_STATUS_OPTIONS.find(x => x.value === key)?.label || "—"; |
| | | } |
| | | |
| | | /** 业务申请页状态文案:PENDING→进行中 APPROVED→已完成 REJECTED→已驳回 */ |
| | |
| | | * 进行中(PENDING)、已完成(APPROVED) 不可修改;已驳回、已撤销等可修改 |
| | | */ |
| | | export function canEditBusinessInstanceRow(row) { |
| | | const key = normalizeApprovalStatusKey( |
| | | row?.approvalStatus ?? row?.statusRaw ?? row?.status |
| | | ); |
| | | const key = normalizeApprovalStatusKey(row?.approvalStatus ?? row?.statusRaw ?? row?.status); |
| | | return key !== "pending" && key !== "approved"; |
| | | } |
| | | |
| | |
| | | /** 列表行 → 编辑表单(仅用行数据回显) */ |
| | | export function buildEditFormFromInstanceRow(row) { |
| | | const { fields, formPayload, templateSnapshot } = resolveInstanceFormFields(row); |
| | | const normalized = normalizeFlowNodes( |
| | | row?.flowNodes?.length ? row.flowNodes : mapTasksToFlowNodes(row?.tasks) |
| | | ); |
| | | const flowNodes = normalized.length |
| | | ? JSON.parse(JSON.stringify(normalized)) |
| | | : [createEmptyNode(1)]; |
| | | const normalized = normalizeFlowNodes(row?.flowNodes?.length ? row.flowNodes : mapTasksToFlowNodes(row?.tasks)); |
| | | const flowNodes = normalized.length ? JSON.parse(JSON.stringify(normalized)) : [createEmptyNode(1)]; |
| | | |
| | | return { |
| | | templateKey: String(row?.templateId || ""), |
| | |
| | | formPayload, |
| | | flowNodes, |
| | | templateAttachments: initTemplateAttachmentsFromSnapshot(templateSnapshot), |
| | | storageBlobDTOs: row?.storageBlobDTOs?.length |
| | | ? JSON.parse(JSON.stringify(row.storageBlobDTOs)) |
| | | : [], |
| | | storageBlobDTOs: (row?.storageBlobDTOs?.length ? row.storageBlobDTOs : row?.storageBlobVOList || []).map(f => JSON.parse(JSON.stringify(f))), |
| | | }; |
| | | } |
| | | |
| | |
| | | const tpl = templateOverride || null; |
| | | const payload = tpl?.fields?.length ? buildFormPayloadFromFields(tpl.fields) : { summary: "" }; |
| | | const normalized = normalizeFlowNodes(flowNodesOverride); |
| | | const flowNodes = normalized.length |
| | | ? JSON.parse(JSON.stringify(normalized)) |
| | | : [createEmptyNode(1)]; |
| | | const flowNodes = normalized.length ? JSON.parse(JSON.stringify(normalized)) : [createEmptyNode(1)]; |
| | | return { |
| | | templateKey: templateKey || "", |
| | | templateId: tpl?.templateId || "", |
| | |
| | | formFieldDefs: tpl?.fields || [], |
| | | formPayload: payload, |
| | | flowNodes, |
| | | templateAttachments: tpl?.storageBlobDTOs |
| | | ? JSON.parse(JSON.stringify(tpl.storageBlobDTOs)) |
| | | : [], |
| | | templateAttachments: tpl?.storageBlobDTOs ? JSON.parse(JSON.stringify(tpl.storageBlobDTOs)) : [], |
| | | storageBlobDTOs: [], |
| | | }; |
| | | } |