feat(perm/frontend): PM 视角的权限管理界面与个人有效权限接入

- store/study 与 router 改为读取 /api-permissions/me 拉取当前用户在
  当前项目的有效权限,菜单与路由守卫据此判定,并在 PM 项目缺省时
  主动 ensureDefaultPmStudy。
- api/projectPermissions 暴露 fetchMyApiEndpointPermissions,并允许
  调用方关闭统一错误提示,便于在批量项目权限拉取场景下静默失败。
- 项目管理:Projects 页根据每个项目的有效权限决定项目入口的可点击
  状态,缺权限时禁用项目名跳转;ProjectDetail 据 setup_config 写权限
  渲染保存/回填/清空/发布按钮,并在无读取权限时提示并退出页面。
- 权限管理:PermissionManagement 切换为按角色提交,Admin 视角才能
  编辑 PM 行;按系统模块美化系统级权限展示并标注 PM 可访问项;项目
  成员表的角色下拉受 PM 等级约束,自定义角色入口下线。
- 监控:PermissionMonitoring/PermissionAccessLogs 增加 isAdmin 与
  showSecurityLog 入参,仅 ADMIN 才能看到底层安全日志与统计。
- ApiEndpointPermissions 表格根据当前用户角色禁用不可写行,避免
  误操作 PM 行;MODULE_LABELS 增加 setup_config 的中文展示。
- 测试同步覆盖以上行为:新版 router/Layout/Projects/PermissionManagement
  /PermissionAccessLogs/PermissionMonitoring/PermissionIpLocations 等
  组件均补足检测,并按需为相关组件提供 pinia + localStorage stub。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Cheng Zhou
2026-05-25 12:38:54 +08:00
parent 747dd55225
commit 934d114a29
22 changed files with 501 additions and 145 deletions
@@ -62,6 +62,7 @@
<template #default="{ row }">
<el-checkbox
:model-value="isOperationAllowed(row.operation_key, role)"
:disabled="!isRoleEditable(role)"
@change="(val: boolean) => onPermissionChange(row.operation_key, role, val)"
/>
</template>
@@ -78,6 +79,8 @@ import { ElMessage } from "element-plus";
import type { ApiEndpointPermissionsResponse } from "@/types/api";
import { fetchApiOperations } from "@/api/projectPermissions";
import { isApiPermissionAllowed } from "@/utils/apiPermissionValue";
import { useAuthStore } from "@/store/auth";
import { isSystemAdmin } from "@/utils/roles";
interface Operation {
operation_key: string;
@@ -99,6 +102,14 @@ interface Emits {
const props = defineProps<Props>();
const emit = defineEmits<Emits>();
const auth = useAuthStore();
const isAdmin = computed(() => isSystemAdmin(auth.user));
const isRoleEditable = (role: string) => {
if (role === "ADMIN") return false;
if (isAdmin.value) return true;
return role !== "PM";
};
const searchText = ref("");
const filterModule = ref("");
const filterAction = ref("");
@@ -112,6 +123,7 @@ const MODULE_LABELS: Record<string, string> = {
project_members: "项目成员",
project_milestones: "项目里程碑",
project_overview: "项目总览",
setup_config: "立项配置",
fees: "合同费用",
materials: "物资管理",
material_equipments: "物资设备",