Vue3 custom instruction to implement button permissions

1. Prerequisites

After the login is successful, the backend directly returns all the permissions of the user (routing permissions + button permissions). On the basis of the menu permissions that have been realized, the button permissions of each page are realized. The tree data structure is as follows:

{
    "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",                           "isHide": false,                           "title": "Sync Data",
                        "meta": {


                          "roles": [
                            "screen:firstScreen:loadingData"
                          ],
                          "icon": ""
                        },
                        "children": [],
                    },
                  ],
              },
            ],
        },
    ],             
}

 

2. Implementation ideas

Obtain the permission of the current routing page, filter out all the button permissions of the current routing page, judge whether a button has permission, and set it to display:none through css if there is no permission

Three, specific implementation steps (vue3+ts)

1. Create a new directive file under the src file, and create a new btnPermission.ts file in the directive file

The specific directory structure is as follows:

2. In 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. Register custom directives in index.ts under the directive file

import type { App } from 'vue';
import { btnPermission } from '/@/directive/btnPermission';

/**
 * 导出指令方法:v-xxx
 * @methods btnPermission 按钮权限指令,用法:v-btnPermission
 */

export function directive(app: App) {
  // 按钮权限指令
  btnPermission(app)
}

 4. Use in the target page

  // v-btnPermission="'按钮权限的name值'",真实项目中的字段取用自行与后端协商
  <el-button size="default" v-btnPermission="'loadingData'" type="primary"
          @click="handleSubmit">同步数据</el-button>

Guess you like

Origin blog.csdn.net/weixin_48082900/article/details/131377057