Vue3.5 企业级管理系统实战(二十):角色菜单

本篇聚焦于角色菜单权限分配功能的实现,围绕“给角色赋予菜单权限”这一核心场景,从接口设计、组件封装到页面集成展开完整技术方案的阐述。主要内容包括:

1. 角色权限接口开发:定义获取角色权限、分配权限等接口,规范数据交互格式;

2. 权限分配组件封装:实现基于树形结构的可视化权限配置组件,支持全选、父子节点联动控制等功能;

3. 角色管理页面集成:新增“菜单权限”操作按钮,通过组件化方式关联权限分配逻辑。 

 1 角色权限 api

在 src/api/roleAccess.ts 中添加角色权限相关 api,代码如下:

//src/api/roleAccess.ts 
import service from "./config/request";
import type { ApiResponse } from "./type";export interface IRoleAccess {id: number;access_id: number;role_id: number;
}export type IRoleAccessList = IRoleAccess[];// 获取角色对应权限
export const getRoleAccess = (id: number
): Promise<ApiResponse<IRoleAccessList>> => {return service.get(`/role_access/${id}`);
};// 给角色分配权限
export const allocRoleAccess = (id: number,data: number[]
): Promise<ApiResponse> => {return service.post(`/role_access/${id}`, {access: data});
};// 获取角色对应权限
export const getRoleAccessByRoles = (roles: number[]
): Promise<ApiResponse<any>> => {return service.post(`/role_access/role/access`, {roles});
};

2 封装 RoleMenu 组件

在 /src/views/system/role/components/roleMenu.vue 中封装角色菜单分配组件,代码如下:

