You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

289 lines
7.1 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div class="page-container fade-in-up">
<div class="page-header">
<h2 class="page-title">权限管理</h2>
<p class="page-subtitle">管理各角色访问权限保障系统安全</p>
</div>
<!-- 角色列表 -->
<div class="roles-cards">
<div
v-for="role in roles"
:key="role.id"
class="role-card"
:class="{ active: activeRole === role.id }"
@click="activeRole = role.id"
>
<div class="role-icon" :style="{ background: role.color }">
<el-icon :size="20">
<component :is="role.icon" />
</el-icon>
</div>
<div class="role-info">
<div class="role-name">{{ role.name }}</div>
<div class="role-count">{{ role.userCount }} </div>
</div>
</div>
</div>
<!-- 权限矩阵 -->
<div class="perm-matrix-card">
<div class="matrix-header">
<h3>权限分配矩阵</h3>
<el-tag type="success" size="small" effect="plain">当前角色: {{ currentRoleName }}</el-tag>
</div>
<div class="matrix-table">
<table>
<thead>
<tr>
<th class="perm-label">功能模块</th>
<th v-for="perm in permissions" :key="perm.key" class="perm-col">{{ perm.label }}</th>
</tr>
</thead>
<tbody>
<tr v-for="module in modules" :key="module.key">
<td class="perm-label">{{ module.label }}</td>
<td v-for="perm in permissions" :key="perm.key" class="perm-col">
<el-checkbox
v-model="matrix[activeRole][module.key][perm.key]"
:disabled="perm.key === 'view'"
@change="handlePermChange"
/>
</td>
</tr>
</tbody>
</table>
</div>
<!-- 权限说明 -->
<div class="perm-legend">
<div class="legend-item">
<el-icon :size="14" color="#bfbfbf"><InfoFilled /></el-icon>
<span>查看权限为基本权限,默认勾选;取消需谨慎。</span>
</div>
</div>
</div>
<!-- 操作按钮 -->
<div class="save-bar">
<el-button type="primary" size="large" :icon="Check" @click="savePermissions">保存权限配置</el-button>
<el-button size="large" @click="resetPermissions"></el-button>
</div>
</div>
</template>
<script setup>
import { ref, computed, reactive } from 'vue'
import { ElMessage } from 'element-plus'
const activeRole = ref('admin')
const roles = ref([
{ id: 'admin', name: '管理员', icon: 'UserFilled', color: 'linear-gradient(135deg, #52c41a, #73d13d)', userCount: 3 },
{ id: 'staff', name: '教务员', icon: 'Avatar', color: 'linear-gradient(135deg, #1890ff, #40a9ff)', userCount: 8 },
{ id: 'teacher', name: '教师', icon: 'User', color: 'linear-gradient(135deg, #722ed1, #9254de)', userCount: 25 }
])
const modules = ref([
{ key: 'dashboard', label: '首页' },
{ key: 'behavior', label: '课堂行为分析' },
{ key: 'history', label: '历史记录查询' },
{ key: 'bigscreen', label: '数据展示大屏' },
{ key: 'settings', label: '系统设置' }
])
const permissions = ref([
{ key: 'view', label: '查看' },
{ key: 'edit', label: '编辑' },
{ key: 'export', label: '导出' },
{ key: 'delete', label: '删除' }
])
// 初始化权限矩阵
const matrix = reactive({
admin: {
dashboard: { view: true, edit: true, export: true, delete: true },
behavior: { view: true, edit: true, export: true, delete: true },
history: { view: true, edit: true, export: true, delete: true },
bigscreen: { view: true, edit: true, export: true, delete: true },
settings: { view: true, edit: true, export: true, delete: true }
},
staff: {
dashboard: { view: true, edit: false, export: true, delete: false },
behavior: { view: false, edit: false, export: false, delete: false },
history: { view: true, edit: false, export: true, delete: false },
bigscreen: { view: false, edit: false, export: false, delete: false },
settings: { view: false, edit: false, export: false, delete: false }
},
teacher: {
dashboard: { view: true, edit: false, export: true, delete: false },
behavior: { view: true, edit: false, export: false, delete: false },
history: { view: true, edit: false, export: true, delete: false },
bigscreen: { view: false, edit: false, export: false, delete: false },
settings: { view: false, edit: false, export: false, delete: false }
}
})
const currentRoleName = computed(() => {
return roles.value.find(r => r.id === activeRole.value)?.name || ''
})
const handlePermChange = () => {
// 联动逻辑取消view时自动取消所有子权限
}
const savePermissions = () => {
ElMessage.success('权限配置保存成功,角色权限已立即更新')
}
const resetPermissions = () => {
ElMessage.info('已恢复默认权限配置')
}
</script>
<style lang="scss" scoped>
.roles-cards {
display: flex;
gap: 16px;
margin-bottom: 20px;
}
.role-card {
flex: 1;
background: #ffffff;
border-radius: 8px;
padding: 20px;
display: flex;
align-items: center;
gap: 16px;
cursor: pointer;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
border: 2px solid transparent;
transition: all 0.3s ease;
&:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
&.active {
border-color: #52c41a;
box-shadow: 0 4px 16px rgba(82, 196, 26, 0.15);
}
}
.role-icon {
width: 48px;
height: 48px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
color: #ffffff;
flex-shrink: 0;
}
.role-info {
.role-name {
font-size: 16px;
font-weight: 600;
color: #262626;
margin-bottom: 4px;
}
.role-count {
font-size: 12px;
color: #bfbfbf;
}
}
.perm-matrix-card {
background: #ffffff;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
margin-bottom: 20px;
}
.matrix-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
h3 {
font-size: 16px;
font-weight: 600;
color: #262626;
}
}
.matrix-table {
overflow-x: auto;
table {
width: 100%;
border-collapse: collapse;
}
thead th {
padding: 12px 16px;
text-align: center;
font-size: 13px;
font-weight: 600;
color: #262626;
border-bottom: 2px solid #f0f0f0;
background: #fafafa;
}
tbody td {
padding: 14px 16px;
text-align: center;
border-bottom: 1px solid #f5f5f5;
transition: background 0.15s ease;
}
tbody tr:hover td {
background: #fafafa;
}
}
.perm-label {
text-align: left !important;
font-size: 14px;
color: #525252;
font-weight: 500;
min-width: 140px;
}
.perm-col {
min-width: 80px;
}
.perm-legend {
margin-top: 16px;
padding: 10px 16px;
background: #f5f7fa;
border-radius: 6px;
.legend-item {
display: flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: #8c8c8c;
}
}
.save-bar {
display: flex;
gap: 12px;
justify-content: flex-end;
.el-button {
border-radius: 8px;
min-width: 130px;
}
}
</style>