Solon + EasyQuery + ElementPlus 实现后台管理系统之 06-权限菜单与角色授权
AI 摘要
本文基于 Solon + EasyQuery + ElementPlus 实现后台管理系统的权限菜单与角色授权功能。后端提供权限的增删改查接口,支持模糊查询、非必填字段、子权限校验等逻辑;前端通过扁平数据转树形工具渲染 ElementPlus 树表,并在角色列表中集成授权弹窗,支持回显与批量更新角色权限,默认角色禁止操作。
权限菜单
后端 API
核心注意事项:
- 权限管理的后端 API,提供基础增删改查方法。
- 获取权限列表:可以根据权限名称、权限标识模糊查询,返回全量列表,前端自行根据全量列表解析得到树形结构数据进行渲染。
- 添加权限/修改权限:权限路由路径、权限路由组件非必填项。
- 删除权限:删除时权限 ID 下是否有子权限,如有禁止删除。
AI 生成控制器提示词:
基于Solon+EasyQuery,生成权限控制器,要求如下:
1、编码风格,严格参考部门控制器DeptController。
1、获取权限列表:可以根据权限名称name、权限标识identifier模糊查询,返回全量列表,不需要分页。
2、添加权限:前端提交父级权限ID-parentId、权限名称name、权限标识identifier、权限路由路径path(非必填)、权限路由组件component(非必填)、权限类型type、排序ID-sortId、权限状态status,使用注解进行数据校验,校验后插入数据到数据库。
4、修改权限:流程同添加权限。
5、删除权限:删除时权限ID下是否有子权限,如有禁止删除。编写权限控制器(cn.duozai.sadmin.controller.PermsController),提供基础方法:
/**
* 权限控制器
* @visduo
*/
@Mapping("/perms")
@Controller
public class PermsController {
@Db
EasyEntityQuery easyEntityQuery;
/**
* 获取权限列表
* @visduo
*
* @param name 查询条件-权限名称
* @param identifier 查询条件-权限标识
* @return 权限列表分页结果
*/
@Get
@Mapping("/list")
public ResponseResult list(@Param(required = false) String name,
@Param(required = false) String identifier) {
List<PermsEntity> permsList = easyEntityQuery.queryable(PermsEntity.class)
.where(p -> {
// 权限名称不为空时对权限名称进行模糊查询
p.name().like(StrUtil.isNotBlank(name), name);
// 权限标识不为空时对权限标识进行模糊查询
p.identifier().like(StrUtil.isNotBlank(identifier), identifier);
})
.orderBy(p -> {
// 根据排序ID进行排序,越小越靠前
p.sortId().asc();
})
// 查询全量列表数据
.toList();
return ResponseResult.success("查询成功", permsList);
}
/**
* 添加权限
* @visduo
*
* @param parentId 父级权限ID
* @param name 权限名称
* @param identifier 权限标识
* @param path 权限路由路径
* @param component 权限路由组件
* @param type 权限类型
* @param sortId 排序ID
* @param status 权限状态
* @return 添加结果
*/
@Post
@Mapping("/add")
public ResponseResult add(@NotBlank(message = "父级权限ID不能为空") Integer parentId,
@NotBlank(message = "权限名称不能为空") String name,
@NotBlank(message = "权限标识不能为空") String identifier,
@Param(required = false) String path,
@Param(required = false) String component,
@NotBlank(message = "权限类型不能为空") String type,
@NotBlank(message = "排序ID不能为空") Integer sortId,
@NotBlank(message = "权限状态不能为空") Integer status) {
PermsEntity permsEntity = new PermsEntity();
permsEntity.setParentId(parentId);
permsEntity.setName(name);
permsEntity.setIdentifier(identifier);
permsEntity.setPath(path);
permsEntity.setComponent(component);
permsEntity.setType(Integer.parseInt(type));
permsEntity.setSortId(sortId);
permsEntity.setStatus(status);
// 插入权限数据
easyEntityQuery.insertable(permsEntity).executeRows();
return ResponseResult.success("添加成功", null);
}
/**
* 修改权限
* @visduo
*
* @param id 权限id
* @param name 权限名称
* @return 修改结果
*/
@Put
@Mapping("/update/{id}")
public ResponseResult update(@Path int id,
@NotBlank(message = "父级权限ID不能为空") Integer parentId,
@NotBlank(message = "权限名称不能为空") String name,
@NotBlank(message = "权限标识不能为空") String identifier,
@Param(required = false) String path,
@Param(required = false) String component,
@NotBlank(message = "权限类型不能为空") String type,
@NotBlank(message = "排序ID不能为空") Integer sortId,
@NotBlank(message = "权限状态不能为空") Integer status) {
PermsEntity permsEntity = new PermsEntity();
permsEntity.setId(id);
permsEntity.setParentId(parentId);
permsEntity.setName(name);
permsEntity.setIdentifier(identifier);
permsEntity.setPath(path);
permsEntity.setComponent(component);
permsEntity.setType(Integer.parseInt(type));
permsEntity.setSortId(sortId);
permsEntity.setStatus(status);
// 修改权限数据
easyEntityQuery.updatable(permsEntity).executeRows();
return ResponseResult.success("修改成功", null);
}
/**
* 删除权限
* @visduo
*
* @param id 权限id
* @return 删除结果
*/
@Delete
@Mapping("/delete/{id}")
public ResponseResult delete(@Path int id) {
// 该权限下有子权限,禁止删除
long count = easyEntityQuery.queryable(PermsEntity.class)
.where(p -> {
p.parentId().eq(id);
}).count();
if (count > 0) {
return ResponseResult.failure("该权限下有子权限,禁止删除", null);
}
// 删除权限数据
easyEntityQuery.deletable(PermsEntity.class)
.where(p -> {
p.id().eq(id);
}).executeRows();
return ResponseResult.success("删除成功", null);
}
/**
* 根据权限ID获取权限信息
* @visduo
*
* @param id 权限ID
* @return 权限信息
*/
@Get
@Mapping("/get/{id}")
public ResponseResult get(@Path int id) {
PermsEntity permsEntity = easyEntityQuery.queryable(PermsEntity.class)
.where(p -> {
p.id().eq(id);
}).firstOrNull();
return ResponseResult.success("查询成功", permsEntity);
}
}前端组件
核心注意事项:
- 权限管理的前端组件,提供基础增删改查表单,表单相关注意事项和要求同前。
- 后端 API 返回给前端的权限列表是扁平化列表,前端需要自行编写工具类方法,将其转换为树形结构列表。
- 权限列表,使用 ElementPlus 树形数据表格组件渲染。
- 增改表单涉及关联父级权限下拉框,使用 ElementPlus 树形选择下拉框组件渲染。
AI 生成树形结构工具方法提示词:
编写一个工具类src/plugins/TreeUtil,工具类中包含方法toTreeList.js,作用为:
1、将扁平结构的权限数据数组,转换为支持无限级嵌套的树形结构数组。
2、方法入参原始数组flatList,数组中的元素包含id、parentId,转换后的每个树形节点需完整保留原始节点的所有字段,仅新增childre字段以保存树形结构数据。
3、方法返回转换后的树形结构数组。编写树形结构工具类(plugins/TreeUtil.js),提供树形结构转换方法:
/**
* 将扁平结构的权限数据数组,转换为支持无限级嵌套的树形结构数组
* @param {Array} flatList 扁平结构的数据数组,每个元素需要包含id和parentId字段
* @returns {Array} 转换后的树形结构数组,每个节点包含原节点的所有字段及children字段
*/
export function toTreeList(flatList) {
// 创建一个映射来存储所有节点
const nodeMap = new Map();
// 结果数组
const result = [];
// 首先复制所有节点到映射中,并添加children属性
flatList.forEach(item => {
nodeMap.set(item.id, { ...item, children: [] });
});
// 构建树形结构
flatList.forEach(item => {
const node = nodeMap.get(item.id);
if (item.parentId === null || item.parentId === undefined || item.parentId === 0) {
// 没有父节点的项作为根节点
result.push(node);
} else {
// 有父节点的项添加到父节点的children中
const parentNode = nodeMap.get(item.parentId);
if (parentNode) {
parentNode.children.push(node);
} else {
// 如果找不到父节点,默认作为根节点处理
result.push(node);
}
}
});
return result;
}
export default {
toTreeList
};AI 生成组件提示词:
基于ElementPlus,生成权限列表页面,要求如下:
1、编码风格,严格参考部门组件Dept.vue。
2、提供搜索表单,搜索条件为权限名称name、权限标识identifier。
3、后端返回给前端的数据是全量列表数据。你需要调用TreeUtil相关方法将其转换为树形结构数组,并使用树形数据表格组件进行渲染。
4、获取权限列表:响应权限数据包含权限ID、父级权限ID-parentId、权限名称name、权限标识identifier、权限路由路径path、权限路由组件component、权限类型type(0目录/1菜单/2操作)、排序ID-sortId、权限状态status。
5、新增/修改表单中,父级权限显示树形选择下拉框,下拉数据即使用TreeUtil处理后的树形结构数组。树形选择下拉框中,默认需要包含一个根权限,id为0。
6、新增/修改表单中,权限路由路径path、权限路由组件component非必填。编写权限组件(views/Perms.vue),提供权限管理视图:
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { toTreeList } from '@/plugins/TreeUtil.js'
import qs from "qs";
// 表格数据
const tableData = ref([])
// 搜索表单数据
const searchForm = reactive({
name: '',
identifier: ''
})
// 添加权限对话框相关
const addDialogVisible = ref(false)
const addFormRef = ref()
const addFormData = reactive({
parentId: 0,
name: '',
identifier: '',
path: '',
component: '',
type: 1,
sortId: 0,
status: 1
})
const addFormRules = {
parentId: [
{ required: true, message: '请选择父级权限', trigger: 'change' }
],
name: [
{ required: true, message: '请输入权限名称', trigger: 'blur' },
{ min: 1, max: 50, message: '长度应在1到50个字符之间', trigger: 'blur' }
],
identifier: [
{ required: true, message: '请输入权限标识', trigger: 'blur' },
{ min: 1, max: 100, message: '长度应在1到100个字符之间', trigger: 'blur' }
],
type: [
{ required: true, message: '请选择权限类型', trigger: 'change' }
],
sortId: [
{ required: true, message: '请输入排序ID', trigger: 'blur' }
],
status: [
{ required: true, message: '请选择权限状态', trigger: 'change' }
]
}
// 编辑权限对话框相关
const editDialogVisible = ref(false)
const editFormRef = ref()
const editFormData = reactive({
id: '',
parentId: 0,
name: '',
identifier: '',
path: '',
component: '',
type: 1,
sortId: 0,
status: 1
})
const editFormRules = {
parentId: [
{ required: true, message: '请选择父级权限', trigger: 'change' }
],
name: [
{ required: true, message: '请输入权限名称', trigger: 'blur' },
{ min: 1, max: 50, message: '长度应在1到50个字符之间', trigger: 'blur' }
],
identifier: [
{ required: true, message: '请输入权限标识', trigger: 'blur' },
{ min: 1, max: 100, message: '长度应在1到100个字符之间', trigger: 'blur' }
],
type: [
{ required: true, message: '请选择权限类型', trigger: 'change' }
],
sortId: [
{ required: true, message: '请输入排序ID', trigger: 'blur' }
],
status: [
{ required: true, message: '请选择权限状态', trigger: 'change' }
]
}
// 父级权限选项(树形结构)
const parentPermsOptions = ref([])
// 权限类型选项
const typeOptions = [
{ label: '目录', value: 0 },
{ label: '菜单', value: 1 },
{ label: '操作', value: 2 }
]
// 权限状态选项
const statusOptions = [
{ label: '启用', value: 1 },
{ label: '禁用', value: 0 }
]
// 获取权限列表
const fetchPermsList = () => {
// 构造查询参数
const params = {
name: searchForm.name || undefined,
identifier: searchForm.identifier || undefined
}
axios.get('/perms/list', { params }).then((res) => {
// 将扁平数据转换为树形结构
const treeData = toTreeList(res.data)
tableData.value = treeData
})
}
// 获取所有权限列表(用于父级权限选项)
const fetchAllPermsList = () => {
axios.get('/perms/list').then((res) => {
// 将扁平数据转换为树形结构
const treeData = toTreeList(res.data)
// 更新父级权限选项,添加根权限选项
parentPermsOptions.value = [{ id: 0, name: '根权限', children: treeData }]
})
}
// 搜索
const submitSearchForm = () => {
fetchPermsList()
}
// 重置搜索
const resetSearchForm = () => {
searchForm.name = ''
searchForm.identifier = ''
fetchPermsList()
}
// 显示添加权限对话框
const showAddDialog = () => {
fetchAllPermsList()
addDialogVisible.value = true
}
// 提交添加表单
const submitAddForm = () => {
addFormRef.value.validate((valid) => {
if (valid) {
axios.post('/perms/add', qs.stringify(addFormData)).then((res) => {
ElMessage.success('添加成功')
addDialogVisible.value = false
resetAddForm()
fetchPermsList()
})
} else {
ElMessage.error('请正确填写表单信息')
return false
}
})
}
// 重置添加表单
const resetAddForm = () => {
addFormRef.value.resetFields()
}
// 显示编辑权限对话框
const showEditDialog = (row) => {
fetchAllPermsList()
// 先设置ID,用于请求详细信息
editFormData.id = row.id
editDialogVisible.value = true
// 获取权限详细信息
axios.get(`/perms/get/${row.id}`).then((res) => {
editFormData.parentId = res.data.parentId
editFormData.name = res.data.name
editFormData.identifier = res.data.identifier
editFormData.path = res.data.path
editFormData.component = res.data.component
editFormData.type = res.data.type
editFormData.sortId = res.data.sortId
editFormData.status = res.data.status
})
}
// 提交编辑表单
const submitEditForm = () => {
editFormRef.value.validate((valid) => {
if (valid) {
axios.put(`/perms/update/${editFormData.id}`, qs.stringify(editFormData)).then((res) => {
ElMessage.success('修改成功')
editDialogVisible.value = false
resetEditForm()
fetchPermsList()
})
} else {
ElMessage.error('请正确填写表单信息')
return false
}
})
}
// 重置编辑表单
const resetEditForm = () => {
editFormRef.value.resetFields()
}
// 删除权限
const handleDelete = (id) => {
ElMessageBox.confirm('确定要删除该权限吗?', '删除确认', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
axios.delete(`/perms/delete/${id}`)
.then((res) => {
ElMessage.success('删除成功')
fetchPermsList()
})
}).catch(() => {
// 用户取消删除
})
}
// 初始化加载数据
onMounted(() => {
fetchPermsList()
})
</script>
<template>
<el-main class="layout-main">
<!-- 搜索表单 -->
<el-card shadow="never" style="margin-bottom: 1rem;" :body-style="{paddingBottom: '2px'}">
<el-form :model="searchForm" inline>
<el-form-item label="权限名称">
<el-input v-model="searchForm.name" placeholder="请输入权限名称" />
</el-form-item>
<el-form-item label="权限标识">
<el-input v-model="searchForm.identifier" placeholder="请输入权限标识" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitSearchForm">搜索</el-button>
<el-button @click="resetSearchForm">重置</el-button>
<el-button type="warning" @click="showAddDialog">添加权限</el-button>
</el-form-item>
</el-form>
</el-card>
<!-- 数据表格 -->
<el-card shadow="never">
<template #header>
<div class="card-header">
<span>权限列表</span>
</div>
</template>
<el-table :data="tableData" style="width: 100%" row-key="id" default-expand-all :tree-props="{children: 'children'}" stripe>
<el-table-column prop="name" label="权限名称" />
<el-table-column prop="identifier" label="权限标识" />
<el-table-column prop="path" label="路由路径" />
<el-table-column prop="component" label="组件路径" />
<el-table-column prop="type" label="权限类型" width="80">
<template #default="scope">
<el-tag v-if="scope.row.type === 0">目录</el-tag>
<el-tag v-else-if="scope.row.type === 1" type="success">菜单</el-tag>
<el-tag v-else-if="scope.row.type === 2" type="warning">操作</el-tag>
</template>
</el-table-column>
<el-table-column prop="sortId" label="排序ID" width="80" />
<el-table-column prop="status" label="状态" width="80">
<template #default="scope">
<el-tag v-if="scope.row.status === 1" type="success">启用</el-tag>
<el-tag v-else type="danger">禁用</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="150">
<template #default="scope">
<el-button type="primary" size="small" @click="showEditDialog(scope.row)">编辑</el-button>
<el-button type="danger" size="small" @click="handleDelete(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 添加权限对话框 -->
<el-dialog v-model="addDialogVisible" title="添加权限" width="500px" @close="resetAddForm">
<el-form ref="addFormRef" :model="addFormData" :rules="addFormRules" label-width="100px" label-position="top">
<el-form-item label="父级权限" prop="parentId">
<el-tree-select
v-model="addFormData.parentId"
:data="parentPermsOptions"
node-key="id"
:props="{ label: 'name', children: 'children' }"
check-strictly
style="width: 100%"
placeholder="请选择父级权限"
/>
</el-form-item>
<el-form-item label="权限名称" prop="name">
<el-input v-model="addFormData.name" placeholder="请输入权限名称"/>
</el-form-item>
<el-form-item label="权限标识" prop="identifier">
<el-input v-model="addFormData.identifier" placeholder="请输入权限标识"/>
</el-form-item>
<el-form-item label="路由路径">
<el-input v-model="addFormData.path" placeholder="请输入路由路径"/>
</el-form-item>
<el-form-item label="组件路径">
<el-input v-model="addFormData.component" placeholder="请输入组件路径"/>
</el-form-item>
<el-form-item label="权限类型" prop="type">
<el-select v-model="addFormData.type" placeholder="请选择权限类型" style="width: 100%">
<el-option
v-for="item in typeOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="排序ID" prop="sortId">
<el-input-number v-model="addFormData.sortId" :min="0" controls-position="right" style="width: 100%"/>
</el-form-item>
<el-form-item label="权限状态" prop="status">
<el-select v-model="addFormData.status" placeholder="请选择权限状态" style="width: 100%">
<el-option
v-for="item in statusOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<div style="width: 100%; text-align: center">
<el-button @click="addDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitAddForm">确定</el-button>
</div>
</template>
</el-dialog>
<!-- 编辑权限对话框 -->
<el-dialog v-model="editDialogVisible" title="编辑权限" width="500px" @close="resetEditForm">
<el-form ref="editFormRef" :model="editFormData" :rules="editFormRules" label-width="100px" label-position="top">
<el-form-item label="父级权限" prop="parentId">
<el-tree-select
v-model="editFormData.parentId"
:data="parentPermsOptions"
node-key="id"
:props="{ label: 'name', children: 'children' }"
check-strictly
style="width: 100%"
placeholder="请选择父级权限"
/>
</el-form-item>
<el-form-item label="权限名称" prop="name">
<el-input v-model="editFormData.name" placeholder="请输入权限名称"/>
</el-form-item>
<el-form-item label="权限标识" prop="identifier">
<el-input v-model="editFormData.identifier" placeholder="请输入权限标识"/>
</el-form-item>
<el-form-item label="路由路径">
<el-input v-model="editFormData.path" placeholder="请输入路由路径"/>
</el-form-item>
<el-form-item label="组件路径">
<el-input v-model="editFormData.component" placeholder="请输入组件路径"/>
</el-form-item>
<el-form-item label="权限类型" prop="type">
<el-select v-model="editFormData.type" placeholder="请选择权限类型" style="width: 100%">
<el-option
v-for="item in typeOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="排序ID" prop="sortId">
<el-input-number v-model="editFormData.sortId" :min="0" controls-position="right" style="width: 100%"/>
</el-form-item>
<el-form-item label="权限状态" prop="status">
<el-select v-model="editFormData.status" placeholder="请选择权限状态" style="width: 100%">
<el-option
v-for="item in statusOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<div style="width: 100%; text-align: center">
<el-button @click="editDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitEditForm">确定</el-button>
</div>
</template>
</el-dialog>
</el-main>
</template>编写路由配置文件(router/index.js),提供权限管理路由信息:
{
// 权限管理
path: 'perms/list',
component: () => import('@/views/Perms.vue'),
},编写布局组件(views/Layouts.vue),提供权限管理菜单:
{
id: 20,
title: '权限管理',
path: '/perms/list'
},在浏览器中测试:
角色授权
后端 API
核心注意事项:
- 修改角色权限:提供修改角色权限方法,传入授权的权限 ID 字符串,并保存到数据库中。
- 角色 ID 为 1 即最高角色,禁止修改角色权限。
编写角色控制器(cn.duozai.sadmin.controller.RoleController),提供修改角色权限方法:
package cn.duozai.sadmin.controller;
import cn.duozai.sadmin.repository.RoleEntity;
import cn.duozai.sadmin.repository.UsersEntity;
import cn.duozai.sadmin.utils.ResponseResult;
import cn.hutool.core.util.StrUtil;
import com.easy.query.api.proxy.client.EasyEntityQuery;
import com.easy.query.core.api.pagination.EasyPageResult;
import com.easy.query.solon.annotation.Db;
import org.noear.solon.annotation.*;
import org.noear.solon.validation.annotation.NotBlank;
import java.util.List;
/**
* 角色控制器
* @visduo
*/
@Mapping("/role")
@Controller
public class RoleController {
// ...
/**
* 修改角色权限
* @visduo
*
* @param id 角色id
* @param perms 授权的权限菜单列表
* @return 修改结果
*/
@Put
@Mapping("/updatePerms/{id}")
public ResponseResult updatePerms(@Path int id,
@Param String perms) {
// 禁止修改ID为1的角色
if (id == 1) {
return ResponseResult.failure("默认角色禁止修改", null);
}
RoleEntity roleEntity = new RoleEntity();
roleEntity.setId(id);
roleEntity.setPerms(perms);
easyEntityQuery.updatable(roleEntity).executeRows();
return ResponseResult.success("修改成功", null);
}
}
前端组件
核心注意事项:
- 角色列表中,操作列提供授权按钮,点击授权按钮显示授权模态框,回显勾选已授权的权限。
- 授权模态框中,使用 Tree 树形控件组件展示权限树形结构列表。
- Tree 树形控件组件支持取消父子节点的勾选关联,让父节点和子节点的勾选状态完全独立,父节点不会因子节点勾选和取消而自动半选或全选,子节点也不受父节点影响。
- 表单提交时获取选中的权限 ID 数组并转换为字符串,发送给后端 API。
AI 生成组件提示词:
在Role.vue的基础上,实现:
1、在表格操作列添加一个授权按钮,点击授权按钮后,弹出授权模态框。
2、授权模态框展示时,发送请求到/perms/list获取全量权限列表,并使用TreeUtil转换为树形结构。
3、使用Tree树形控件组件展示权限列表。
4、授权模态框展示时,发送请求到/role/get/xxx,获取到角色信息中的perms后,回显勾选权限列表。perms的格式为字符串1,2,3,4。
5、点击确定按钮,获取权限列表中选中项的id数组并将其转换成字符串,发送请求到/role/updatePerms/xxx。
6、ID为1的角色是默认角色,需要禁用授权按钮。编写角色组件(views/Role.vue),提供角色授权视图:
<script setup>
// ...
// 授权对话框相关
const authDialogVisible = ref(false)
const permTreeData = ref([])
const defaultCheckedKeys = ref([])
const treeRef = ref()
// ...
// 显示授权对话框
const showAuthDialog = (row) => {
// 保存当前角色ID用于后续操作
editFormData.id = row.id;
// 获取全量权限列表
axios.get('/perms/list').then((res) => {
// 将扁平数据转换为树形结构
permTreeData.value = toTreeList(res.data)
// 获取角色详细信息,包括权限列表
axios.get(`/role/get/${row.id}`).then((response) => {
// 设置默认选中的权限
// 处理perms可能不存在或为逗号分隔字符串的情况
let permIds = [];
if (response.data.perms) {
// perms是逗号分隔的字符串格式,例如"1,2,3,4,5"
permIds = response.data.perms.split(',').map(id => parseInt(id.trim())).filter(id => !isNaN(id));
}
defaultCheckedKeys.value = permIds;
// 显示授权对话框
authDialogVisible.value = true
})
})
}
// 提交授权表单
const submitAuthForm = () => {
// 获取选中的权限ID数组
const checkedKeys = treeRef.value.getCheckedKeys()
// 发送请求更新角色权限
axios.put(`/role/updatePerms/${editFormData.id}`, qs.stringify({ perms: checkedKeys.join(',') })).then((res) => {
ElMessage.success('授权成功')
authDialogVisible.value = false
fetchRoleList()
})
}
// 重置授权表单
const resetAuthForm = () => {
defaultCheckedKeys.value = []
permTreeData.value = []
}
// ...
</script>
<template>
<el-main class="layout-main">
<!-- ... -->
<!-- 数据表格 -->
<el-card shadow="never">
<template #header>
<div class="card-header">
<span>角色列表</span>
</div>
</template>
<el-table :data="tableData" style="width: 100%" stripe>
<!-- ... -->
<el-table-column label="操作">
<template #default="scope">
<el-button type="primary" size="small" @click="showEditDialog(scope.row)">编辑</el-button>
<el-button type="success" size="small" @click="showAuthDialog(scope.row)" :disabled="scope.row.id === 1">
授权
</el-button>
<el-button type="danger" size="small" @click="handleDelete(scope.row.id)" :disabled="scope.row.id === 1">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- ... -->
</el-card>
<!-- ... -->
<!-- 授权对话框 -->
<el-dialog v-model="authDialogVisible" title="角色授权" width="500px" @close="resetAuthForm">
<el-tree
ref="treeRef"
:data="permTreeData"
show-checkbox
node-key="id"
:props="{ label: 'name', children: 'children' }"
:default-checked-keys="defaultCheckedKeys"
:default-expand-all="false"
:check-strictly="true"
style="width: 100%"
/>
<template #footer>
<div style="width: 100%; text-align: center">
<el-button @click="authDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitAuthForm">确定</el-button>
</div>
</template>
</el-dialog>
</el-main>
</template>
在浏览器中测试:
如无特殊说明,网站中的系列文章均为作者「@多仔」原创编辑,版权归作者「@多仔」所有,资源引用部分已注明来源,AIGC 创作部分已注明标识,拒绝未经授权的任何个人或组织以任何形式转载、复制、修改、发布或用于商业目的。
文章中可能会存在些许错别字内容描述不完整、表述不准确、排版布局异常等问题,文章中提及的软件、依赖、框架等程序可能随其版本更新迭代而产生变化,文章中的相关代码片段、例图、文本等内容仅供参考。
如若转载,请注明出处:https://www.duox.dev/post/124.html
文章中可能会存在些许错别字内容描述不完整、表述不准确、排版布局异常等问题,文章中提及的软件、依赖、框架等程序可能随其版本更新迭代而产生变化,文章中的相关代码片段、例图、文本等内容仅供参考。
如若转载,请注明出处:https://www.duox.dev/post/124.html