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:
WeiCHEN
2026-09-13 02:50:22 +00:00
committed by weichen
co-authored by Cursor
parent a8c8cba447
commit 636eb0ccf1
19 changed files with 217 additions and 5685 deletions
+19 -19
View File
@@ -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));
});
+6 -6
View File
@@ -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,
}),
];
+7 -7
View File
@@ -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,