| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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, |
| | | }; |
| | | } |