【Dv3Admin】Vue3一键配置权限规则

张开发
2026/4/9 15:18:52 15 分钟阅读

分享文章

【Dv3Admin】Vue3一键配置权限规则
在后台权限体系中角色、菜单、接口按钮与数据范围往往被拆散在多个配置入口中维护实际落地时极易出现按钮越权、数据范围错配、前端状态与后端存储不一致等问题。这类风险通常不源于单一逻辑错误而是配置路径过长、默认策略缺失以及批量操作能力不足共同叠加后的结果。本文围绕“角色权限配置”这一真实模块展开聚焦权限配置抽屉RoleDrawer与接口权限面板RoleMenuBtn的协作方式完整拆解从部门切换、菜单选择、按钮勾选到数据范围持久化的实现链路重点关注参数传递、状态同步与接口封装方式。文章目录需求解析功能实现总结需求解析该功能位于后台系统的角色管理模块中运行在前端基于 Vue 与 Element Plus 的管理界面后端通过统一的权限接口提供数据支撑主要服务于角色创建或调整后的权限配置场景。使用过程中需要在一个统一界面内完成部门切换、菜单定位、接口按钮授权以及数据范围控制且所有操作要求即时生效并持久化。从操作链路上看权限配置从角色列表页触发打开权限配置抽屉后通过部门筛选驱动菜单树刷新菜单节点变化进一步触发接口权限面板的数据加载按钮勾选与数据范围设置最终通过接口写入后端。结果落库接口持久化权限配置选择菜单加载接口按钮勾选按钮设置数据范围上下文切换切换部门加载菜单树入口触发角色列表页打开RoleDrawer功能实现权限配置抽屉由RoleDrawer.vue承载负责统一容纳部门切换、菜单树以及不同权限面板通过抽屉形式避免页面跳转带来的上下文丢失。template el-drawer v-modelRoleDrawer.drawerVisible title权限配置 directionrtl size80% :close-on-click-modalfalse :before-closeRoleDrawer.handleDrawerClose :destroy-on-closetrue template #header div styledisplay: flex;align-items: center; el-form-item label部门 propcompany stylemargin-top: 16px;margin-right: 12px; el-select v-modelRoleDrawer.company placeholder请选择部门 changehandleDeptChange stylewidth: 200px; el-option v-foritem in deptAllList :keyitem.key :labelitem.name :valueitem.name / /el-select /el-form-item div当前授权角色 el-tag stylemargin-right: 20px{{ RoleDrawer.roleName }}/el-tag 授权人员 el-button sizesmall :iconUserFilled clickhandleUsers{{ RoleDrawer.users.length }}/el-button /div /div /template splitpanes classdefault-theme styleheight: 100% pane min-size20 size22 div classpane-box MenuTreeCom refrefMenuTreeCom / /div /pane pane min-size20 div classpane-box el-tabs v-modelactiveName classdemo-tabs el-tab-pane label接口权限 namefirst MenuBtnCom / /el-tab-pane el-tab-pane label列字段权限 namesecond MenuFieldCom / /el-tab-pane /el-tabs /div /pane /splitpanes /el-drawer el-dialog v-modeldialogVisible title授权用户 width700px :close-on-click-modalfalse RoleUsersCom / /el-dialog /template该组件的关键在于将部门、菜单与权限面板解耦抽屉关闭时销毁实例避免历史状态残留。接口权限面板由RoleMenuBtn.vue实现承担默认接口权限、按钮勾选与快捷配置能力。template div classpccm-item v-ifRoleMenuBtn.$state.length 0 div classmenu-form-alert div styledisplay: flex; align-items: center; white-space: nowrap; margin-bottom: 10px span默认接口权限:/span el-select v-modeldefault_selectBtn.data_range changedefaulthandlePermissionRangeChange placeholder请选择 stylemargin-left: 5px; width: 250px; min-width: 250px el-option v-foritem in dataPermissionRange :keyitem.value :labelitem.label :valueitem.value / /el-select el-tree-select v-showdefault_selectBtn.data_range 4 node-keyid v-modeldefault_selectBtn.dept :propsdefaultTreeProps :datadeptData changecustomhandlePermissionRangeChange(default_selectBtn.dept) placeholder请选择自定义部门 multiple check-strictly :render-after-expandfalse show-checkbox classdialog-tree stylemargin-left: 15px; width: AUTO; min-width: 250px; margin-top: 0 / /div span配置操作功能接口权限配置数据权限点击小齿轮/span /div div stylemargin-bottom: 20px; el-button typeprimary clickhandleQuickQuery(快速查询)快速查询/el-button el-button typeprimary clickhandleQuickQuery(标准业务)标准业务/el-button /div el-checkbox v-forbtn in RoleMenuBtn.$state :keybtn.id v-modelbtn.isCheck changehandleCheckChange(btn) div classbtn-item {{ btn.data_range ! null ? ${btn.name}(${formatDataRange(btn.data_range, btn.dept)}) : btn.name }} span v-showbtn.isCheck click.stop.preventhandleSettingClick(btn) el-icon Setting / /el-icon /span span【{{ btn.api }}】/span /div /el-checkbox /div默认接口权限在此作为批量勾选的基准避免为每个按钮重复配置数据范围。按钮勾选与快速配置通过统一接口完成写入并同步更新本地状态。consthandleCheckChangeasync(btn:RoleMenuBtnType){selectBtn.valuedefault_selectBtn.value;constput_data{isCheck:btn.isCheck,roleId:RoleDrawer.roleId,menuId:RoleMenuTree.id,btnId:btn.id,data_range:default_selectBtn.value.data_range,dept:default_selectBtn.value.dept,};const{data,msg}awaitsetRoleMenuBtn(put_data);RoleMenuBtn.updateState(data);ElMessage({message:msg,type:success});};该逻辑保证勾选行为与后端状态保持同步否则会导致前端显示与实际权限不一致。快捷配置基于后端预设返回按钮集合再批量写入权限。consthandleQuickQueryasync(type:string){const{data}awaitgetRoleMenuBtnField({roleId:RoleDrawer.roleId,menuId:RoleMenuTree.id,select:type,});constnamesdata.menu_btn.map((item:any)item.name);constupdatedButtonsRoleMenuBtn.$state.map((btn:RoleMenuBtnType)({...btn,isCheck:names.includes(btn.name)}));RoleMenuBtn.updateBatchState(updatedButtons);constpromisesupdatedButtons.filter(btnnames.includes(btn.name)).map(async(btn){constput_data{isCheck:btn.isCheck,roleId:RoleDrawer.roleId,menuId:RoleMenuTree.id,btnId:btn.id,data_range:default_selectBtn.value.data_range,dept:default_selectBtn.value.dept,};returnawaitsetRoleMenuBtn(put_data);});try{awaitPromise.all(promises);ElMessage({message:快速配置成功,type:success});}catch(error){ElMessage({message:快速配置失败,type:error});}}单按钮的数据范围通过弹窗单独配置确认后立即持久化。consthandleDialogConfirmasync(){const{data,msg}awaitsetRoleMenuBtnDataRange(selectBtn.value);selectBtn.valuedata;dialogVisible.valuefalse;ElMessage({message:msg,type:success});};接口统一封装在组件内的api.ts确保权限相关读写路径集中维护。exportfunctiongetRoleMenu(query:object){returnrequest({url:/api/system/role_menu_button_permission/get_role_menu/,method:get,params:query,}).then((res:any){returnXEUtils.toArrayTree(res.data,{key:id,parentKey:parent,children:children,strict:false});});}/** * 设置 角色-菜单 */exportfunctionsetRoleMenu(data:object){returnrequest({url:/api/system/role_menu_button_permission/set_role_menu/,method:put,data,});}角色列表页通过权限控制暴露入口避免无权限访问配置能力。permission:{type:primary,text:权限配置,show:auth(role:Permission),click:(clickContext:any):void{const{row}clickContext;context.RoleDrawer.handleDrawerOpen(row);context.RoleMenuBtn.setState([]);context.RoleMenuField.setState([]);},},总结该模块通过权限配置抽屉将部门、菜单与接口权限聚合在单一操作空间内避免多页面切换造成的状态割裂同时以默认接口权限作为批量授权的核心锚点。在实现层面勾选即存与弹窗即存降低了配置遗漏风险但接口调用频繁对后端幂等性与性能提出更高要求若重新设计可引入批量提交或事务化策略以减少请求数量。整体链路在权限渲染、数据一致性与维护成本之间取得平衡为复杂业务场景下的角色权限管理提供了一套可复用的实现范式。

更多文章