foreign-admin-ui/src/views/system/role/index.vue

419 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>