419 lines
11 KiB
Vue
419 lines
11 KiB
Vue
<template>
|
||
<div class="system">
|
||
<!-- 角色列表头 -->
|
||
<div class="header">
|
||
<h4>角色列表</h4>
|
||
<el-button type="primary" @click="handleAddRole" v-auth="'roles_create'">新增角色</el-button>
|
||
</div>
|
||
<!-- 角色列表表格 -->
|
||
<RoleTable :table-data="roleTree" :columns="roleTableColumns" row-key="id">
|
||
<template #status="{ row }">
|
||
<el-switch
|
||
:model-value="row.status === 1"
|
||
:active-value="true"
|
||
:inactive-value="false"
|
||
active-text="启用"
|
||
inactive-text="禁用"
|
||
/>
|
||
</template>
|
||
<template #createTime="{ row }">
|
||
{{ row.created_at }}
|
||
</template>
|
||
<template #action="{ row }">
|
||
<el-button
|
||
link
|
||
type="primary"
|
||
size="small"
|
||
@click="handleEditRole(row)"
|
||
v-auth="'roles_edit'"
|
||
>
|
||
编辑
|
||
</el-button>
|
||
<el-button
|
||
link
|
||
type="primary"
|
||
size="small"
|
||
@click="handlePermission(row)"
|
||
v-auth="'roles_setPermission'"
|
||
>
|
||
设置权限
|
||
</el-button>
|
||
<el-button
|
||
link
|
||
type="danger"
|
||
size="small"
|
||
@click="handleDeleteRole(row)"
|
||
v-auth="'roles_del'"
|
||
>
|
||
删除
|
||
</el-button>
|
||
</template>
|
||
</RoleTable>
|
||
</div>
|
||
<!-- 角色新增/编辑弹窗 -->
|
||
<RoleDialog
|
||
:visible="dialogVisible"
|
||
:title="dialogTitle"
|
||
:type="dialogType"
|
||
@confirm="handleSubmit"
|
||
@cancel="handleCancel"
|
||
@close="handleClose"
|
||
:fullscreen="fullScreen"
|
||
>
|
||
<RoleForm
|
||
:form-data="roleForm"
|
||
:form-rules="roleFormRules"
|
||
:form-items="roleFormItemOptions"
|
||
ref="roleFormRef"
|
||
:options-map="roleFormOptionsMap"
|
||
:dialog-type="dialogType"
|
||
>
|
||
<template #permissions="{ formData }">
|
||
<div class="permission-group">
|
||
<div
|
||
v-for="(group, module) in groupedPermissions"
|
||
:key="module"
|
||
class="permission-module"
|
||
>
|
||
<!-- 点击事件的 checked 参数 -->
|
||
<el-checkbox
|
||
:model-value="getModuleCheckedState(module)"
|
||
:indeterminate="getModuleIndeterminateState(module)"
|
||
@change="
|
||
(checked: boolean | string | number) => handleModuleCheckChange(module, !!checked)
|
||
"
|
||
class="module-title"
|
||
>
|
||
{{ module }}
|
||
</el-checkbox>
|
||
<!-- 添加子权限 change 事件监听 -->
|
||
<el-checkbox-group v-model="formData.permissions" @change="handlePermissionChange">
|
||
<el-checkbox v-for="perm in group" :key="perm.id" :value="perm.id">
|
||
{{ perm.title }} ({{ perm.name }})
|
||
</el-checkbox>
|
||
</el-checkbox-group>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
</RoleForm>
|
||
</RoleDialog>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
|
||
defineOptions({
|
||
name: 'Role'
|
||
})
|
||
import type { FormInstance } from 'element-plus'
|
||
import { Plus } from '@element-plus/icons-vue'
|
||
|
||
// 组件配置
|
||
import RoleTable from '@/components/common/Table.vue'
|
||
import RoleDialog from '@/components/common/Dialog.vue'
|
||
import RoleForm from '@/components/common/Form.vue'
|
||
import { roleTableColumns, roleFormItem, permissionsFormItem } from './options'
|
||
import { rules } from './rules'
|
||
|
||
import {
|
||
getRoleApi,
|
||
createRoleApi,
|
||
editRoleApi,
|
||
deleteRoleApi,
|
||
getRolePermissionApi,
|
||
setRolePermissionApi,
|
||
} from '@/api/modules/system/role'
|
||
|
||
// 定义header配置
|
||
const roleTitle = ref('角色管理')
|
||
const roleHeaderButtons = [
|
||
{ label: '新增角色', type: 'primary' as const, icon: Plus, key: 'addRole' },
|
||
]
|
||
|
||
// 定义表格配置
|
||
const roleTree = ref<any[]>([])
|
||
|
||
// 定义弹窗配置
|
||
const dialogVisible = ref(false)
|
||
const dialogTitle = ref('')
|
||
const dialogType = ref('add')
|
||
const fullScreen = ref(false)
|
||
|
||
// 定义角色表单数据
|
||
const roleForm = ref({
|
||
name: '', // 角色名称
|
||
title: '', // 角色标题
|
||
permissions: [] as number[], // 角色权限
|
||
})
|
||
const roleFormRef = ref<FormInstance>()
|
||
// 表单验证规则
|
||
const roleFormRules = rules()
|
||
// 角色表单选项
|
||
const roleFormItemOptions = ref(roleFormItem)
|
||
// 角色表单选项映射
|
||
const roleFormOptionsMap = ref({
|
||
permissions: [] as any[],
|
||
})
|
||
|
||
//保存权限id
|
||
const permissionIds = ref('')
|
||
// 分组后的权限 { 模块名: [权限1,权限2...] }
|
||
const groupedPermissions = ref<Record<string, any[]>>({})
|
||
// 原始权限列表
|
||
const allPermissions = ref<any[]>([])
|
||
|
||
/**
|
||
@description: 新增角色
|
||
**/
|
||
const handleAddRole = () => {
|
||
console.log('新增角色', dialogType.value)
|
||
dialogVisible.value = true
|
||
dialogTitle.value = '新增角色'
|
||
handleDialogType(dialogType.value)
|
||
}
|
||
|
||
/**
|
||
@description: 角色数据处理
|
||
**/
|
||
// 处理角色状态,只保留 status=1 的角色
|
||
const filterRoles = (roleList: any[]) => {
|
||
const enabledRoles = roleList.filter((role) => role.status === 1)
|
||
return enabledRoles
|
||
}
|
||
|
||
// 获取角色列表
|
||
const fetchRoleList = async () => {
|
||
try {
|
||
const data = await getRoleApi()
|
||
roleTree.value = data
|
||
} catch (err) {
|
||
console.error('获取角色列表失败', err)
|
||
}
|
||
}
|
||
|
||
// 页面加载时获取菜单列表
|
||
onMounted(async () => {
|
||
await fetchRoleList()
|
||
})
|
||
|
||
/**
|
||
@description: 处理菜单编辑/删除/状态切换
|
||
**/
|
||
// 角色编辑
|
||
const handleEditRole = (row: any) => {
|
||
dialogVisible.value = true
|
||
dialogTitle.value = '编辑角色'
|
||
dialogType.value = 'edit'
|
||
handleDialogType(dialogType.value)
|
||
roleForm.value = {
|
||
...row,
|
||
id: row.id, // 角色id
|
||
}
|
||
console.log('编辑角色', dialogType.value)
|
||
}
|
||
// 角色删除
|
||
const handleDeleteRole = async (row: any) => {
|
||
try {
|
||
await deleteRoleApi({ id: row.id })
|
||
await fetchRoleList()
|
||
} catch (err) {
|
||
console.error('删除角色失败')
|
||
}
|
||
}
|
||
|
||
//区分新增和编辑角色表单选项
|
||
const handleDialogType = (type: string) => {
|
||
if (type === 'permissions') {
|
||
roleFormItemOptions.value = permissionsFormItem as any
|
||
fullScreen.value = true
|
||
console.log('权限弹窗', fullScreen.value)
|
||
} else {
|
||
roleFormItemOptions.value = roleFormItem as any
|
||
fullScreen.value = false
|
||
}
|
||
}
|
||
|
||
// 获取模块全选状态(实时计算)
|
||
const getModuleCheckedState = (module: string) => {
|
||
const group = groupedPermissions.value[module]
|
||
if (!group) return false
|
||
const groupIds = group.map((perm) => perm.id)
|
||
return groupIds.every((id) => roleForm.value.permissions.includes(id))
|
||
}
|
||
|
||
// 获取模块半选状态(实时计算)
|
||
const getModuleIndeterminateState = (module: string) => {
|
||
const group = groupedPermissions.value[module]
|
||
if (!group) return false
|
||
const groupIds = group.map((perm) => perm.id)
|
||
const selectedCount = groupIds.filter((id) => roleForm.value.permissions.includes(id)).length
|
||
return selectedCount > 0 && selectedCount < group.length
|
||
}
|
||
|
||
// 处理模块复选框点击(全选/取消全选)
|
||
const handleModuleCheckChange = (module: string, checked: boolean) => {
|
||
const group = groupedPermissions.value[module]
|
||
if (!group) return
|
||
const groupIds = group.map((perm) => perm.id)
|
||
|
||
if (checked) {
|
||
roleForm.value.permissions = [...new Set([...roleForm.value.permissions, ...groupIds])]
|
||
} else {
|
||
roleForm.value.permissions = roleForm.value.permissions.filter((id) => !groupIds.includes(id))
|
||
}
|
||
}
|
||
|
||
// 子权限变化时强制更新视图
|
||
const handlePermissionChange = () => {
|
||
roleForm.value = { ...roleForm.value }
|
||
}
|
||
|
||
// 按 module 分组权限
|
||
const groupPermissionsByModule = (permissions: any[]) => {
|
||
const grouped: Record<string, any[]> = {}
|
||
permissions.forEach((perm) => {
|
||
grouped[perm.module] = grouped[perm.module] || []
|
||
const item = {
|
||
...perm,
|
||
pId: permissions.find((p) => p.title === perm.module).id,
|
||
}
|
||
grouped[perm.module]!.push(item)
|
||
})
|
||
for (const key in grouped) {
|
||
console.log(key, grouped[key])
|
||
grouped[key] = grouped[key].filter((item) => item.pId !== item.id)
|
||
}
|
||
Object.values(grouped).forEach((group) => group.sort((a, b) => a.id - b.id))
|
||
return grouped
|
||
}
|
||
|
||
// 角色权限获取和设置
|
||
const handlePermission = async (row: any) => {
|
||
dialogVisible.value = true
|
||
dialogTitle.value = '设置角色权限'
|
||
dialogType.value = 'permissions'
|
||
handleDialogType(dialogType.value)
|
||
permissionIds.value = row.id
|
||
try {
|
||
const data = await getRolePermissionApi({ id: row.id })
|
||
allPermissions.value = data.all_permission_info.map((item) => ({
|
||
...item,
|
||
pId: data.all_permission_info.find((p) => p.title === item.module)?.id,
|
||
}))
|
||
groupedPermissions.value = groupPermissionsByModule(data.all_permission_info)
|
||
roleForm.value.permissions = data.permission_ids || []
|
||
console.log('分组后的权限', groupedPermissions.value)
|
||
} catch (err) {
|
||
console.error('获取角色权限失败', err)
|
||
}
|
||
}
|
||
|
||
/**
|
||
@description: 处理弹窗提交/取消/关闭事件
|
||
**/
|
||
const handleSubmit = async () => {
|
||
console.log(
|
||
'提交菜单表单',
|
||
roleForm.value.permissions,
|
||
groupedPermissions.value,
|
||
allPermissions.value,
|
||
) // 新增:打印选中的权限ID,便于调试
|
||
try {
|
||
await roleFormRef.value?.validate()
|
||
if (dialogType.value === 'add') {
|
||
const params = {
|
||
name: roleForm.value.name,
|
||
title: roleForm.value.title,
|
||
}
|
||
await createRoleApi(params)
|
||
await fetchRoleList()
|
||
} else if (dialogType.value === 'edit') {
|
||
await editRoleApi(roleForm.value)
|
||
await fetchRoleList()
|
||
} else {
|
||
let permissionIdList: any[] = [...roleForm.value.permissions]
|
||
for (let i = 0; i < allPermissions.value.length; i++) {
|
||
const flag = permissionIdList.includes(allPermissions.value[i]!.id)
|
||
if (flag) {
|
||
if (!permissionIdList.includes(allPermissions.value[i]!.pId))
|
||
permissionIdList.push(allPermissions.value[i]!.pId)
|
||
}
|
||
}
|
||
console.log('设置角色权限', permissionIdList.join(','))
|
||
|
||
await setRolePermissionApi({
|
||
id: permissionIds.value,
|
||
permission_ids: permissionIdList.join(','),
|
||
})
|
||
await fetchRoleList()
|
||
}
|
||
dialogVisible.value = false
|
||
} catch (err) {
|
||
console.log('表单验证失败')
|
||
return
|
||
}
|
||
}
|
||
|
||
// 角色弹窗取消
|
||
const handleCancel = () => {
|
||
dialogVisible.value = false
|
||
dialogType.value = 'add'
|
||
roleForm.value = {
|
||
name: '',
|
||
title: '',
|
||
permissions: [] as number[],
|
||
}
|
||
}
|
||
|
||
// 角色弹窗关闭
|
||
const handleClose = () => {
|
||
dialogVisible.value = false
|
||
dialogType.value = 'add'
|
||
roleForm.value = {
|
||
name: '',
|
||
title: '',
|
||
permissions: [] as number[],
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.permission-group {
|
||
width: 100%;
|
||
}
|
||
:deep(.el-form-item__content) {
|
||
margin-left: 0 !important;
|
||
}
|
||
|
||
.permission-module {
|
||
margin-bottom: 20px;
|
||
border: 1px solid #e5e7eb;
|
||
border-radius: 6px;
|
||
padding: 15px;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
}
|
||
|
||
.module-title {
|
||
margin: 0 0 10px 0;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
border-bottom: 1px solid #e5e7eb;
|
||
padding-bottom: 8px;
|
||
display: flex; // 修复:从 flex 改为 block,让复选框标题排版更合理
|
||
}
|
||
|
||
.permission-list {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 15px;
|
||
}
|
||
|
||
.el-checkbox-group {
|
||
label {
|
||
margin-right: 15px;
|
||
}
|
||
}
|
||
</style>
|