权限管理:接入项目级权限矩阵
新增项目级角色权限矩阵,覆盖 PM、CRA、PV、IMP、QA 等项目角色,并通过迁移表持久化各业务模块的读写权限。 后端将参与者、合同费用、物资、启动、里程碑、风险问题、监查稽查、FAQ、共享库、文件版本等接口接入矩阵校验,修复审计日志导出权限和登录 502 的依赖导入问题。 前端新增权限管理页面和项目路由权限映射,按矩阵控制导航显示、直接访问拦截、操作按钮启停,并限制管理后台仅 admin 和授权 PM 可进入。 补充后端权限归一化与接口静态测试、前端路由/权限工具/权限管理页面/工作台等回归测试。
This commit is contained in:
@@ -167,6 +167,7 @@ import { useRouter } from "vue-router";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { ArrowDown } from "@element-plus/icons-vue";
|
||||
import { createAuditEvent, fetchAuditLogs } from "../../api/auditLogs";
|
||||
import { fetchProjectRolePermissions } from "../../api/projectPermissions";
|
||||
import { fetchUsers } from "../../api/users";
|
||||
import { listMembers } from "../../api/members";
|
||||
import { auditDict, normalizeAuditEvent } from "../../audit";
|
||||
@@ -187,6 +188,7 @@ const exportLoading = ref(false);
|
||||
const logs = ref<any[]>([]);
|
||||
const users = ref<any[]>([]);
|
||||
const allLogs = ref<any[]>([]);
|
||||
const permissionMatrix = ref<any | null>(null);
|
||||
const page = ref(1);
|
||||
const pageSize = ref(20);
|
||||
const total = ref(0);
|
||||
@@ -212,8 +214,14 @@ const resolveUserDisplayName = (u: any): string => {
|
||||
const userOptions = computed(() => users.value.map((u: any) => ({ label: resolveUserDisplayName(u), value: u.id })));
|
||||
const isAdmin = computed(() => isSystemAdmin(auth.user));
|
||||
const projectRole = computed(() => getProjectRole(study.currentStudy, study.currentStudyRole));
|
||||
const canProjectExport = computed(() => !!study.currentStudy && isAdmin.value);
|
||||
const canAccessAuditLogs = computed(() => isAdmin.value || projectRole.value === "PM");
|
||||
const canProjectExport = computed(() => {
|
||||
if (isAdmin.value) return true;
|
||||
return projectRole.value === "PM" && !!permissionMatrix.value?.roles?.PM?.audit_export?.read;
|
||||
});
|
||||
const canAccessAuditLogs = computed(() => {
|
||||
if (isAdmin.value) return true;
|
||||
return projectRole.value === "PM" && !!permissionMatrix.value?.roles?.PM?.audit_export?.read;
|
||||
});
|
||||
|
||||
const ensureAccess = () => {
|
||||
if (!canAccessAuditLogs.value) {
|
||||
@@ -221,6 +229,12 @@ const ensureAccess = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const loadPermissionMatrix = async () => {
|
||||
if (!study.currentStudy) return;
|
||||
const { data } = await fetchProjectRolePermissions(study.currentStudy.id);
|
||||
permissionMatrix.value = data;
|
||||
};
|
||||
|
||||
const loadUsers = async () => {
|
||||
try {
|
||||
if (isAdmin.value) {
|
||||
@@ -244,6 +258,9 @@ const loadLogs = async () => {
|
||||
if (!study.currentStudy) return;
|
||||
loading.value = true;
|
||||
try {
|
||||
if (!permissionMatrix.value) {
|
||||
await loadPermissionMatrix();
|
||||
}
|
||||
const batchLimit = 500;
|
||||
let skip = 0;
|
||||
const allItems: any[] = [];
|
||||
@@ -418,6 +435,7 @@ onMounted(async () => {
|
||||
if (!auth.user && auth.token) {
|
||||
await auth.fetchMe().catch(() => {});
|
||||
}
|
||||
await loadPermissionMatrix().catch(() => {});
|
||||
ensureAccess();
|
||||
await loadUsers();
|
||||
await loadLogs();
|
||||
|
||||
Reference in New Issue
Block a user