第三十一节:角色管理页面 + 权限分配树形弹窗
目标:完成角色列表,新增编辑角色,弹出 el‑tree 树形组件,给角色勾选菜单权限,保存权限集合。
技术点:Element Plus
el‑tree树形控件,勾选回显、获取选中节点、弹窗嵌套树形组件。
1、mock 接口补充 src/mock/index.js
// 获取角色列表
'/api/role/list': () => {
return {
code: 200,
data: {
records: [
{ id:1, roleName:'超级管理员', roleKey:'admin', remark:'拥有全部权限' },
{ id:2, roleName:'普通用户', roleKey:'user', remark:'仅有查看权限' }
]
}
}
},
// 新增角色
'/api/role/add': ({body}) => {
return {code:200,msg:'角色新增成功'}
},
//编辑角色
'/api/role/update': ({body}) => {
return {code:200,msg:'角色编辑成功'}
},
//删除角色
'/api/role/remove': ({body}) => {
return {code:200,msg:'角色删除成功'}
},
// 获取所有菜单树(用于分配权限弹窗)
'/api/menu/tree': () => {
return {
code:200,
data:[
{
id:1,
label:'用户管理',
children:[
{id:11,label:'用户查询'},
{id:12,label:'用户新增'},
{id:13,label:'用户编辑'},
{id:14,label:'用户删除'}
]
},
{
id:2,
label:'角色管理',
children:[
{id:21,label:'角色查询'},
{id:22,label:'角色编辑'}
]
}
]
}
},
//保存角色权限
'/api/role/savePermission':({body})=>{
console.log('保存权限id数组',body.permIds)
return {code:200,msg:'权限分配成功'}
}
2、新建 api 角色请求 src/api/role.js
import request from '@/utils/request'
export function getRoleList(){
return request({url:'/api/role/list',method:'get'})
}
export function addRole(data){
return request({url:'/api/role/add',method:'post',data})
}
export function updateRole(data){
return request({url:'/api/role/update',method:'post',data})
}
export function deleteRole(data){
return request({url:'/api/role/remove',method:'post',data})
}
//获取全部菜单树
export function getMenuTree(){
return request({url:'/api/menu/tree',method:'get'})
}
//保存角色权限
export function saveRolePermission(data){
return request({url:'/api/role/savePermission',method:'post',data})
}
3、封装权限分配弹窗子组件 src/views/system/role/components/PermissionDialog.vue
<template>
<el-dialog
v-model="dialogVisible"
title="分配权限"
width="480px"
@close="handleClose"
>
<!--树形组件 show-checkbox开启复选框 -->
<el-tree
ref="treeRef"
:data="treeData"
show-checkbox
node-key="id"
:default-checked-keys="checkedKeys"
:props="{ label:'label', children:'children' }"
/>
<template #footer>
<el-button @click="dialogVisible=false">取消</el-button>
<el-button type="primary" @click="submitPermission">确定保存</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { getMenuTree, saveRolePermission } from '@/api/role'
const props = defineProps({
visible:{type:Boolean,default:false},
roleId:{type:Number,default:null}
})
const emit = defineEmits(['update:visible','success'])
const dialogVisible = ref(false)
const treeRef = ref(null)
const treeData = ref([])
const checkedKeys = ref([])
watch(()=>props.visible,val=>{
dialogVisible.value = val
if(val){
loadTree()
}
})
//加载菜单树
async function loadTree(){
const res = await getMenuTree()
treeData.value = res.data
//模拟:编辑角色时回显已勾选id,实际项目由接口返回该角色已拥有的权限id
checkedKeys.value = [1,11,12]
}
async function submitPermission(){
//获取当前所有选中节点id
const permIds = treeRef.value.getCheckedKeys()
await saveRolePermission({
roleId: props.roleId,
permIds
})
ElMessage.success('权限分配完成')
dialogVisible.value = false
emit('success')
}
function handleClose(){
emit('update:visible',false)
}
</script>
4、角色管理主页面 src/views/system/role/index.vue
<template>
<div>
<h2>角色管理</h2>
<div style="margin:12px 0">
<el-button type="primary">新增角色</el-button>
</div>
<el-table :data="tableData">
<el-table-column label="ID" prop="id"/>
<el-table-column label="角色名称" prop="roleName"/>
<el-table-column label="角色标识" prop="roleKey"/>
<el-table-column label="备注" prop="remark"/>
<el-table-column label="操作">
<template #default="scope">
<el-link type="primary">编辑</el-link>
<el-link type="warning" @click="openPermDialog(scope.row)">分配权限</el-link>
<el-link type="danger">删除</el-link>
</template>
</el-table-column>
</el-table>
<!--权限分配弹窗-->
<PermissionDialog
v-model:visible="permDialogShow"
:role-id="currentRoleId"
@success="getList"
/>
</div>
</template>
<script setup>
import {ref,onMounted} from 'vue'
import { getRoleList } from '@/api/role'
import PermissionDialog from './components/PermissionDialog.vue'
const tableData = ref([])
const permDialogShow = ref(false)
const currentRoleId = ref(null)
async function getList(){
const res = await getRoleList()
tableData.value = res.data.records
}
//打开分配权限弹窗
function openPermDialog(row){
currentRoleId.value = row.id
permDialogShow.value = true
}
onMounted(()=>{
getList()
})
</script>
测试步骤
- 访问角色管理页面,可以加载角色列表。
- 点击【分配权限】,弹窗打开,树形菜单渲染出来,部分节点默认勾选。
- 修改勾选状态,点击确定保存,mock 控制台打印提交的权限 id 数组。
- 保存成功后回调刷新角色列表。
重点坑点
- el‑tree 必须配置
node‑key="id",getCheckedKeys () 才可以正常拿到选中 id。 default‑checked‑keys只在组件初始化生效;弹窗第二次打开要重新赋值。- 真实业务场景,打开弹窗时需要调用接口获取该角色已有的权限 id,赋值给 checkedKeys 做回显。
