fix(web): 项目成员可见本项目流程受控文档

已打开项目的流程受控文档按成员基线展示。单文档指定人、角色白名单和私密隔离仍然优先。
This commit is contained in:
weichen
2026-09-28 15:36:39 +00:00
parent 721af4ccb8
commit 32568ed13e
3 changed files with 37 additions and 7 deletions
+3 -1
View File
@@ -472,7 +472,9 @@ export default function App() {
// 基于当前登录用户与 RBAC 规则过滤可见交付物 (私密文档严格按 creatorId 隔离,单文档覆盖优先于工作流基线)
const visibleDeliverables = useMemo(() => {
return filterVisibleDeliverablesWithRBAC(currentProjectDeliverables, currentUser, roles);
return filterVisibleDeliverablesWithRBAC(currentProjectDeliverables, currentUser, roles, {
projectMember: true,
});
}, [currentProjectDeliverables, currentUser, roles]);
// 单文档可见性覆盖保存处理
+20 -1
View File
@@ -112,8 +112,21 @@ test('用例 3: 常规工作流基线可见性 (workflow:view_all) 判定', () =
// 工程师有 workflow:view_all -> 可见
assert.equal(isDeliverableVisible(sampleUsers.engineer, DEFAULT_ROLES, normalDoc), true);
// 外部审计员无 workflow:view_all 且不是责任人 -> 不可见
// 外部审计员无 workflow:view_all 且不是项目成员 -> 不可见
assert.equal(isDeliverableVisible(sampleUsers.guest, DEFAULT_ROLES, normalDoc), false);
// 同一访客作为项目成员打开本项目 -> 可见流程受控文档
assert.equal(
isDeliverableVisible(sampleUsers.guest, DEFAULT_ROLES, normalDoc, { projectMember: true }),
true,
);
const memberVisible = filterVisibleDeliverablesWithRBAC(
[normalDoc],
sampleUsers.guest,
DEFAULT_ROLES,
{ projectMember: true },
);
assert.equal(memberVisible.length, 1);
});
test('用例 4: 单文档覆盖 - designated_only (仅编制/审核/批准人可见,其他用户被精确拦截)', () => {
@@ -138,6 +151,12 @@ test('用例 4: 单文档覆盖 - designated_only (仅编制/审核/批准人可
// 王总监虽为研发总监,但非三权责任人 -> 被单文档覆盖拦截 (不可见)
assert.equal(isDeliverableVisible(sampleUsers.director, DEFAULT_ROLES, restrictedDoc), false);
// 项目成员身份不覆盖「仅责任人」收紧
assert.equal(
isDeliverableVisible(sampleUsers.guest, DEFAULT_ROLES, restrictedDoc, { projectMember: true }),
false,
);
// 系统管理员超级权限仍可见
assert.equal(isDeliverableVisible(sampleUsers.admin, DEFAULT_ROLES, restrictedDoc), true);
});
+14 -5
View File
@@ -108,12 +108,14 @@ export function hasPermission(
* - designated_only: 仅责任人可见 (非责任人已在步骤4排除,直接拒绝)
* - role_whitelist: 仅白名单内角色可见
* - public: 全员可见
* 6. 回退继承工作流基线:用户角色需具备 workflow:view_all 权限
* 6. 项目成员:已打开的项目内,流程受控文档对 active 成员可见(非成员不传 projectMember)
* 7. 回退继承工作流基线:用户角色需具备 workflow:view_all 权限
*/
export function isDeliverableVisible(
user: UserProfile,
roles: RoleDefinition[],
doc: DeliverableItem
doc: DeliverableItem,
options?: { projectMember?: boolean },
): boolean {
// 步骤 1:个人私密文档 (private) 绝对隔离
if (doc.category === 'private') {
@@ -166,7 +168,13 @@ export function isDeliverableVisible(
}
}
// 步骤 6:回退继承工作流默认基线规则(文档可见性仍用角色矩阵作 UI 展示兜底)
// 步骤 6:项目成员可见本项目流程受控文档。
// 非成员仍回退到 workflow:view_all;单文档覆盖(步骤 5)优先于成员基线。
if (doc.category === 'workflow' && options?.projectMember) {
return true;
}
// 步骤 7:回退继承工作流默认基线规则(文档可见性仍用角色矩阵作 UI 展示兜底)
return hasPermission(user, roles, 'workflow:view_all', capabilitiesFromRole(roles, user.roleId));
}
@@ -176,9 +184,10 @@ export function isDeliverableVisible(
export function filterVisibleDeliverablesWithRBAC(
deliverables: DeliverableItem[],
user: UserProfile,
roles: RoleDefinition[]
roles: RoleDefinition[],
options?: { projectMember?: boolean },
): DeliverableItem[] {
return deliverables.filter((doc) => isDeliverableVisible(user, roles, doc));
return deliverables.filter((doc) => isDeliverableVisible(user, roles, doc, options));
}
/**