统一项目权限读取模型
1、合并列表与详情读取权限,统一使用 subjects:read、project_members:read、monitoring_issues:read 等业务读取 key。 2、增加历史读取权限 key 的兼容映射,确保存量项目权限覆盖值不会丢失。 3、同步前端权限工具、路由权限与权限管理页面,避免继续引用已合并的旧权限 key。 4、补充项目角色启停保护与抽屉未保存变更守卫,防止停用 PM 或仍有关联成员的角色。
This commit is contained in:
@@ -237,24 +237,24 @@ describe("ApiEndpointPermissions.vue", () => {
|
||||
});
|
||||
|
||||
(wrapper.vm as any).operations = [
|
||||
{ operation_key: "subject_aes:list", module: "subjects", action: "read", description: "查询参与者AE列表", default_roles: [] },
|
||||
{ operation_key: "subject_aes:read", module: "subjects", action: "read", description: "查询参与者AE列表", default_roles: [] },
|
||||
{ operation_key: "subject_pds:list", module: "subjects", action: "read", description: "查询参与者PD列表", default_roles: [] },
|
||||
{ operation_key: "monitoring_issues:list", module: "risk_issues", action: "read", description: "查询监查访视问题列表", default_roles: [] },
|
||||
{ operation_key: "monitoring_issues:read", module: "risk_issues", action: "read", description: "查询监查访视问题列表", default_roles: [] },
|
||||
];
|
||||
|
||||
const riskRows = (wrapper.vm as any).filteredOperations.filter((operation: any) => operation.module === "risk_issues");
|
||||
|
||||
expect(riskRows.map((operation: any) => operation.operation_key)).toEqual([
|
||||
"subject_aes:list",
|
||||
"subject_aes:read",
|
||||
"subject_pds:list",
|
||||
"monitoring_issues:list",
|
||||
"monitoring_issues:read",
|
||||
]);
|
||||
expect(riskRows.map((operation: any) => (wrapper.vm as any).getOperationSection(operation))).toEqual([
|
||||
"AE/SAE",
|
||||
"PD",
|
||||
"监查访视问题",
|
||||
]);
|
||||
expect((wrapper.vm as any).filteredOperations.filter((operation: any) => operation.operation_key === "subject_aes:list")).toHaveLength(2);
|
||||
expect((wrapper.vm as any).filteredOperations.filter((operation: any) => operation.operation_key === "subject_aes:read")).toHaveLength(2);
|
||||
expect((wrapper.vm as any).filteredOperations.filter((operation: any) => operation.operation_key === "subject_pds:list")).toHaveLength(2);
|
||||
});
|
||||
|
||||
@@ -309,6 +309,13 @@ describe("ApiEndpointPermissions.vue", () => {
|
||||
description: "查询药品流向详情",
|
||||
default_roles: [],
|
||||
})).toBe("药品流向管理");
|
||||
expect((wrapper.vm as any).getOperationSection({
|
||||
operation_key: "drug_shipments_attachments:delete",
|
||||
module: "materials",
|
||||
action: "write",
|
||||
description: "删除药物发货附件",
|
||||
default_roles: [],
|
||||
})).toBe("药品流向管理");
|
||||
expect((wrapper.vm as any).getOperationSection({
|
||||
operation_key: "material_equipments:read",
|
||||
module: "materials",
|
||||
@@ -316,9 +323,16 @@ describe("ApiEndpointPermissions.vue", () => {
|
||||
description: "查询设备详情",
|
||||
default_roles: [],
|
||||
})).toBe("设备管理");
|
||||
expect((wrapper.vm as any).getOperationSection({
|
||||
operation_key: "material_equipments_attachments:delete",
|
||||
module: "materials",
|
||||
action: "write",
|
||||
description: "删除物资设备附件",
|
||||
default_roles: [],
|
||||
})).toBe("设备管理");
|
||||
});
|
||||
|
||||
it("groups startup ethics permissions with visible business names", () => {
|
||||
it("groups startup ethics permissions into initiation and ethics sections", () => {
|
||||
const wrapper = mount(ApiEndpointPermissions, {
|
||||
props: {
|
||||
project: { id: "test-id", name: "Test Project" },
|
||||
@@ -338,14 +352,28 @@ describe("ApiEndpointPermissions.vue", () => {
|
||||
action: "read",
|
||||
description: "查询立项记录详情",
|
||||
default_roles: [],
|
||||
})).toBe("立项记录");
|
||||
})).toBe("立项");
|
||||
expect((wrapper.vm as any).getOperationSection({
|
||||
operation_key: "startup_initiation_attachments:delete",
|
||||
module: "startup_ethics",
|
||||
action: "write",
|
||||
description: "删除立项记录附件",
|
||||
default_roles: [],
|
||||
})).toBe("立项");
|
||||
expect((wrapper.vm as any).getOperationSection({
|
||||
operation_key: "startup_ethics:read",
|
||||
module: "startup_ethics",
|
||||
action: "read",
|
||||
description: "查询伦理记录详情",
|
||||
default_roles: [],
|
||||
})).toBe("伦理记录");
|
||||
})).toBe("伦理");
|
||||
expect((wrapper.vm as any).getOperationSection({
|
||||
operation_key: "startup_ethics_attachments:delete",
|
||||
module: "startup_ethics",
|
||||
action: "write",
|
||||
description: "删除伦理记录附件",
|
||||
default_roles: [],
|
||||
})).toBe("伦理");
|
||||
});
|
||||
|
||||
it("filters endpoints by search text", async () => {
|
||||
|
||||
@@ -340,9 +340,13 @@ const SECTION_LABELS: Record<string, string> = {
|
||||
monitoring_issues: "监查访视问题",
|
||||
project_milestones: "项目里程碑",
|
||||
drug_shipments: "药品流向管理",
|
||||
drug_shipments_attachments: "药品流向管理",
|
||||
material_equipments: "设备管理",
|
||||
startup_initiation: "立项记录",
|
||||
startup_ethics: "伦理记录",
|
||||
material_equipments_attachments: "设备管理",
|
||||
startup_initiation: "立项",
|
||||
startup_initiation_attachments: "立项",
|
||||
startup_ethics: "伦理",
|
||||
startup_ethics_attachments: "伦理",
|
||||
precautions: "注意事项",
|
||||
precautions_attachments: "注意事项",
|
||||
faq: "医学咨询/FAQ",
|
||||
|
||||
Reference in New Issue
Block a user