完善项目级权限与项目管理入口

- 新增项目成员候选用户接口,避免 PM 读取全局用户列表
- 按项目角色和权限矩阵控制项目管理、成员、中心与审计入口
- 合并侧边栏管理后台入口,统一从项目管理进入成员等模块
- 加强成员管理安全约束,禁止 PM 修改自己、系统管理员或更高权限角色
- 修复多项目角色缓存串用问题,并补充前后端回归测试
This commit is contained in:
Cheng Zhou
2026-05-13 14:16:15 +08:00
parent ab1975d3c6
commit a17f4cc522
21 changed files with 452 additions and 134 deletions
+2 -25
View File
@@ -17,11 +17,11 @@
<span>{{ TEXT.menu.workbench }}</span>
</el-menu-item>
<el-menu-item-group v-if="isAdmin" class="menu-group">
<el-menu-item-group v-if="auth.user" class="menu-group">
<template #title>
<span class="menu-divider">{{ TEXT.menu.admin }}</span>
</template>
<el-menu-item index="/admin/users">
<el-menu-item v-if="isAdmin" index="/admin/users">
<el-icon><User /></el-icon>
<span>{{ TEXT.menu.accountManagement }}</span>
</el-menu-item>
@@ -35,24 +35,6 @@
</el-menu-item>
</el-menu-item-group>
<el-menu-item-group v-if="canAccessPmAdminBackend" class="menu-group">
<template #title>
<span class="menu-divider">{{ TEXT.menu.admin }}</span>
</template>
<el-menu-item v-if="canAccessPmAdminModule('project_members')" :index="`/admin/projects/${study.currentStudy?.id}/members`">
<el-icon><User /></el-icon>
<span>{{ TEXT.modules.adminProjectMembers.memberLabel }}</span>
</el-menu-item>
<el-menu-item v-if="canAccessPmAdminModule('sites')" :index="`/admin/projects/${study.currentStudy?.id}/sites`">
<el-icon><Suitcase /></el-icon>
<span>{{ TEXT.modules.adminSites.title }}</span>
</el-menu-item>
<el-menu-item v-if="canAccessPmAdminModule('audit_export')" index="/admin/audit-logs">
<el-icon><Document /></el-icon>
<span>{{ TEXT.menu.auditLogs }}</span>
</el-menu-item>
</el-menu-item-group>
<el-menu-item-group v-if="study.currentStudy && hasAnyProjectModuleAccess" class="menu-group">
<template #title>
<span class="menu-divider">{{ TEXT.menu.currentProject }}</span>
@@ -244,11 +226,6 @@ const route = useRoute();
const isAdmin = computed(() => auth.user?.role === "ADMIN");
const isCollapsed = ref(localStorage.getItem("ctms_sidebar_collapsed") === "1");
const projectRole = computed(() => study.currentStudyRole || (study.currentStudy as any)?.role_in_study || "");
const canAccessPmAdminModule = (module: string) =>
!isAdmin.value && projectRole.value === "PM" && !!study.currentPermissions?.roles?.PM?.[module]?.read;
const canAccessPmAdminBackend = computed(() =>
!!study.currentStudy && ["project_members", "sites", "audit_export"].some((module) => canAccessPmAdminModule(module))
);
const canAccessProjectPath = (path: string) =>
hasProjectPermission(study.currentPermissions?.roles, projectRole.value, getProjectRoutePermission(path), isAdmin.value);
const canAccessAnyProjectPath = (paths: string[]) => paths.some((path) => canAccessProjectPath(path));