fix(web): align workbench user ids with auth seed
Unify MOCK_USERS with backend auth (admin id=1), merge session identity on login, and migrate demo seeds/tests to id 2/3/4 for 张工/李/王. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
committed by
weichen
co-authored by
Cursor
parent
a8c8cba447
commit
636eb0ccf1
@@ -53,7 +53,7 @@ const SAMPLE_DELIVERABLES: DeliverableItem[] = [
|
||||
title: '4K超高清荧光内窥镜立项报告',
|
||||
stage: 'V0.1',
|
||||
category: 'workflow',
|
||||
creatorId: 1,
|
||||
creatorId: 2,
|
||||
creatorName: '张工',
|
||||
isFixedWorkflow: true,
|
||||
isTemplateOnly: false,
|
||||
@@ -89,7 +89,7 @@ const SAMPLE_DELIVERABLES: DeliverableItem[] = [
|
||||
title: 'Sony vs 长光辰芯 CMOS 传感器成本分析',
|
||||
stage: 'V0.5',
|
||||
category: 'shared',
|
||||
creatorId: 1,
|
||||
creatorId: 2,
|
||||
creatorName: '张工',
|
||||
sharedAt: '2026-09-08 15:00',
|
||||
isFixedWorkflow: false,
|
||||
@@ -108,7 +108,7 @@ const SAMPLE_DELIVERABLES: DeliverableItem[] = [
|
||||
title: '张工个人商务底线与让利谈判备忘',
|
||||
stage: 'V1.0',
|
||||
category: 'private',
|
||||
creatorId: 1,
|
||||
creatorId: 2,
|
||||
creatorName: '张工',
|
||||
isFixedWorkflow: false,
|
||||
isTemplateOnly: false,
|
||||
@@ -126,7 +126,7 @@ const SAMPLE_DELIVERABLES: DeliverableItem[] = [
|
||||
title: '李主管专属:团队工时饱和度与绩效评估',
|
||||
stage: 'V0.5',
|
||||
category: 'private',
|
||||
creatorId: 2,
|
||||
creatorId: 3,
|
||||
creatorName: '李主管',
|
||||
isFixedWorkflow: false,
|
||||
isTemplateOnly: false,
|
||||
@@ -140,9 +140,9 @@ const SAMPLE_DELIVERABLES: DeliverableItem[] = [
|
||||
];
|
||||
|
||||
test('三层交付物多用户隐私绝对隔离测试 (Multi-user Strict Privacy Isolation)', () => {
|
||||
// 1. 张工 (ID: 1) 登录:必须看到 2个工作流文档 + 1个共享文档 + 张工自己的私密文档 (共4个)
|
||||
// 1. 张工 (ID: 2) 登录:必须看到 2个工作流文档 + 1个共享文档 + 张工自己的私密文档 (共4个)
|
||||
// 严禁看到李主管的私密文档!
|
||||
const zhangView = filterVisibleDeliverables(SAMPLE_DELIVERABLES, 1);
|
||||
const zhangView = filterVisibleDeliverables(SAMPLE_DELIVERABLES, 2);
|
||||
assert.equal(zhangView.length, 4);
|
||||
assert.ok(zhangView.some((d) => d.docId === 'doc-wf-1'));
|
||||
assert.ok(zhangView.some((d) => d.docId === 'doc-wf-2'));
|
||||
@@ -150,9 +150,9 @@ test('三层交付物多用户隐私绝对隔离测试 (Multi-user Strict Privac
|
||||
assert.ok(zhangView.some((d) => d.docId === 'doc-priv-zhang'));
|
||||
assert.ok(!zhangView.some((d) => d.docId === 'doc-priv-li'), '张工界面中绝不可泄漏李主管的私密备忘');
|
||||
|
||||
// 2. 李主管 (ID: 2) 登录:必须看到 2个工作流文档 + 1个共享文档 + 李主管自己的私密文档 (共4个)
|
||||
// 2. 李主管 (ID: 3) 登录:必须看到 2个工作流文档 + 1个共享文档 + 李主管自己的私密文档 (共4个)
|
||||
// 严禁看到张工的私密文档!
|
||||
const liView = filterVisibleDeliverables(SAMPLE_DELIVERABLES, 2);
|
||||
const liView = filterVisibleDeliverables(SAMPLE_DELIVERABLES, 3);
|
||||
assert.equal(liView.length, 4);
|
||||
assert.ok(liView.some((d) => d.docId === 'doc-wf-1'));
|
||||
assert.ok(liView.some((d) => d.docId === 'doc-wf-2'));
|
||||
@@ -160,8 +160,8 @@ test('三层交付物多用户隐私绝对隔离测试 (Multi-user Strict Privac
|
||||
assert.ok(liView.some((d) => d.docId === 'doc-priv-li'));
|
||||
assert.ok(!liView.some((d) => d.docId === 'doc-priv-zhang'), '李主管界面中绝不可泄漏张工的私密谈判备忘');
|
||||
|
||||
// 3. 王总监 (ID: 3) 登录:王总监未生成任何私密文档,只应看到 2个工作流文档 + 1个共享文档 (共3个)
|
||||
const wangView = filterVisibleDeliverables(SAMPLE_DELIVERABLES, 3);
|
||||
// 3. 王总监 (ID: 4) 登录:王总监未生成任何私密文档,只应看到 2个工作流文档 + 1个共享文档 (共3个)
|
||||
const wangView = filterVisibleDeliverables(SAMPLE_DELIVERABLES, 4);
|
||||
assert.equal(wangView.length, 3);
|
||||
assert.ok(wangView.every((d) => d.category !== 'private'), '无私密文档的用户只看到公共受控与共享内容');
|
||||
});
|
||||
@@ -183,8 +183,8 @@ test('一键共享至项目参考库流转测试 (Promote to Shared Reference Te
|
||||
d.docId === sharedDoc.docId ? sharedDoc : d
|
||||
);
|
||||
|
||||
// 李主管 (ID: 2) 重新刷新视图:现在李主管可以查阅这份被共享出来的文档!
|
||||
const liViewAfterShare = filterVisibleDeliverables(updatedDeliverables, 2);
|
||||
// 李主管 (ID: 3) 重新刷新视图:现在李主管可以查阅这份被共享出来的文档!
|
||||
const liViewAfterShare = filterVisibleDeliverables(updatedDeliverables, 3);
|
||||
assert.ok(
|
||||
liViewAfterShare.some((d) => d.docId === 'doc-priv-zhang'),
|
||||
'一旦创建者一键共享,项目组成员李主管立即具有查阅权限'
|
||||
@@ -194,24 +194,24 @@ test('一键共享至项目参考库流转测试 (Promote to Shared Reference Te
|
||||
test('撤回共享恢复私有草稿测试 (Revoke Shared Reference Test)', () => {
|
||||
const sharedDoc = SAMPLE_DELIVERABLES.find((d) => d.docId === 'doc-sh-1')!;
|
||||
assert.equal(sharedDoc.category, 'shared');
|
||||
assert.equal(sharedDoc.creatorId, 1);
|
||||
assert.equal(sharedDoc.creatorId, 2);
|
||||
|
||||
// 1. 非创建者 (李主管 ID: 2) 尝试撤回:必须抛出权限越权异常
|
||||
// 1. 非创建者 (李主管 ID: 3) 尝试撤回:必须抛出权限越权异常
|
||||
assert.throws(
|
||||
() => revokeShareToPrivate(sharedDoc, 2),
|
||||
() => revokeShareToPrivate(sharedDoc, 3),
|
||||
/只有该共享文档的创建者本人方可撤回为私有/
|
||||
);
|
||||
|
||||
// 2. 创建者 (张工 ID: 1) 正确执行撤回
|
||||
const revokedDoc = revokeShareToPrivate(sharedDoc, 1);
|
||||
// 2. 创建者 (张工 ID: 2) 正确执行撤回
|
||||
const revokedDoc = revokeShareToPrivate(sharedDoc, 2);
|
||||
assert.equal(revokedDoc.category, 'private');
|
||||
assert.equal(revokedDoc.sharedAt, undefined);
|
||||
|
||||
// 3. 验证撤回后李主管 (ID: 2) 的视图已彻底不可见
|
||||
// 3. 验证撤回后李主管 (ID: 3) 的视图已彻底不可见
|
||||
const updatedDeliverables = SAMPLE_DELIVERABLES.map((d) =>
|
||||
d.docId === revokedDoc.docId ? revokedDoc : d
|
||||
);
|
||||
const liViewAfterRevoke = filterVisibleDeliverables(updatedDeliverables, 2);
|
||||
const liViewAfterRevoke = filterVisibleDeliverables(updatedDeliverables, 3);
|
||||
assert.ok(
|
||||
!liViewAfterRevoke.some((d) => d.docId === 'doc-sh-1'),
|
||||
'撤回私有后,其他成员立刻无法访问该文档'
|
||||
|
||||
@@ -9,7 +9,7 @@ test('集成验证:项目切换时交付物严格隔离,新建项目即刻
|
||||
projectId: 1,
|
||||
projectName: '4K超高清荧光内窥镜系统',
|
||||
deviceType: '硬管荧光腹腔内窥镜',
|
||||
creatorId: 1,
|
||||
creatorId: 2,
|
||||
creatorName: '张工',
|
||||
});
|
||||
|
||||
@@ -18,7 +18,7 @@ test('集成验证:项目切换时交付物严格隔离,新建项目即刻
|
||||
projectId: 2,
|
||||
projectName: '便携式掌上无线超声诊断仪',
|
||||
deviceType: '便携式超声探头',
|
||||
creatorId: 1,
|
||||
creatorId: 2,
|
||||
creatorName: '张工',
|
||||
});
|
||||
|
||||
@@ -64,7 +64,7 @@ test('集成验证:三层隐私与项目物理隔离双重约束', () => {
|
||||
projectId: 1,
|
||||
projectName: '项目A',
|
||||
deviceType: '器械A',
|
||||
creatorId: 1,
|
||||
creatorId: 2,
|
||||
creatorName: '张工',
|
||||
});
|
||||
|
||||
@@ -72,7 +72,7 @@ test('集成验证:三层隐私与项目物理隔离双重约束', () => {
|
||||
projectId: 2,
|
||||
projectName: '项目B',
|
||||
deviceType: '器械B',
|
||||
creatorId: 1,
|
||||
creatorId: 2,
|
||||
creatorName: '张工',
|
||||
});
|
||||
|
||||
@@ -84,7 +84,7 @@ test('集成验证:三层隐私与项目物理隔离双重约束', () => {
|
||||
title: '张工专属推演备忘',
|
||||
stage: 'V0.5',
|
||||
category: 'private',
|
||||
creatorId: 1,
|
||||
creatorId: 2,
|
||||
creatorName: '张工',
|
||||
isFixedWorkflow: false,
|
||||
isTemplateOnly: false,
|
||||
@@ -103,7 +103,7 @@ test('集成验证:三层隐私与项目物理隔离双重约束', () => {
|
||||
title: '李主管专属预算底稿',
|
||||
stage: 'V0.5',
|
||||
category: 'private',
|
||||
creatorId: 2,
|
||||
creatorId: 3,
|
||||
creatorName: '李主管',
|
||||
isFixedWorkflow: false,
|
||||
isTemplateOnly: false,
|
||||
@@ -120,14 +120,14 @@ test('集成验证:三层隐私与项目物理隔离双重约束', () => {
|
||||
// 1. 张工在项目 1:可看 7 份工作流模板 + 自己的私密文档 = 8 份 (李主管私密文档绝对不可见)
|
||||
const zhangP1Visible = allDocs
|
||||
.filter((d) => d.projectId === 1)
|
||||
.filter((d) => d.category === 'workflow' || d.category === 'shared' || d.creatorId === 1);
|
||||
.filter((d) => d.category === 'workflow' || d.category === 'shared' || d.creatorId === 2);
|
||||
assert.strictEqual(zhangP1Visible.length, 8);
|
||||
assert.ok(!zhangP1Visible.some((d) => d.docId === 'doc-p1-priv-li'));
|
||||
|
||||
// 2. 张工在项目 2:仅可看项目 2 的 7 份模板,项目 1 的任何交付物(包括张工自己的私密文档)均不穿透
|
||||
const zhangP2Visible = allDocs
|
||||
.filter((d) => d.projectId === 2)
|
||||
.filter((d) => d.category === 'workflow' || d.category === 'shared' || d.creatorId === 1);
|
||||
.filter((d) => d.category === 'workflow' || d.category === 'shared' || d.creatorId === 2);
|
||||
assert.strictEqual(zhangP2Visible.length, 7);
|
||||
assert.ok(zhangP2Visible.every((d) => d.projectId === 2));
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ const sampleUsers: Record<string, UserProfile> = {
|
||||
roleId: 'role-admin',
|
||||
},
|
||||
director: {
|
||||
id: 3,
|
||||
id: 4,
|
||||
name: '王总监',
|
||||
employeeId: 'SMDF-0018',
|
||||
department: '医疗器械研发事业部',
|
||||
@@ -28,7 +28,7 @@ const sampleUsers: Record<string, UserProfile> = {
|
||||
roleId: 'role-director',
|
||||
},
|
||||
lead: {
|
||||
id: 2,
|
||||
id: 3,
|
||||
name: '李主管',
|
||||
employeeId: 'SMDF-0205',
|
||||
department: '机器人与微创内窥镜研发中心',
|
||||
@@ -36,7 +36,7 @@ const sampleUsers: Record<string, UserProfile> = {
|
||||
roleId: 'role-tech-lead',
|
||||
},
|
||||
engineer: {
|
||||
id: 1,
|
||||
id: 2,
|
||||
name: '张工',
|
||||
employeeId: 'SMDF-0821',
|
||||
department: '机器人与微创内窥镜研发中心',
|
||||
@@ -60,7 +60,7 @@ const createMockDoc = (overrides: Partial<DeliverableItem> = {}): DeliverableIte
|
||||
title: '测试受控交付物',
|
||||
stage: 'V0.1',
|
||||
category: 'workflow',
|
||||
creatorId: 1,
|
||||
creatorId: 2,
|
||||
creatorName: '张工',
|
||||
isFixedWorkflow: true,
|
||||
isTemplateOnly: false,
|
||||
@@ -177,7 +177,7 @@ test('用例 6: 单文档覆盖 - public (放宽可见性,无 workflow:view_al
|
||||
test('用例 7: 私密文档隔离强红线 (category === private 无论任何管理员或单文档覆盖,非创建者绝对不可见)', () => {
|
||||
const privateDraft = createMockDoc({
|
||||
category: 'private',
|
||||
creatorId: 1, // 张工创建
|
||||
creatorId: 2, // 张工创建
|
||||
creatorName: '张工',
|
||||
visibilityRule: {
|
||||
mode: 'public', // 即使误设 public 也绝不能穿透 private 隔离
|
||||
@@ -232,7 +232,7 @@ test('用例 9: filterVisibleDeliverablesWithRBAC 能够批处理过滤大盘交
|
||||
docId: 'doc-3',
|
||||
title: '张工个人草案',
|
||||
category: 'private',
|
||||
creatorId: 1,
|
||||
creatorId: 2,
|
||||
}),
|
||||
];
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ test('集成场景 1: 动态新增合规审计员角色,并配置其仅能查
|
||||
title: '常规内部立项可行性报告',
|
||||
stage: 'V0.1',
|
||||
category: 'workflow',
|
||||
creatorId: 1,
|
||||
creatorId: 2,
|
||||
creatorName: '张工',
|
||||
isFixedWorkflow: true,
|
||||
isTemplateOnly: false,
|
||||
@@ -63,7 +63,7 @@ test('集成场景 1: 动态新增合规审计员角色,并配置其仅能查
|
||||
title: '器械注册与临床评价白皮书 (开放审计)',
|
||||
stage: 'V0.5',
|
||||
category: 'workflow',
|
||||
creatorId: 1,
|
||||
creatorId: 2,
|
||||
creatorName: '张工',
|
||||
isFixedWorkflow: true,
|
||||
isTemplateOnly: false,
|
||||
@@ -86,7 +86,7 @@ test('集成场景 1: 动态新增合规审计员角色,并配置其仅能查
|
||||
title: '张工敏感商业测算草案',
|
||||
stage: 'V0.1',
|
||||
category: 'private',
|
||||
creatorId: 1,
|
||||
creatorId: 2,
|
||||
creatorName: '张工',
|
||||
isFixedWorkflow: false,
|
||||
isTemplateOnly: false,
|
||||
@@ -120,7 +120,7 @@ test('集成场景 2: 动态修改角色权限矩阵,权限即刻全量生效'
|
||||
assert.equal(engineerRole.permissions.includes('project:create'), false);
|
||||
|
||||
const zhangUser: UserProfile = {
|
||||
id: 1,
|
||||
id: 2,
|
||||
name: '张工',
|
||||
employeeId: 'SMDF-0821',
|
||||
department: '微创中心',
|
||||
@@ -146,7 +146,7 @@ test('集成场景 3: 单文档覆盖 designated_only 严格收紧与撤回恢
|
||||
const roles = DEFAULT_ROLES;
|
||||
|
||||
const zhangAuthor: UserProfile = {
|
||||
id: 1,
|
||||
id: 2,
|
||||
name: '张工',
|
||||
employeeId: 'SMDF-0821',
|
||||
department: '微创中心',
|
||||
@@ -155,7 +155,7 @@ test('集成场景 3: 单文档覆盖 designated_only 严格收紧与撤回恢
|
||||
};
|
||||
|
||||
const liReviewer: UserProfile = {
|
||||
id: 2,
|
||||
id: 3,
|
||||
name: '李主管',
|
||||
employeeId: 'SMDF-0205',
|
||||
department: '微创中心',
|
||||
@@ -179,7 +179,7 @@ test('集成场景 3: 单文档覆盖 designated_only 严格收紧与撤回恢
|
||||
title: '涉密荧光滤光片设计图',
|
||||
stage: 'V0.5',
|
||||
category: 'workflow',
|
||||
creatorId: 1,
|
||||
creatorId: 2,
|
||||
creatorName: '张工',
|
||||
isFixedWorkflow: true,
|
||||
isTemplateOnly: false,
|
||||
|
||||
Reference in New Issue
Block a user