import { parseTime } from "@/utils/ruoyi"; import { formatFieldDisplayValue, getFieldOptionLabel, isSelectField, mergeFormConfigForEdit, } from "./approvalFormField.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); } /** 解析实例 formConfig 为只读展示字段 */ export function resolveInstanceDisplayFields(formConfig) { const merged = mergeFormConfigForEdit("", 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)) { return getFieldOptionLabel(field, val) || String(val); } const shown = formatFieldDisplayValue(field, val); return shown || 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 一致:扁平 query(current/size/businessType/...) * 审批列表不传 businessType 即查全部 */ export function buildInstanceListParams({ page, businessType, extraDto = {}, searchForm, }) { const extra = { ...(extraDto && typeof extraDto === "object" ? extraDto : {}) }; if (extra.createTime != null && extra.createTimeStart == null) { extra.createTimeStart = extra.createTime; } delete extra.createTime; const params = { current: page.current, size: page.size, ...extra, }; const bizType = businessType ?? searchForm?.businessType; if (bizType != null && bizType !== "") { params.businessType = bizType; } if (searchForm?.status) { params.status = searchForm.status; } const range = searchForm?.createTimeRange ?? searchForm?.applyDateRange ?? searchForm?.transferDateRange; if (Array.isArray(range) && range[0] && params.createTimeStart == null) { params.createTimeStart = range[0]; } if (Array.isArray(range) && range[1] && params.createTimeEnd == null) { params.createTimeEnd = range[1]; } return params; } export function unwrapInstancePage(res) { const data = res?.data ?? res; return { records: Array.isArray(data?.records) ? data.records : [], total: Number(data?.total ?? 0), }; } /** 从 formConfig 提取列表展示字段(label + value) */ export function buildFormDisplayRows(formConfig, listFields = []) { const fields = resolveInstanceDisplayFields(formConfig); const rows = []; const propKeys = (listFields || []).map(f => f.prop).filter(Boolean); if (propKeys.length) { propKeys.forEach(prop => { const hit = fields.find(f => f.key === prop); if (hit) { rows.push({ label: hit.label, value: displayFieldValue(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.formConfig, listFields); const extra = {}; const formFields = resolveInstanceDisplayFields(row.formConfig); (listFields || []).forEach(def => { if (!def?.prop) return; const hit = formFields.find(f => f.key === def.prop); extra[def.prop] = hit ? displayFieldValue(hit) : "-"; }); const formPayload = {}; formFields.forEach(f => { if (f?.key) formPayload[f.key] = f.value ?? f.defaultValue ?? ""; }); return { ...row, approvalStatus: normalizeApprovalStatusKey(row.status), summary: row.title || row.templateName || "", createTime: formatDateTime(row.applyTime || row.createTime), displayRows, formPayload, ...extra, }; }