第三十一节:角色管理页面 + 权限分配树形弹窗

第三十一节:角色管理页面 + 权限分配树形弹窗

目标:完成角色列表,新增编辑角色,弹出 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>

测试步骤

  1. 访问角色管理页面,可以加载角色列表。
  2. 点击【分配权限】,弹窗打开,树形菜单渲染出来,部分节点默认勾选。
  3. 修改勾选状态,点击确定保存,mock 控制台打印提交的权限 id 数组。
  4. 保存成功后回调刷新角色列表。

重点坑点

  1. el‑tree 必须配置 node‑key="id",getCheckedKeys () 才可以正常拿到选中 id。
  2. default‑checked‑keys只在组件初始化生效;弹窗第二次打开要重新赋值。
  3. 真实业务场景,打开弹窗时需要调用接口获取该角色已有的权限 id,赋值给 checkedKeys 做回显。
相关推荐
zz-zjx1 小时前
Python实用转换模板
开发语言·前端·python
暖焰核心1 小时前
C++模板进阶——特化全解
javascript·c++·jquery
Csvn1 小时前
声明文件(.d.ts):让 TypeScript 认识你的 JS 库
前端
晓得迷路了1 小时前
栗子前端技术周刊第 145 期 - Remix 3 RC、htmx 4.0、Rslib 1.0...
前端·javascript·react.js
恋猫de小郭1 小时前
OpenAI :GPT-6 开始你需要给 Skill 和 AGENTS.md 做一次大扫除了
前端·人工智能·ai编程
IT_陈寒1 小时前
Redis莫名连接失败,查了三天居然是配置的锅
前端·人工智能·后端
晴天161 小时前
Esbuild:前端构建工具的“速度革命”
前端
雪芽蓝域zzs1 小时前
第三十五节:Axios 统一错误拦截、401 Token 过期处理
前端·javascript·vue.js
XIE3922 小时前
TipKit:开源富文本编辑器套件,一套逻辑,任意风格!
前端·笔记·开源