import { parseTime } from "@/utils/ruoyi";
|
import {
|
formatFieldDisplayValue,
|
getFieldOptionLabel,
|
isSelectField,
|
mergeFormConfigForEdit,
|
} from "./approvalFormField.js";
|
import {
|
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 一致:扁平 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),
|
};
|
}
|
|
/** 从实例行提取列表展示字段(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,
|
};
|
}
|