权限监控与管理界面全面美化

重新设计权限系统所有 UI 组件的视觉风格,统一配色、圆角、阴影和交互动效:
- 实时概览:统计卡片加图标和渐变色条,健康评分改为环形进度,告警改为卡片式
- 趋势分析:图表卡片加彩色图标标识,ECharts 配色升级为渐变面积填充
- 访问日志:指标卡片带图标,日志审计改为卡片式入口,IP排行前三高亮
- IP属地:工具栏重设计,排行列表前三渐变高亮,指标卡片统一新风格
- 系统级权限:从 el-table 改为自定义卡片列表,模块块独立圆角卡片
- 项目权限配置:空状态引导优化,成员表格加头像,工具栏加背景容器
- 角色概览卡片:加进度条可视化,hover 微动效
- 接口权限矩阵:工具栏分离布局,表格圆角包裹
- 角色管理抽屉:侧边栏选中态渐变,操作行 hover 高亮

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Cheng Zhou
2026-05-20 14:36:35 +08:00
parent e95eeed90e
commit 6cefa620e4
68 changed files with 6927 additions and 984 deletions
@@ -1,41 +1,40 @@
<template>
<div class="api-permissions">
<!-- 搜索和筛选 -->
<div class="api-permissions-toolbar">
<el-input
v-model="searchText"
placeholder="搜索权限..."
clearable
style="width: 250px"
>
<template #prefix>
<el-icon><Search /></el-icon>
</template>
</el-input>
<el-select v-model="filterModule" placeholder="筛选模块" clearable style="width: 150px">
<el-option label="全部模块" value="" />
<el-option
v-for="module in uniqueModules"
:key="module"
:label="moduleLabel(module)"
:value="module"
<div class="toolbar-left">
<span class="toolbar-title">接口权限矩阵</span>
<span class="toolbar-desc">为各角色配置 API 接口的访问权限</span>
</div>
<div class="toolbar-filters">
<el-input
v-model="searchText"
placeholder="搜索权限..."
clearable
style="width: 220px"
:prefix-icon="Search"
/>
</el-select>
<el-select v-model="filterAction" placeholder="筛选操作" clearable style="width: 120px">
<el-option label="全部操作" value="" />
<el-option label="创建" value="create" />
<el-option label="读取" value="read" />
<el-option label="更新" value="update" />
<el-option label="删除" value="delete" />
<el-option label="导出" value="export" />
</el-select>
<el-select v-model="filterModule" placeholder="筛选模块" clearable style="width: 150px">
<el-option label="全部模块" value="" />
<el-option
v-for="module in uniqueModules"
:key="module"
:label="moduleLabel(module)"
:value="module"
/>
</el-select>
<el-select v-model="filterAction" placeholder="筛选操作" clearable style="width: 120px">
<el-option label="全部操作" value="" />
<el-option label="创建" value="create" />
<el-option label="读取" value="read" />
<el-option label="更新" value="update" />
<el-option label="删除" value="delete" />
<el-option label="导出" value="export" />
</el-select>
</div>
</div>
<!-- 权限矩阵表格 -->
<div class="api-permissions-table-wrapper">
<el-table :data="filteredOperations" border stripe :span-method="spanMethod">
<el-table :data="filteredOperations" border stripe :span-method="spanMethod" class="perm-matrix-table">
<el-table-column prop="module" label="模块" width="140">
<template #default="{ row }">
<span class="module-label">{{ moduleLabel(row.module) }}</span>
@@ -45,7 +44,7 @@
<el-table-column prop="operation_key" label="权限操作" width="200">
<template #default="{ row }">
<div class="operation-cell">
<el-tag :type="getActionType(row)" size="small">
<el-tag :type="getActionType(row)" size="small" class="action-tag">
{{ getActionLabel(row) }}
</el-tag>
<span class="operation-name">{{ row.description || row.operation_key }}</span>
@@ -78,6 +77,7 @@ import { Search } from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";
import type { ApiEndpointPermissionsResponse } from "@/types/api";
import { fetchApiOperations } from "@/api/projectPermissions";
import { isApiPermissionAllowed } from "@/utils/apiPermissionValue";
interface Operation {
operation_key: string;
@@ -195,9 +195,7 @@ const spanMethod = ({ row, rowIndex, columnIndex }: { row: Operation; rowIndex:
// 检查操作是否允许
const isOperationAllowed = (operation_key: string, role: string): boolean => {
if (!props.matrix || !props.matrix[role]) return false;
const perm = props.matrix[role][operation_key];
if (!perm) return false;
return typeof perm === "boolean" ? perm : perm.allowed;
return isApiPermissionAllowed(props.matrix[role][operation_key]);
};
// 从 operation_key 提取操作类型
@@ -258,38 +256,82 @@ const onPermissionChange = (operation_key: string, role: string, allowed: boolea
onMounted(() => {
loadOperations();
});
defineExpose({ searchText });
</script>
<style scoped lang="scss">
<style scoped>
.api-permissions {
padding: 20px 0;
}
.api-permissions-toolbar {
display: flex;
gap: 15px;
margin-bottom: 20px;
align-items: center;
justify-content: space-between;
gap: 16px;
margin-bottom: 18px;
padding: 14px 18px;
background: #fff;
border: 1px solid #e2e8f0;
border-radius: 14px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.03);
}
.toolbar-left {
display: flex;
flex-direction: column;
gap: 2px;
}
.toolbar-title {
font-size: 15px;
font-weight: 600;
color: #1a2332;
}
.toolbar-desc {
font-size: 12px;
color: #64748b;
}
.toolbar-filters {
display: flex;
align-items: center;
gap: 10px;
}
.api-permissions-table-wrapper {
overflow-x: auto;
border-radius: 12px;
border: 1px solid #e2e8f0;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.03);
}
.perm-matrix-table {
width: 100%;
}
.module-label {
font-weight: 600;
font-size: 13px;
color: #303133;
color: #1a2332;
}
.operation-cell {
display: flex;
align-items: center;
gap: 8px;
}
.operation-name {
font-size: 13px;
color: #606266;
}
.action-tag {
flex-shrink: 0;
min-width: 40px;
text-align: center;
}
.operation-name {
font-size: 13px;
color: #475569;
}
</style>