管理台权限模块 - 完整路由权限及按钮权限

这篇文章主要讲的是动态路由添加,下篇我们再仔细说明一下按钮权限的做法,

  1. 本文基础框架在element-ui element-admin-template基础上进行的二次开发

动态路由权限:

首先这里我们应该想清楚我们要怎么去做这个动态路由,按照我对动态路由的理解,一般都是服务端储存路由数据,返回到客户端进行路由列表渲染,element-admin官方的根据角色权限渲染可能是另外一种方式,不过在我自己处理的前端框架中一般情况都是第一种方案,这里只是给大家提供一个思路,特殊情况的需要自己处理。

1 全局路由守卫添加如下代码

// 获取动态路由然后使用VUEX进行组织
const accessRoutes = await store.dispatch('permission/generateRoutes', menuList);

// 高版本vue-router使用addRoute 方法,低版本则使用 addRoutes
accessRoutes.forEach(item => {
    router.addRoute(item)
})

这里我们先看下这个menuList的返回格式 下图中这个是单条数据格式,我解释下关键的几个字段,首先是id(主键),然后是pid(父级ID),fullAuth(权限授权),path(命名路由),因为返回的并不是一棵树,所有我们接下来要进行实际的数据组织

{
  "description": "Dubbo管理",
  "createTime": "2021-10-13 18:46:15",
  "createBy": "c107e1f74d484b218bdf11341f5c048d",
  "deleteTime": null,
  "deleteBy": null,
  "updateBy": null,
  "updateTime": null,
  "isDel": "0",
  "id": "1a1f1e0f528d49399c0ead0fb92e6b1d",
  "pid": "b2e13293b744402081e023337a58b23e",
  "name": "Dubbo管理",
  "fkDicMenuType": "01", // 菜单类型 01 - 菜单, 02 - 按钮
  "fkDicMenuShow": "01", // 是否显示 01 - 是, 02 - 否
  "auth": "dubbo",
  "fullAuth": "system:dubbo",
  "path": "dubbo",
  "icon": null,
  "sort": 7,
  "fkModularId": "cafc9923d4404babada7ebcb90a2f377",
  "parent": null,
  "flag": true
}

2 组织原始数据

下面的代码不难看懂,递归一个树,为什么设置pid初始值为1呢,因为跟pid为1,这个要看后端的具体返回

function dataToTree(data, pid = '1') => {
  if (!data) return [];
  let res = [];
  let loopList = data.filter(ele => {
    return ele.pid == pid;
  })
  if (loopList && loopList.length) {
    let children = [];
    loopList.forEach(im => {
      children = utils.dataToTree(data, im.id);
      if (children && children.length) {
        im.children = children;
      } else {
        im.children = undefined;
      }
    })
    res.push(...loopList);
    return res;
  } else {
    return []
  }
}

3 修改原始数据

 这里我直接上代码,然后看注释

return new Promise(res => {
let accessedRoutes, originMenuList;
if (true || rootState.app.isPro) {
  // 过滤之前保存一份原始menu 用途是按钮权限获取
  originMenuList = lodash.cloneDeep(menuList);

  // 利用刚才的工具方法递归数据
  originMenuList = utils.dataToTree(originMenuList);

  // 组织树结构
  accessedRoutes = getMenuItems(asyncRoutes, menuList);

  // 过滤不显示的路由
  accessedRoutes = filterMenu(accessedRoutes);

  // 排序
  accessedRoutes = lodash.sortBy(accessedRoutes, it => {
    return it.sort;
  });
  console.log(accessedRoutes);

} else {
  accessedRoutes = asyncRoutes;
}

// 保存原始数据
commit('SET_ORIGINMENULIST', originMenuList)

// 添加目前的路由数据
commit('SET_ROUTES', accessedRoutes)

// 返回数据
res (accessedRoutes)
})

我们逐个分析这几个核心方法

  • getMenuItems

function getMenuItems(list, accessMenu) {

  if (!accessMenu || !accessMenu.length) return [];

  return list.map(item => {

    // 查找是否有当前路由

    let menu = accessMenu.find(it => {

      return it.path == item.name;

    });

    if (menu) {

      let {

        path,  

        alwaysShow, 

        meta,

        redirect,

        component,

        icon,

      } = item,

        {

          name,

          fkDicMenuType,

          fkDicMenuShow,

          auth,

          fullAuth,

          sort

        } = menu,

        children = undefined;

        let target = menu.path;

        // 如果数据有children 就进入递归方法传入item.children

      if (item.children && item.children.length > 0) {

        children = getMenuItems(item.children, accessMenu);

      };

      return {

        alwaysShow, // 遵循路由规则 不熟悉的童鞋可以去看下element-admin

        children, // 子集

        redirect, 

        component, // 当前路由的component

        path,  //  path路径

        meta: {

          title: name,  // 路由名称

          icon:meta.icon, // 路由图标 -- 根据自己的需求去改,后来我舍弃了,没必要

          affix: meta.affix  // 遵循路由规则 不熟悉的童鞋可以去看下element-admin

        },

        fkDicMenuShow,  // 路由是否显示

        fkDicMenuType, // 路由类型

        auth, 

        fullAuth, // 路由权限,用来处理按钮权限的标识

        sort,

        name: target

      };

    } else {

      // 这里就是为了我下一步过滤做准备

      return {

        fkDicMenuShow: '02'

      }

    }

  });

};

 到此呢我们就完成了基本的数据组装,可能有些童鞋会理解不了,精心思考就明白了,无非就是多了一个递归写法,如果有children就是找,接下来要做的事情就是过滤那些不展示的路由

  • filterMenu

function filterMenu(list){

  return list.filter((item) => {

      let children = undefined;

      if(item.children && item.children.length > 0){

          children = filterMenu(item.children);

          item.children = children;

          if (!children || children.length == 0) {

              return false;

          } else {

              return item.fkDicMenuShow == '01';

          }

      }else{

          return item.fkDicMenuShow == '01';

      }

  });

};

这段代码的作用就是将后端返回中不显示的菜单过滤掉,同样也是使用了递归方法

4 添加路由

我是在全局路由守卫中添加的

accessRoutes.forEach(item => {
    router.addRoute(item)
})

// 所有不存在的路由都是404
router.addRoute({ path: '*', redirect: '/404', hidden: true }); 

ok,大功告成!

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高效前端Hello World!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值