collaborativeApproval/approvalManagement/index.vuecollaborativeApproval/approvalProcess/index.vuesafeProduction/safeWorkApproval/index.vuecollaborativeApproval/approvalProcess/components/approvalDia.vuesafeProduction/safeWorkApproval/components/approvalDia.vue| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /approveProcessConfigNode/listNode | 查询审批节点配置(响应新增 approveMode 字段) |
| POST | /approveProcessConfigNode/addApproveProcessConfigNodes | 保存节点配置(每行一个审批人,同一 nodeOrder 多行即同一节点多人,需传 approveMode) |
| POST | /approveProcess/addApprove | 发起审批(新增响应/快照字段 approve_node_config,节点含多人时写入 approve_user_current_ids/names) |
| GET | /approveProcess/details | 审批详情(节点列表新增 approveMode 字段;isShen 仅当前待审节点且当前登录人可审时返回 true) |
| POST | /approveNode/updateApproveNode | 提交审批(**不再需要 isLast 参数**,流转判断由后端按节点模式完成) |
同一节点多审批人通过多条记录表达,nodeOrder 相同、approveMode 标识模式:
[
{ "approveType": 1, "nodeOrder": 1, "approverId": 11, "approverName": "张三", "approveMode": "or" },
{ "approveType": 1, "nodeOrder": 1, "approverId": 12, "approverName": "李四", "approveMode": "or" },
{ "approveType": 1, "nodeOrder": 2, "approverId": 21, "approverName": "王五", "approveMode": "and" },
{ "approveType": 1, "nodeOrder": 2, "approverId": 22, "approverName": "赵六", "approveMode": "and" }
]
approveMode:or=或签(任一人通过即流转),and=会签(需所有人通过才流转)每个节点新增:
| 字段 | 类型 | 说明 |
|---|---|---|
| approveMode | String | 节点审批模式:or / and |
| approveNodeOrder | Integer | 节点序号(同一节点的多人记录相同) |
| isShen | Boolean | 是否为当前登录人的待审节点 |
流程级新增(列表接口返回):approveUserCurrentIds、approveUserCurrentNames(当前节点全部待审人)。
collaborativeApproval/approvalManagement/index.vue
审批人改为多选,新增模式单选:
<el-form-item label="审批人">
<el-select v-model="item.approverIds" multiple filterable placeholder="选择审批人(可多选)">
<el-option v-for="u in allUsers" :key="u.userId" :label="u.nickName" :value="u.userId" />
</el-select>
</el-form-item>
<el-form-item label="审批模式">
<el-radio-group v-model="item.approveMode">
<el-radio-button value="or">或签(任意一人通过)</el-radio-button>
<el-radio-button value="and">会签(需所有人通过)</el-radio-button>
</el-radio-group>
</el-form-item>
loadData:将接口扁平配置按 nodeOrder 合并为卡片数据:
const groupMap = new Map();
(res.data || []).forEach(r => {
const order = r.nodeOrder;
if (!groupMap.has(order)) groupMap.set(order, { nodeOrder: order, approverIds: [], approverNames: [], approveMode: r.approveMode || 'or' });
const g = groupMap.get(order);
if (!g.approverIds.includes(r.approverId)) {
g.approverIds.push(r.approverId);
g.approverNames.push(r.approverName);
}
});
nodeCards.value = Array.from(groupMap.values()).sort((a, b) => a.nodeOrder - b.nodeOrder);
handleSave:每张卡片按审批人展开成多行 payload:
const list = [];
nodeCards.value.forEach(card => {
card.approverIds.forEach((uid, i) => {
list.push({
approveType: currentType,
nodeOrder: card.nodeOrder,
approverId: uid,
approverName: card.approverNames[i],
approveMode: card.approveMode || 'or',
});
});
});
await addApproveProcessConfigNodes(list);
collaborativeApproval/approvalProcess/index.vue、safeProduction/safeWorkApproval/index.vue
当前审批人列展示同节点全部待审人,富化行数据:
tableData.value = (res.data.records || []).map(r => ({
...r,
currentApproverNames: r.approveUserCurrentNames || r.approveUserCurrentName || '-',
_canApprove:
String(r.approveUserCurrentIds ?? '').split(',').filter(Boolean).includes(String(userStore.id)) ||
r.approveUserCurrentId === userStore.id,
}));
审核按钮禁用条件:
disabled: row =>
row.approveStatus == 2 || row.approveStatus == 3 || row.approveStatus == 4 || !row._canApprove,
collaborativeApproval/approvalProcess/components/approvalDia.vue、safeProduction/safeWorkApproval/components/approvalDia.vue
新增分组计算属性,同一 approveNodeOrder 的多名审批人归为一个步骤组:
const stepGroups = computed(() => {
const map = new Map();
(activities.value || []).forEach(a => {
const order = a.approveNodeOrder;
if (!map.has(order)) map.set(order, []);
map.get(order).push(a);
});
return Array.from(map.values());
});
el-steps 改为遍历 stepGroups,每组一个 el-step,组内循环渲染成员(姓名、状态、意见、签名、待审输入框):
<el-steps :active="getActiveStep()" ...>
<el-step v-for="(group, gIndex) in stepGroups" :key="gIndex" ...>
<template #title>
<span>{{ getNodeTitle(gIndex, stepGroups.length) }}</span>
<el-tag :type="group[0]?.approveMode === 'and' ? 'warning' : 'info'">
{{ group[0]?.approveMode === 'and' ? '会签' : '或签' }}
</el-tag>
</template>
<template #description>
<div v-for="(activity, aIndex) in group" :key="activity.id || aIndex" class="node-user-item">
<!-- 成员姓名、状态、审批意见;仅 isShen 成员渲染输入框 -->
</div>
</template>
</el-step>
</el-steps>
当前激活步骤取含待审成员的组下标:
const getActiveStep = () => {
const idx = stepGroups.value.findIndex(group => group.some(a => a.isShen === true));
if (idx === -1) return stepGroups.value.length;
return idx;
};
提交审批不再传 isLast:
currentActivity.approveNodeStatus = status;
updateApproveNode({ ...currentActivity }).then(() => {
proxy.$modal.msgSuccess("提交成功");
closeDia();
});
管理员账号(角色为 普通2 / admin / 最高1)可审批任意流程,不再受"审批人必须是流程节点配置的审批人"限制。
details:管理员对当前待审节点的首个待审记录返回 isShen=true(代审整节点)。updateApproveNode:管理员跳过"无权审批该节点"校验;审批通过时自动将同节点其余待审记录标记为"管理员代审通过"(或签/会签均整节点放行);拒绝仍按一票否决处理。两个列表页(approvalProcess / safeWorkApproval)新增 isAdminUser 判断:
const isAdminUser = computed(() =>
["admin", "普通2", "最高1"].some(r => (userStore.roles || []).includes(r))
);
_canApprove 对管理员恒为 true,审核按钮不再禁用:
_canApprove: isAdminUser.value || String(r.approveUserCurrentIds ?? '').split(',').filter(Boolean).includes(String(userStore.id)) || r.approveUserCurrentId === userStore.id
updateApproveNode 已改为按节点模式(或签/会签)统计同 order 的同意数决定是否流转,前端**必须删除 isLast 传参**,否则旧字段会被忽略(不影响结果,但无意义)。approveMode 为空按"或签"处理;存量流程 approveUserCurrentNames 为空时前端兜底 approveUserCurrentName。approve_node_config 快照重建节点以保持分组与模式,无快照时按"一节点一人 or"回退。