//src/views/system/role/components/roleMenu.vue 
<template><el-dialog v-model="dialogVisible"><!-- 权限树组件,展示菜单结构并支持勾选 --><el-tree:data="treeData"show-checkbox:props="defaultProps":default-expand-all="true"highlight-currentref="menuTree"node-key="id":check-strictly="checkStrictly"></el-tree><template #footer><el-button type="primary" @click="handleCheckAll">全部选择</el-button><el-button type="warning" @click="handleSubmit">确认分配</el-button></template></el-dialog>
</template><script lang="ts" setup>
import type { IRole } from "@/api/role";
import { useMenuStore } from "@/stores/menu";
import type { PropType } from "vue";
import { ElTree } from "element-plus";
import Node from "element-plus/es/components/tree/src/model/node.mjs";
import { allocRoleAccess, getRoleAccess } from "@/api/roleAccess";
import { useReloadPage } from "@/hooks/useReloadPage";// 是否父子节点关联(true:不关联,false:关联)
const checkStrictly = ref(false);
const { reloadPage } = useReloadPage();
const store = useMenuStore();
// 从菜单存储获取树形菜单数据
const treeData = computed(() => store.state.menuTreeData);// 生命周期钩子:组件挂载后获取所有菜单数据
onMounted(() => {store.getAllMenuList();
});// 树组件配置项,指定子节点和标签字段
const defaultProps = {children: "children",label: "title"
};// 树组件实例类型和引用
type ElTreeInstance = InstanceType<typeof ElTree>;
const menuTree = ref<ElTreeInstance | null>(null);// 全选状态标识
const isCheckAll = ref(false);/*** 全选/取消全选处理函数*/
const handleCheckAll = () => {if (!isCheckAll.value) {// 设置所有节点为选中状态menuTree.value?.setCheckedNodes(treeData.value as unknown as Node[], false);} else {// 取消所有选中状态menuTree.value?.setCheckedNodes([], false);}isCheckAll.value = !isCheckAll.value;
};const { proxy } = getCurrentInstance()!;/*** 提交权限分配处理函数*/
const handleSubmit = async () => {const tree = menuTree.value!;// 获取所有选中的节点IDconst keys = tree.getCheckedKeys(false);// 获取半选中的节点ID(部分子节点被选中)const halfKeys = tree.getHalfCheckedKeys();const selectKeys = [...keys, ...halfKeys];// 调用API分配权限const res = await allocRoleAccess(role.id, selectKeys as number[]);if (res.code === 0) {proxy?.$message.success("权限分配成功");reloadPage(); // 刷新页面}
};// 定义组件接收的props
const { role, modelValue } = defineProps({role: {type: Object as PropType<IRole>,required: true},modelValue: {type: Boolean,default: false}
});// 对话框显示状态
const dialogVisible = ref(modelValue);
// 定义自定义事件
const emit = defineEmits(["update:modelValue"]);// 监听对话框显示状态变化,触发自定义事件
watch(() => dialogVisible.value,(newValue) => {emit("update:modelValue", newValue);}
);/*** 获取角色已分配的权限列表*/
const getRoleAccessList = async () => {checkStrictly.value = true; // 临时解除父子节点关联,避免联动问题const res = await getRoleAccess(role.id);if (res.code === 0) {const access = res.data.map((item) => item.access_id);// 设置已选中的权限节点menuTree.value?.setCheckedKeys(access);// 异步恢复父子节点关联setTimeout(() => {checkStrictly.value = false;}, 0);}
};// 生命周期钩子:组件挂载后获取角色权限
onMounted(() => {getRoleAccessList();
});
</script>

3 修改角色管理页面

修改 src/views/system/role/index.vue,添加角色菜单权限,如图所示:

代码如下:

//src/views/system/role/index.vue
<template><div p-30px><h2>角色管理</h2><el-button @click="hanleAddRole">角色添加</el-button><el-table :data="roles" style="width: 100%"><el-table-column prop="id" label="角色id" width="180" /><el-table-column prop="name" label="角色名称" width="180" /><el-table-column prop="description" label="描述" /><el-table-columnprop="is_default"label=" 默认角色":formatter="formatter"/><el-table-column label="操作" fixed="right"><template #default="scope"><el-button link @click="handleRoleMenu(scope.row)">菜单权限</el-button><el-button link @click="handleEditRole(scope.row)">编辑</el-button><el-button link @click="handleRemove(scope.row)">删除</el-button></template></el-table-column></el-table><el-pagination:page-sizes="[1, 5, 10, 20]"layout="prev, pager, next, sizes, total":total="count":page-size="pageSize"@size-change="handleSizeChange"@current-change="handleCurrentChange"/><!-- 右侧面板组件,使用 v-model 绑定 visible 控制显示隐藏,设置标题 --><right-panel v-model="visible" :title="panelTitle"><!-- 角色编辑组件,传递编辑类型和编辑数据,监听 submit 事件 --><editor-role:type="editType":data="editData"@submit="handleSubmit"></editor-role></right-panel><role-menu:role="roleData"v-model="roleMenuVisible"v-if="roleMenuVisible && roleData"></role-menu></div>
</template><script lang="ts" setup>
import type { IRole } from "@/api/role";
import { useRoleStore } from "@/stores/role";
import { useRoleHelpers } from "./roleHelpers";
import { ref, toRefs, watchEffect } from "vue";const roleData = ref<IRole | null>(null);
const roleMenuVisible = ref(false);
const handleRoleMenu = (row: IRole) => {roleMenuVisible.value = true;roleData.value = row;
};// 获取角色状态管理仓库实例
const store = useRoleStore();
// 当前页码,初始为 0
const pageNum = ref(0);
// 每页显示的记录数,初始为 10
const pageSize = ref(10);// 从 useRoleHelpers 组合式函数中解构出所需的方法和状态
const {handleSubmit,handleRemove,handleEditRole,hanleAddRole,panelTitle,editType,visible,editData
} = useRoleHelpers({ pageNum, pageSize });// 将仓库状态中的 count 和 roles 转换为响应式引用
const { count, roles } = toRefs(store.state);// 监听 pageNum 和 pageSize 的变化,当变化时重新获取角色数据
watchEffect(() => {store.getRoles({ pageNum: pageNum.value, pageSize: pageSize.value, flag: 0 });
});// 处理每页显示记录数改变的方法
const handleSizeChange = (val: number) => {pageSize.value = val;
};// 处理当前页码改变的方法
const handleCurrentChange = (val: number) => {pageNum.value = val - 1;
};// 格式化是否为默认角色的显示内容
const formatter = (row: IRole) => {return row.is_default ? "是" : "否";
};
</script>

以上,就是角色菜单的相关内容。

下一篇将继续探讨 菜单权限实现,敬请期待~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/news/907096.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

go实现钉钉三方登录

钉钉的的官方开发文档中只给出了java实现三方登录的&#xff0c;我们准备用go语言来实现 实现网页方式登录应用&#xff08;登录第三方网站&#xff09; - 钉钉开放平台 首先就是按照文档进行操作&#xff0c;备注好网站的信息 获得应用凭证&#xff0c;我们后面会用到 之后…

一、OpenCV的基本操作

目录 1、OpenCV的模块 2、OpenCV的基础操作 2.1图像的IO操作 2.2绘制几何图形 2.3获取并修改图像中的像素点 2.4 获取图像的属性 2.5图像通道的拆分与合并 2.6色彩空间的改变 3、OpenCV的算数操作 3.1图像的加法 3.2图像的混合 3.3总结 1、OpenCV的模块 2、OpenCV的基…

虚拟机配置桥接,远程工具直接访问

虚拟机网络配置 前言windows下安装linux虚拟机配置网络1、设置虚拟机网络模式&#xff1a;桥接模式2、配置网络参数1、查看本机电脑连接的网络情况2、打开虚拟机&#xff0c;编辑配置文件3、编辑虚拟网络 3、测试连通性 前言 好不容易装上了虚拟机&#xff0c;输入命令时又发现…

RabbitMQ 概述与安装

MQ 作用与介绍 MQ 是什么 MQ (message queue),从字面意思看是一个队列, FIFO 先进先出,只不过里面存放的内容是 消息 消息 可以比较简单,比如只包含 文本字符串,JSON 等;也可以很复杂,比如 内嵌对象 等 MQ 多用于分布式系统之间进行通信 系统之间的调用通常有两种方式: 1…

如何在Vue中实现延迟刷新列表:以Element UI的el-switch为例

如何在Vue中实现延迟刷新列表&#xff1a;以Element UI的el-switch为例 在开发过程中&#xff0c;我们经常需要根据用户操作或接口响应结果来更新页面数据。本文将以Element UI中的el-switch组件为例&#xff0c;介绍如何在状态切换后延迟1秒钟再调用刷新列表的方法&#xff0…

CSS2相关知识点

CSS2相关知识点 CSS的编写位置样式种类样式表的优先级 CSS选择器CSS基本选择器通配选择器元素选择器类选择器ID选择器 复合选择器HTML元素间的关系交集选择器并集选择器后代选择器子代选择器兄弟选择器属性选择器伪类选择器伪元素选择器 颜色的表示表示方式一&#xff1a;颜色名…

centos yum源,docker源

yum源repo文件&#xff1a; wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repodocker源repo文件&#xff1a; yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo安装docker和docker c…

深入探索AI模型工程:算法三大门派与监督学习的魅力

在当今人工智能蓬勃发展的时代&#xff0c;AI系统正逐渐渗透到我们生活的方方面面。从智能语音助手到自动驾驶汽车&#xff0c;从医疗影像诊断到金融风险预测&#xff0c;AI的应用场景无处不在。然而&#xff0c;构建一个高效、可靠的AI系统并非易事&#xff0c;它需要我们从宏…

[De1CTF 2019]SSRF Me

算是我第一次正儿八经的分析python代码了 from flask import Flask, request import socket import hashlib import urllib import sys import os import jsonreload(sys) sys.setdefaultencoding(latin1)app Flask(__name__) # 创建一个Flask应用实例 secret_key os.ura…

Halcon 图像预处理②

非线性图像分段变化&#xff1a; 先窗体打开图片 对数非线性变化&#xff1a; 结果图像的亮度/对比度显著增加 log_image(Image,LogImag1,e) 参数1&#xff1a;输入图像 参数2&#xff1a; 输出图像 参数3&#xff1a;底数 log_image(Image,LogImage2,0.1) 图像结果亮度和…

云原生安全之网络IP协议:从基础到实践指南

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 IP协议&#xff08;Internet Protocol&#xff09;是互联网通信的核心协议族之一&#xff0c;负责在设备间传递数据包。其核心特性包括&…

QML学习08Text

Text 1、颜色&#xff08;color&#xff09;2、获取宽度和高度&#xff08;contentWidth、contentHeight&#xff09;3、字体格式&#xff08;font&#xff09;4、文本样式&#xff08;textFormat&#xff09;5、超链接 1、颜色&#xff08;color&#xff09; //颜色Text {colo…

Python网络编程深度解析

目录 一、网络编程概述 二、TCP与UDP协议详解 1.TCP协议&#xff1a;可靠传输的基石 2.UDP协议&#xff1a;高效但不可靠的传输 3. TCP与UDP对比 三、Socket编程模型 1. Socket基础 2.TCP服务器实现详解 3. UDP服务器实现详解 四、进阶应用&#xff1a;简易聊天程序 …

ElasticSearch导读

ElasticSearch 简介&#xff1a;ElasticSearch简称ES是一个开源的分布式搜素和数据分析引擎。是使用Java开发并且是当前最流行的开源的企业级搜索引擎&#xff0c;能够达到近实时搜索&#xff0c;它专门设计用于处理大规模的文本数据和实现高性能的全文搜索。它基于 Apache Luc…

【后端高阶面经:数据库篇】18、分布式事务:如何在分库分表中实现高性能与一致性?

一、分布式事务核心挑战:分库分表下的一致性困境 在分布式系统架构中,分库分表通过将数据分散存储提升了扩展性和性能,但却打破了传统单库事务的边界,使得分布式事务成为保障数据一致性的核心难题。其挑战主要体现在以下三方面: 1.1 ACID特性的分布式撕裂 原子性(Atomi…

Tailwind css实战,基于Kooboo构建AI对话框页面(一)

在当今数字化时代&#xff0c;AI 助手已成为网站和应用不可或缺的一部分。本文将带你一步步使用 Tailwind CSS 和 Kooboo 构建一个现代化的 AI 对话界面框。 一、选择 Kooboo平台 的核心优势 智能提示&#xff1a;在输入 class 属性时&#xff0c;会自动触发 Tailwind CSS 规则…

python学习day2:进制+码制+逻辑运算符

进制 Python 中的进制表示与转换 进制的基本概念 二进制、八进制、十进制、十六进制的定义与特点不同进制在计算机科学中的应用场景 Python 中的进制表示 二进制表示&#xff1a;使用 0b 前缀八进制表示&#xff1a;使用 0o 前缀十六进制表示&#xff1a;使用 0x 前缀示例…

ROS2学习(11)------ROS2通信接口

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 ROS版本&#xff1a;2 ROS 2 提供了多种通信接口&#xff0c;用于节点之间的数据交换。这些接口主要包括话题&#xff08;Topics&#xff09;、服务&#xff08;Services&#xff09;、动作&…

STM32G0xx基于串口(UART)Ymodem协议实现OTA升级包括Bootloader、上位机、应用程序

STM32G0xx基于串口Ymodem协议实现OTA升级包括Bootloader、上位机、应用程序 例程说明一、串口相关的底层配置二、OTA相关的应用层三、Flash相关的操作四、Flash存储参数相关五、核心部分Ymodem相关六、其他宏配置七、主函数八、使用Python合并文件九、测试结果有疑问欢迎加交流…

Jenkins实践(6):配置“构建历史的显示名称,加上包名等信息“

Jenkins实践(6):配置“构建历史的显示名称,加上包名等信息“ 版本:Jenkins 4.262.2 需求:想要在构建历史中展示,本次运行的是哪个版本或哪个包 操作步骤: 1、先安装插件Build Name and Description Setter 2、Set Build Name 3、构建历史处查看展示 插件特性说明 安装依赖…