From 22002c2b5bf09bb769a51448537fa6a572a3ea88 Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期五, 22 五月 2026 10:25:09 +0800
Subject: [PATCH] 费用报销的审批流程
---
src/views/officeProcessAutomation/ReimburseManage/travel-reimburse/useTravelReimburse.js | 6 +++
src/views/officeProcessAutomation/ReimburseManage/cost-reimburse/useCostReimburse.js | 13 +++++-
src/views/officeProcessAutomation/ReimburseManage/cost-reimburse/costReimburseUtils.js | 36 ++++++++++++-----
src/views/officeProcessAutomation/ReimburseManage/shared/finReimbursementMappers.js | 63 ++++++++++++++++++++++---------
4 files changed, 87 insertions(+), 31 deletions(-)
diff --git a/src/views/officeProcessAutomation/ReimburseManage/cost-reimburse/costReimburseUtils.js b/src/views/officeProcessAutomation/ReimburseManage/cost-reimburse/costReimburseUtils.js
index 2d88cd5..1b9c418 100644
--- a/src/views/officeProcessAutomation/ReimburseManage/cost-reimburse/costReimburseUtils.js
+++ b/src/views/officeProcessAutomation/ReimburseManage/cost-reimburse/costReimburseUtils.js
@@ -154,18 +154,32 @@
return roles;
}
-export function buildAutoApprovalFlow(amount, expenseCategory) {
+export function buildAutoApprovalFlow(amount, expenseCategory, previousNodes = []) {
const roles = resolveApprovalRoles(amount, expenseCategory);
- return roles.map((role, i) => ({
- approverId: null,
- approverName: APPROVAL_ROLE_LABELS[role] || role,
- roleKey: role,
- sortOrder: i + 1,
- nodeOrder: i + 1,
- nodeStatus: i === 0 ? "process" : "wait",
- approveOpinion: "",
- approveTime: "",
- }));
+ const prevByRole = new Map();
+ (previousNodes || []).forEach((n, idx) => {
+ if (n?.roleKey) prevByRole.set(n.roleKey, n);
+ else if (n?.approverId != null && n.approverId !== "") {
+ prevByRole.set(`__idx_${idx}`, n);
+ }
+ });
+ return roles.map((role, i) => {
+ const prev = prevByRole.get(role) || prevByRole.get(`__idx_${i}`);
+ const hasApprover = prev?.approverId != null && prev.approverId !== "";
+ return {
+ approverId: hasApprover ? prev.approverId : null,
+ approverName: hasApprover
+ ? prev.approverName || ""
+ : APPROVAL_ROLE_LABELS[role] || role,
+ roleKey: role,
+ signMode: prev?.signMode || "countersign",
+ sortOrder: i + 1,
+ nodeOrder: i + 1,
+ nodeStatus: i === 0 ? "process" : "wait",
+ approveOpinion: "",
+ approveTime: "",
+ };
+ });
}
export function getApprovalRuleHint(amount, expenseCategory) {
diff --git a/src/views/officeProcessAutomation/ReimburseManage/cost-reimburse/useCostReimburse.js b/src/views/officeProcessAutomation/ReimburseManage/cost-reimburse/useCostReimburse.js
index 638d533..04b26ff 100644
--- a/src/views/officeProcessAutomation/ReimburseManage/cost-reimburse/useCostReimburse.js
+++ b/src/views/officeProcessAutomation/ReimburseManage/cost-reimburse/useCostReimburse.js
@@ -21,6 +21,7 @@
resolveReimbursementDeleteId,
unwrapFinReimbursementDetail,
unwrapFinReimbursementPage,
+ validateReimbursementApprovalNodes,
validateReimbursementPersistDto,
} from "../shared/finReimbursementMappers.js";
import { consumeReimburseEditFromApprove } from "../shared/reimburseApproveBridge.js";
@@ -264,7 +265,11 @@
function autoAssignApprovalFlow() {
const amount = Number(form.applyAmount) || detailTotalAmount.value || 0;
- form.approvalFlowNodes = buildAutoApprovalFlow(amount, form.expenseCategory || "other");
+ form.approvalFlowNodes = buildAutoApprovalFlow(
+ amount,
+ form.expenseCategory || "other",
+ form.approvalFlowNodes
+ );
nextTick(() => formRef.value?.validateField?.("approvalFlowNodes"));
}
@@ -448,7 +453,6 @@
return;
}
syncApplyAmountFromDetails();
- autoAssignApprovalFlow();
if (submitSaving.value) return;
const isEdit = formDialog.mode === "edit";
@@ -458,6 +462,11 @@
proxy?.$modal?.msgWarning?.(check.message);
return;
}
+ const nodeCheck = validateReimbursementApprovalNodes(dto);
+ if (!nodeCheck.ok) {
+ proxy?.$modal?.msgWarning?.(nodeCheck.message);
+ return;
+ }
submitSaving.value = true;
try {
await persistFinReimbursement(dto, isEdit);
diff --git a/src/views/officeProcessAutomation/ReimburseManage/shared/finReimbursementMappers.js b/src/views/officeProcessAutomation/ReimburseManage/shared/finReimbursementMappers.js
index 7a82873..c75f6d1 100644
--- a/src/views/officeProcessAutomation/ReimburseManage/shared/finReimbursementMappers.js
+++ b/src/views/officeProcessAutomation/ReimburseManage/shared/finReimbursementMappers.js
@@ -399,6 +399,13 @@
});
}
+/** 琛ㄥ崟涓婄殑瀹℃壒娴侊紙鍏煎 approvalFlowNodes / nodes / flowNodes锛� */
+export function resolveFormApprovalFlowNodes(form) {
+ const list =
+ form?.approvalFlowNodes ?? form?.nodes ?? form?.flowNodes ?? [];
+ return Array.isArray(list) ? list : [];
+}
+
/** 椤甸潰瀹℃壒鑺傜偣 鈫� 鎺ュ彛 nodes */
export function mapApprovalFlowNodesToApi(nodes = [], templateId) {
const list = Array.isArray(nodes) ? nodes : [];
@@ -408,36 +415,50 @@
if (Array.isArray(n.approvers) && n.approvers.length) {
approvers = n.approvers
.filter((a) => a?.approverId != null && a.approverId !== "")
- .map((a, idx) => ({
- id: a.id,
- nodeId: a.nodeId,
- templateId: a.templateId ?? templateId,
- approverId: toNumber(a.approverId) ?? a.approverId,
- approverName: a.approverName || "",
- sortNo: a.sortNo ?? idx + 1,
- }));
+ .map((a, idx) => {
+ const item = {
+ approverId: toNumber(a.approverId) ?? a.approverId,
+ approverName: a.approverName || "",
+ sortNo: a.sortNo ?? idx + 1,
+ };
+ if (a.id != null) item.id = a.id;
+ if (a.nodeId != null) item.nodeId = a.nodeId;
+ if (a.templateId != null) item.templateId = a.templateId;
+ else if (templateId != null) item.templateId = templateId;
+ if (a.roleKey) item.roleKey = a.roleKey;
+ return item;
+ });
} else if (n.approverId != null && n.approverId !== "") {
- approvers = [
- {
- approverId: toNumber(n.approverId) ?? n.approverId,
- approverName: n.approverName || "",
- sortNo: 1,
- },
- ];
+ const item = {
+ approverId: toNumber(n.approverId) ?? n.approverId,
+ approverName: n.approverName || "",
+ sortNo: 1,
+ };
+ if (n.roleKey) item.roleKey = n.roleKey;
+ approvers = [item];
}
if (!approvers.length) return null;
const node = {
- levelNo: n.levelNo ?? n.nodeOrder ?? i + 1,
+ levelNo: n.levelNo ?? n.nodeOrder ?? n.sortOrder ?? i + 1,
approveType: n.approveType || mapSignModeToApi(n.signMode),
approvers,
};
if (n.id != null) node.id = n.id;
if (n.templateId != null) node.templateId = n.templateId;
else if (templateId != null) node.templateId = templateId;
+ if (n.roleKey) node.roleKey = n.roleKey;
return node;
})
.filter(Boolean);
+}
+
+/** 淇濆瓨鍓嶆牎楠� nodes 宸查厤缃� */
+export function validateReimbursementApprovalNodes(dto) {
+ if (Array.isArray(dto?.nodes) && dto.nodes.length > 0) {
+ return { ok: true };
+ }
+ return { ok: false, message: "璇烽厤缃鎵规祦绋嬪苟閫夋嫨瀹℃壒浜�" };
}
function mapDetailsToApi(details = []) {
@@ -532,7 +553,10 @@
withinStandard: form.needSpecialApproval ? "0" : "1",
},
details,
- nodes: mapApprovalFlowNodesToApi(form.approvalFlowNodes, form.templateId),
+ nodes: mapApprovalFlowNodesToApi(
+ resolveFormApprovalFlowNodes(form),
+ form.templateId
+ ),
};
const id = resolveReimbursementId(form);
@@ -574,7 +598,10 @@
billStatus: "IN_APPROVAL",
deptId: toNumber(form.deptId),
details,
- nodes: mapApprovalFlowNodesToApi(form.approvalFlowNodes, form.templateId),
+ nodes: mapApprovalFlowNodesToApi(
+ resolveFormApprovalFlowNodes(form),
+ form.templateId
+ ),
};
const id = resolveReimbursementId(form);
diff --git a/src/views/officeProcessAutomation/ReimburseManage/travel-reimburse/useTravelReimburse.js b/src/views/officeProcessAutomation/ReimburseManage/travel-reimburse/useTravelReimburse.js
index 9aa6294..0df94e5 100644
--- a/src/views/officeProcessAutomation/ReimburseManage/travel-reimburse/useTravelReimburse.js
+++ b/src/views/officeProcessAutomation/ReimburseManage/travel-reimburse/useTravelReimburse.js
@@ -21,6 +21,7 @@
resolveReimbursementDeleteId,
unwrapFinReimbursementDetail,
unwrapFinReimbursementPage,
+ validateReimbursementApprovalNodes,
validateReimbursementPersistDto,
} from "../shared/finReimbursementMappers.js";
import { consumeReimburseEditFromApprove } from "../shared/reimburseApproveBridge.js";
@@ -517,6 +518,11 @@
proxy?.$modal?.msgWarning?.(check.message);
return;
}
+ const nodeCheck = validateReimbursementApprovalNodes(dto);
+ if (!nodeCheck.ok) {
+ proxy?.$modal?.msgWarning?.(nodeCheck.message);
+ return;
+ }
submitSaving.value = true;
try {
await persistFinReimbursement(dto, isEdit);
--
Gitblit v1.9.3