import { parseTime } from "@/utils/ruoyi"; import { formatFieldDisplayValue, getFieldOptionLabel, isSelectField, mergeFormConfigForEdit, } from "./approvalFormField.js"; import { appendDotNotationQuery, buildApprovalInstanceSearchDto, formatKnownSelectLabel, resolveInstanceFormPayload, resolveListFieldRawValue, } from "./approvalModuleListSearch.js"; export const DETAIL_STORAGE_KEY = "oa_approve_instance_detail_row"; export const INSTANCE_STATUS_TEXT = { PENDING: "进行中", APPROVED: "已通过", REJECTED: "已驳回", DRAFT: "草稿", }; export const INSTANCE_STATUS_TAG = { PENDING: "warning", APPROVED: "success", REJECTED: "error", DRAFT: "info", }; export const TASK_STATUS_TEXT = { PENDING: "待处理", APPROVED: "已通过", REJECTED: "已驳回", }; export const TASK_STATUS_TAG = { PENDING: "warning", APPROVED: "success", REJECTED: "error", }; export function instanceStatusText(status) { return INSTANCE_STATUS_TEXT[status] || status || "-"; } export function instanceStatusTagType(status) { return INSTANCE_STATUS_TAG[status] || "info"; } export function taskStatusText(status) { const key = String(status || "").toUpperCase(); return TASK_STATUS_TEXT[key] || status || "待处理"; } export function taskStatusTagType(status) { const key = String(status || "").toUpperCase(); return TASK_STATUS_TAG[key] || "info"; } export function formatDateTime(val) { if (!val) return "-"; return parseTime(val, "{y}-{m}-{d} {h}:{i}:{s}") || String(val); } /** 解析实例为只读展示字段(合并 formPayload,支持传整行或仅 formConfig) */ export function resolveInstanceDisplayFields(formConfigOrRow) { const row = formConfigOrRow && typeof formConfigOrRow === "object" && (formConfigOrRow.formConfig != null || formConfigOrRow.formPayload != null || formConfigOrRow.formFieldDefs != null) ? formConfigOrRow : { formConfig: formConfigOrRow }; const { fields } = resolveInstanceFormPayload(row); if (fields.length) return fields.filter(f => f?.key); const merged = mergeFormConfigForEdit("", row.formConfig); return (merged.fields || []).filter(f => f?.key); } export function displayFieldValue(field) { const val = field.value ?? field.defaultValue; if (val === undefined || val === null || val === "") return "-"; if (isSelectField(field)) { const fromOptions = getFieldOptionLabel(field, val); if (fromOptions && fromOptions !== "-") return fromOptions; const known = formatKnownSelectLabel(field.key, val); if (known) return known; return String(val); } const known = formatKnownSelectLabel(field?.key, val); if (known) return known; const shown = formatFieldDisplayValue(field, val); return shown || String(val); } const DATETIME_LIST_PROPS = new Set([ "startTime", "endTime", "overtimeDate", "applyTime", ]); function formatListFieldDisplay(prop, val, field) { if (val === undefined || val === null || val === "") return "-"; if (DATETIME_LIST_PROPS.has(prop)) { const shown = formatDateTime(val); if (shown && shown !== "-") return shown; } if (field?.type === "datetimerange") { const shown = formatFieldDisplayValue(field, val); if (shown) return shown; } if (field) return displayFieldValue({ ...field, value: val }); const known = formatKnownSelectLabel(prop, val); if (known) return known; return String(val); } /** 审批记录 result:approved | rejected | pending */ export function mapRecordResult(action) { const s = String(action || "").toUpperCase(); if (s === "APPROVED" || s === "APPROVE" || s === "PASS") return "approved"; if (s === "REJECTED" || s === "REJECT" || s === "REFUSE") return "rejected"; return "pending"; } export function recordActionLabel(result) { if (result === "approved") return "通过"; if (result === "rejected") return "驳回"; return "待处理"; } export function mapApprovalRecords(records) { const list = Array.isArray(records) ? records : []; return list.map((r, index) => ({ id: r.id ?? index, operatorName: r.approverName || r.operatorName || r.createUserName || "—", result: mapRecordResult(r.approveAction ?? r.action ?? r.status), opinion: r.approveComment || r.comment || r.opinion || "", time: formatDateTime(r.approveTime || r.createTime || r.time), })); } export function getRejectReasonFromRecords(records) { const mapped = mapApprovalRecords(records); const hit = mapped.find(r => r.result === "rejected"); return hit?.opinion || ""; } /** 列表 tasks → 流程节点(与 apply 页节点结构接近) */ export function mapTasksToFlowNodes(tasks) { const list = Array.isArray(tasks) ? tasks : []; if (!list.length) return []; const byLevel = new Map(); list.forEach(t => { const level = Number(t.levelNo ?? t.taskLevel ?? t.nodeOrder ?? 1); if (!byLevel.has(level)) { byLevel.set(level, { levelNo: level, approveType: t.approveType || "AND", approvers: [], }); } const node = byLevel.get(level); node.approvers.push({ approverName: t.approverName || "—", taskStatus: t.taskStatus ?? t.status, approveComment: t.approveComment, approveTime: t.approveTime, }); if (t.approveType) node.approveType = t.approveType; }); return [...byLevel.entries()] .sort(([a], [b]) => a - b) .map(([, node]) => node); } /** 组装审批提交 DTO(与 Web buildApproveInstanceDto 一致) */ export function buildApproveInstanceDto(id, uiResult, comment) { const opinion = (comment || "").trim(); return { id, approveAction: uiResult === "rejected" ? "REJECTED" : "APPROVED", approveComment: opinion || (uiResult === "approved" ? "同意" : ""), }; } /** 是否本人发起的审批 */ export function isOwnApplication(item, userStore) { const uid = userStore?.id; if (item?.applicantId != null && uid != null && uid !== "") { return String(item.applicantId) === String(uid); } const loginName = userStore?.nickName || userStore?.name; if (loginName && item?.applicantName) { return String(item.applicantName).trim() === String(loginName).trim(); } return false; } /** 仅进行中且本人发起时可编辑 */ export function canModifyInstance(item, userStore) { return item?.status === "PENDING" && isOwnApplication(item, userStore); } /** 待当前用户审批 */ export function canApproveInstance(item) { return Boolean(item?.isApprove) && item?.status === "PENDING"; } export function stashInstanceRow(item) { if (item) { uni.setStorageSync(DETAIL_STORAGE_KEY, item); } } export function loadInstanceRow(id) { const row = uni.getStorageSync(DETAIL_STORAGE_KEY); if (!row || String(row.id) !== String(id)) return null; return row; } export const EDIT_STORAGE_KEY = "oa_approve_instance_edit_row"; /** 业务申请页状态:进行中/已完成不可修改(与 Web canEditBusinessInstanceRow 一致) */ export function normalizeApprovalStatusKey(v) { if (v == null || v === "") return "pending"; const upper = String(v).trim().toUpperCase(); if (upper === "DRAFT") return "draft"; if (upper === "APPROVED" || upper === "PASS") return "approved"; if (upper === "REJECTED" || upper === "REJECT" || upper === "REFUSE") { return "rejected"; } if (upper === "CANCELLED" || upper === "CANCEL") return "cancelled"; if (upper === "PENDING" || upper === "IN_PROGRESS") return "pending"; const lower = String(v).trim().toLowerCase(); if (["draft", "pending", "approved", "rejected", "cancelled"].includes(lower)) { return lower; } return "pending"; } export function canEditBusinessInstanceRow(row) { const key = normalizeApprovalStatusKey(row?.status ?? row?.approvalStatus); return key !== "pending" && key !== "approved"; } export function businessStatusText(status) { const key = normalizeApprovalStatusKey(status); if (key === "draft") return "草稿"; if (key === "pending") return "进行中"; if (key === "approved") return "已完成"; if (key === "rejected") return "已驳回"; if (key === "cancelled") return "已撤销"; return instanceStatusText(status); } export function businessStatusTagType(status) { const key = normalizeApprovalStatusKey(status); if (key === "approved") return "success"; if (key === "rejected") return "error"; if (key === "draft" || key === "cancelled") return "info"; return "warning"; } /** OA 列表自定义状态角标 class */ export function businessStatusClass(status) { return `status-${normalizeApprovalStatusKey(status)}`; } /** * 与 Web buildApprovalInstanceListParams 一致 */ export function buildInstanceListParams({ page, businessType, extraDto = {}, searchForm, }) { const dto = buildApprovalInstanceSearchDto(searchForm, extraDto); const bizType = businessType ?? searchForm?.businessType; if (bizType != null && bizType !== "") { dto.businessType = bizType; } const params = { current: page.current, size: page.size, "page.current": page.current, "page.size": page.size, ...dto, }; appendDotNotationQuery(params, "approvalInstanceDto", dto); return params; } export function unwrapInstancePage(res) { const data = res?.data ?? res; return { records: Array.isArray(data?.records) ? data.records : [], total: Number(data?.total ?? 0), }; } /** 从实例行提取列表展示字段(label + value,含 formPayload) */ export function buildFormDisplayRows(row, listFields = []) { const { fields, formPayload } = resolveInstanceFormPayload(row); const fieldByKey = new Map((fields || []).map(f => [f.key, f])); const rows = []; const defs = listFields || []; if (defs.length) { defs.forEach(def => { if (!def?.prop) return; const prop = def.prop; const hit = fieldByKey.get(prop); const raw = resolveListFieldRawValue(prop, row, fields, formPayload); rows.push({ label: def.label || hit?.label || prop, value: formatListFieldDisplay(prop, raw, hit), }); }); } else { fields.slice(0, 3).forEach(f => { rows.push({ label: f.label, value: displayFieldValue(f) }); }); } return rows; } /** 列表行增强(保留原始字段供详情/编辑) */ export function mapInstanceListRow(row, listFields = []) { if (!row) return {}; const displayRows = buildFormDisplayRows(row, listFields); const extra = {}; const { fields, formPayload } = resolveInstanceFormPayload(row); (listFields || []).forEach(def => { if (!def?.prop) return; const hit = fields.find(f => f.key === def.prop); const raw = resolveListFieldRawValue(def.prop, row, fields, formPayload); extra[def.prop] = formatListFieldDisplay(def.prop, raw, hit); }); return { ...row, approvalStatus: normalizeApprovalStatusKey(row.status), summary: row.title || row.templateName || "", createTime: formatDateTime(row.applyTime || row.createTime), displayRows, formPayload, formFieldDefs: fields, ...extra, }; }