权限管理:接入项目级权限矩阵
新增项目级角色权限矩阵,覆盖 PM、CRA、PV、IMP、QA 等项目角色,并通过迁移表持久化各业务模块的读写权限。 后端将参与者、合同费用、物资、启动、里程碑、风险问题、监查稽查、FAQ、共享库、文件版本等接口接入矩阵校验,修复审计日志导出权限和登录 502 的依赖导入问题。 前端新增权限管理页面和项目路由权限映射,按矩阵控制导航显示、直接访问拦截、操作按钮启停,并限制管理后台仅 admin 和授权 PM 可进入。 补充后端权限归一化与接口静态测试、前端路由/权限工具/权限管理页面/工作台等回归测试。
This commit is contained in:
@@ -30,12 +30,15 @@
|
||||
<el-tag v-else type="success" effect="plain" round>未锁定</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="TEXT.common.labels.actions" width="240" align="center">
|
||||
<el-table-column :label="TEXT.common.labels.actions" width="176" align="center">
|
||||
<template #default="scope">
|
||||
<div class="action-row">
|
||||
<el-tooltip :content="TEXT.modules.adminProjects.members" placement="top">
|
||||
<el-button link type="primary" :icon="User" class="action-btn" @click="goMembers(scope.row)" />
|
||||
</el-tooltip>
|
||||
<el-tooltip content="权限管理" placement="top">
|
||||
<el-button link type="primary" :icon="Key" class="action-btn" @click="goPermissions(scope.row)" />
|
||||
</el-tooltip>
|
||||
<el-tooltip :content="TEXT.modules.adminProjects.sites" placement="top">
|
||||
<el-button link type="primary" :icon="OfficeBuilding" class="action-btn" @click="goSites(scope.row)" />
|
||||
</el-tooltip>
|
||||
@@ -68,7 +71,7 @@
|
||||
import { onMounted, ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { User, OfficeBuilding, ArrowRight, Delete, Lock } from "@element-plus/icons-vue";
|
||||
import { User, OfficeBuilding, ArrowRight, Delete, Lock, Key } from "@element-plus/icons-vue";
|
||||
import { fetchStudies, deleteStudy, lockStudy } from "../../api/studies";
|
||||
import type { Study } from "../../types/api";
|
||||
import ProjectForm from "./ProjectForm.vue";
|
||||
@@ -108,6 +111,10 @@ const goSites = (row: Study) => {
|
||||
router.push(`/admin/projects/${row.id}/sites`);
|
||||
};
|
||||
|
||||
const goPermissions = (row: Study) => {
|
||||
router.push(`/admin/projects/${row.id}/permissions`);
|
||||
};
|
||||
|
||||
const handleDelete = async (study: Study) => {
|
||||
try {
|
||||
// 第一次确认
|
||||
@@ -197,8 +204,9 @@ const handleLockToggle = async (study: Study) => {
|
||||
}
|
||||
};
|
||||
|
||||
const enterStudy = (row: Study) => {
|
||||
const enterStudy = async (row: Study) => {
|
||||
studyStore.setCurrentStudy(row);
|
||||
await studyStore.loadCurrentStudyPermissions().catch(() => {});
|
||||
router.push("/project/overview");
|
||||
};
|
||||
|
||||
@@ -244,7 +252,8 @@ onMounted(() => {
|
||||
.action-row {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
gap: 4px;
|
||||
justify-content: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@@ -263,20 +272,27 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
font-size: 18px;
|
||||
padding: 4px;
|
||||
margin: 0 2px;
|
||||
transition: all 0.3s;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
min-height: 28px;
|
||||
font-size: 16px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.2s, color 0.2s, transform 0.2s;
|
||||
}
|
||||
|
||||
.action-row :deep(.el-button + .el-button) {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.action-btn:hover {
|
||||
transform: scale(1.1);
|
||||
transform: translateY(-1px);
|
||||
background-color: #f3f4f6;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.enter-btn {
|
||||
font-size: 18px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user