fix(web): 项目成员可见本项目流程受控文档
已打开项目的流程受控文档按成员基线展示。单文档指定人、角色白名单和私密隔离仍然优先。
This commit is contained in:
+3
-1
@@ -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]);
|
||||
|
||||
// 单文档可见性覆盖保存处理
|
||||
|
||||
@@ -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
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user