feat(gxmu): 模块下拉改由模块注册表驱动,审批链每级支持审批人规则
- 新增模块注册表 api 与进程内缓存(首次使用拉一次、并发共用同一个请求), 启用清单驱动「可新建审批链」的模块下拉与审核列表模块筛选 - reviewFlowConfigEdit 不再维护硬编码模块清单;停用模块的历史配置按 「标题(已停用)」回显,避免下拉空白 - module → detailKey 的映射收敛到 detailKeyOf 一处,moduleDetailConfig 未命中注册表时回退 module 本身(停用模块的详情仍可打开) - 审核流每级新增「审批人规则」输入(USER:<userId> / COLLEGE_ROLE:<roleCode>, 分号拼装多段,留空沿用「指定人」),随该级提交 reviewerRule 并回显 - 新增 scripts/selfcheck-module-registry.mjs:前端无单测基建时验证下拉过滤、 detailKey 回退与停用模块回显
This commit is contained in:
@@ -63,6 +63,12 @@
|
||||
@focus="loadReviewUsers(item.organizationId)"
|
||||
@update:value="updateReviewUser(index, $event)"
|
||||
/>
|
||||
<a-input
|
||||
allow-clear
|
||||
:value="item.reviewerRule"
|
||||
:placeholder="reviewerRulePlaceholder"
|
||||
@update:value="updateReviewerRule(index, $event)"
|
||||
/>
|
||||
</div>
|
||||
<a-space :size="4">
|
||||
<a-button
|
||||
@@ -109,6 +115,8 @@
|
||||
interface ReviewFlowItem {
|
||||
organizationId?: number;
|
||||
reviewUserId?: number;
|
||||
// 审批人规则:';' 分隔可拼装多段,USER:<userId> / COLLEGE_ROLE:<roleCode>
|
||||
reviewerRule?: string;
|
||||
}
|
||||
|
||||
interface ReviewFlowForm extends Omit<ReviewFlow, 'reviewUserId'> {
|
||||
@@ -148,6 +156,9 @@
|
||||
const reviewUserOptionsMap = ref<Record<number, User[]>>({});
|
||||
const reviewUserLoadingMap = ref<Record<number, boolean>>({});
|
||||
const reviewUserNameMap = ref<Record<number, string>>({});
|
||||
// 审批人规则语法见 docs/adr/0006-approval-chain-convergence.md
|
||||
const reviewerRulePlaceholder =
|
||||
'审批人规则:USER:12 或 COLLEGE_ROLE:COLLEGE_LEAGUE_SECRETARY,可用 ; 拼装多段,留空沿用「指定人」';
|
||||
|
||||
// 用户信息
|
||||
const form = reactive<ReviewFlowForm>({
|
||||
@@ -190,9 +201,13 @@
|
||||
},
|
||||
{
|
||||
validator: async () => {
|
||||
const invalid = form.flowItems.some((item) => !item.reviewUserId);
|
||||
const invalid = form.flowItems.some(
|
||||
(item) => !item.reviewUserId && !item.reviewerRule?.trim()
|
||||
);
|
||||
if (invalid) {
|
||||
return Promise.reject(new Error('请为每一级选择审核人'));
|
||||
return Promise.reject(
|
||||
new Error('请为每一级选择审核人或填写审批人规则')
|
||||
);
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
@@ -357,6 +372,12 @@
|
||||
syncOrganizationIds();
|
||||
};
|
||||
|
||||
const updateReviewerRule = (index: number, reviewerRule?: string) => {
|
||||
const items = [...form.flowItems];
|
||||
items[index] = { ...items[index], reviewerRule };
|
||||
form.flowItems = items;
|
||||
};
|
||||
|
||||
const getSortedFlows = () => {
|
||||
if (props.data?.flows?.length) {
|
||||
return [...props.data.flows].sort(
|
||||
@@ -399,6 +420,7 @@
|
||||
title: form.title,
|
||||
organizationId: item.organizationId,
|
||||
reviewUserId: item.reviewUserId,
|
||||
reviewerRule: item.reviewerRule?.trim() || undefined,
|
||||
level: index + 1
|
||||
};
|
||||
delete (formData as ReviewFlow & { organizationIds?: number[] })
|
||||
@@ -452,7 +474,8 @@
|
||||
.filter((item) => typeof item.organizationId === 'number')
|
||||
.map((item) => ({
|
||||
organizationId: item.organizationId,
|
||||
reviewUserId: item.reviewUserId
|
||||
reviewUserId: item.reviewUserId,
|
||||
reviewerRule: item.reviewerRule
|
||||
}));
|
||||
syncOrganizationIds();
|
||||
await preloadReviewUsers();
|
||||
@@ -503,7 +526,10 @@
|
||||
}
|
||||
|
||||
.flow-step-reviewer {
|
||||
width: 220px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
width: 320px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user