yyb
9 小时以前 22002c2b5bf09bb769a51448537fa6a572a3ea88
费用报销的审批流程
已修改4个文件
118 ■■■■ 文件已修改
src/views/officeProcessAutomation/ReimburseManage/cost-reimburse/costReimburseUtils.js 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/officeProcessAutomation/ReimburseManage/cost-reimburse/useCostReimburse.js 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/officeProcessAutomation/ReimburseManage/shared/finReimbursementMappers.js 63 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/officeProcessAutomation/ReimburseManage/travel-reimburse/useTravelReimburse.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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) {
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);
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);
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);