一、需求前提
登录成功后,后端直接返回了用户的所有权限(路由权限+按钮权限),在已经实现菜单权限的基础上,实现每个页面的按钮权限,树形数据结构如下:
{
"roles": ["admin"],
"token": "12345678901234567890",
"userInfo": {
"id": "1",
"username": "system",
"nickName": "system",
"email": null,
"phoneNumber": "13131234567",
"sex": "1",
"avatar": null,
"userType": "1"
},
"menus": [
{
"id": "1",
"pid": "0",
"menuName": "home",
"type": 1,
"path": "/home",
"perms": "home",
"icon": "iconfont icon-shouye",
"sortNo": 0,
"selected": null,
"status": "0",
"title": "首页",
"redirect": "",
"visible": "0",
"remark": "首页",
"name": "home",
"meta": {
"title": "首页",
"isHide": false,
"roles": [
"home"
],
"icon": "iconfont icon-shouye",
"tagsViewName": "首页"
},
"children": [],
},
{
"id": "2",
"pid": "0",
"menuName": "screen",
"type": 1,
"path": "/screen",
"perms": "screen",
"icon": "iconfont icon-shuju",
"sortNo": 3,
"selected": null,
"status": "0",
"title": "信息大屏",
"redirect": null,
"visible": "0",
"remark": "信息大屏",
"name": "screen",
"meta": {
"title": "信息大屏",
"isHide": false,
"roles": [
"screen"
],
"icon": "iconfont icon-shuju"
},
"children": [
{
"id": "21",
"pid": "2",
"menuName": "firstScreen",
"type": 1,
"path": "/firstScreen",
"perms": "firstScreen",
"icon": "ele-FirstAidKit",
"sortNo": 0,
"selected": null,
"status": "0",
"title": "大屏1",
"redirect": null,
"visible": "0",
"remark": "大屏1",
"name": "firstScreen",
"meta": {
"title": "大屏1",
"isHide": false,
"roles": [
"firstScreen"
],
"icon": "ele-FirstAidKit"
},
"children": [
{
"id": "211",
"pid": "21",
"menuName": "loadingData",
"type": 2,
"path": "loadingData",
"component": "",
"perms": "screen:firstScreen:loadingData",
"icon": "",
"sortNo": 0,
"selected": null,
"status": "0",
"title": "同步数据",
"redirect": null,
"visible": "0",
"remark": "同步数据",
"name": "loadingData",
"meta": {
"title": "同步数据",
"isHide": false,
"roles": [
"screen:firstScreen:loadingData"
],
"icon": ""
},
"children": [],
},
],
},
],
},
],
}
二、实现思路
获取当前路由页面的权限,筛选出当前路由页面拥有的所有按钮权限,判断某个按钮是否拥有权限,没有权限就通过css设置为display:none
三、具体实现步骤(vue3+ts)
1.在src文件下新建directive文件,在directive文件中新建btnPermission.ts文件
具体目录结构如下:
2.在btnPermission.ts中
import type { App } from 'vue';
import { useUserInfo } from '/@/stores/userInfo';
/**
* 按钮权限指令-无按钮权限不显示
* @directive 单个按钮权限验证(v-btnPermission="xxx")
*/
export function btnPermission(app: App) {
app.directive('btnPermission', {
mounted(el, binding) {
// 1.从用户信息pinia中拿到用户信息(用户权限)
const stores = useUserInfo();
// 2.找到当前路由页面拥有的所有权限
const btnArr = filterPath(stores.userInfos.menus, window.location.hash.slice(1))
// 3.判断是否有当前按钮的权限,没有直接不显示
if (!btnArr.find((item: any) => item.name == binding.value)) {
el.style.display = 'none'
}
},
});
}
//递归工具函数---判断当前节点是否匹配目标路由
function filterPath(tree: any, path: string) {
for (let i = 0; i < tree.length; i++) {
const node = tree[i];
if (node.path == path) {
return node.children;
} else {
if (node.children && node.children.length > 0) {
const result: any = filterPath(node.children, path);
if (result) {
return result;
}
}
}
}
}
3.在directive文件下的index.ts中,注册自定义指令
import type { App } from 'vue';
import { btnPermission } from '/@/directive/btnPermission';
/**
* 导出指令方法:v-xxx
* @methods btnPermission 按钮权限指令,用法:v-btnPermission
*/
export function directive(app: App) {
// 按钮权限指令
btnPermission(app)
}
4.在目标页面中使用
// v-btnPermission="'按钮权限的name值'",真实项目中的字段取用自行与后端协商
<el-button size="default" v-btnPermission="'loadingData'" type="primary"
@click="handleSubmit">同步数据</el-button>