vue 后台系统权限管理

前言

最近在做一个后台管理系统,一般的后台系统都有权限管理这块,下面我就分享下我实现权限管理这块的思路。

技术栈及实现思路

首先说下这个系统前端用到的技术栈,vue全家桶,element-ui,axios。首先,用户的权限是通过前端来进行配置的,那么就需要一个页面去进行用户的权限配置。在用户登录之后,通过请求后台查找该用户的权限信息,然后返回到前端。前端拿到权限信息之后,动态配置路由,再生成出对应的菜单列表。

如何进行权限配置

权限分配页面

毋庸置疑,权限是跟用户挂钩的。在用户管理页面,做一个授权页面。如下图:

树结构用的是element-ui里面的树形控件。生成这个树形菜单的数据源为前端配置好的默认的路由表。'icon’为菜单对应的图表,'index’为自定义的索引,用来配合这个树形控件生成权限信息。

export const homeRoute = {
  path: '/',
  component: index,
  redirect: '/home',
  children: []
};
export const routes = [
  {
    path: '/home',
    component: home,
    icon: 'el-icon-home',
    index: '1',
    name: '系统首页',
    disabled: true
  }, {
    path: '/list',
    component: list,
    icon: 'el-icon-tickets',
    name: '菜单1',
    redirect: '/list1',
    index: '2',
    children: [
      {
        path: '/list1',
        name: '菜单列表1',
        component: list1,
        index: '2-1'
      },
      {
        path: '/list2',
        name: '菜单列表2',
        component: list2,
        index: '2-2'
      }
    ]
  }, {
    path: '/userManage',
    component: userManage,
    icon: 'el-icon-ticket',
    name: '用户管理',
    index: '3'
  }
];

首页默认是所有用户都能查看的。当为改用户勾选对应的菜单后,则会生成一个数组,存储着选中的菜单列表,如:[‘1’, ‘2-1’, ‘3’, ‘2’, ‘2-2’]。

动态配置路由

我在main.js文件做了如下配置:

var per = true;
router.beforeEach((to, from, next) => {
  if (getStore('token') == null && to.path !== '/login') {
    next('/login');
  } else {
    if (from.path !== '/login') {
      if (per) {
        store.dispatch('setPermList').then(() => {
          per = false;
        });
      } else {
        next();
      }
    } else {
      next();
    }
  }
  next();
});

当页面每次刷新的时候(ps:定义per变量,就是为了防止每次进刷新的时候去dispatch,而是在页面刷新的时候去触发),去dispatch.状态管理的代码如下。首先拿到用户权限数组,然后分成一级菜单跟二级菜单两个数组。对一级菜单和默认的路由表进行遍历,筛选出有权限的路由表,再过滤掉一级路由里没有权限的二级路由。

const state = {
  permList: []
};
const getters = {
  permList: state => state.permList
};
const getters = {
  permList: state => state.permList
};
const actions = {
  setPermList ({commit}) {
    return new Promise(resolve => {
      api.getUserPerm().then(res => {
        let perm = res.data;
        // 一级菜单
        let oldParent = perm.filter(item => item.indexOf('-') < 0);
        // 一级菜单下的二级菜单
        let child = perm.filter(item => item.indexOf('-') > 0);
        // for (let c of child) {
        //   oldParent.push(c.split('-')[0]);
        // }
        child.map(c => {
          oldParent.push(c.split('-')[0]);
        });
        console.log(child);
        let newParent = [...new Set(oldParent)]; // 去重
        let routesList = [...new Set(routes)]; // 去重
        let parentArray = [];
        // 生成一级菜单
        newParent.map(
          item => {
            routesList.map(
              routesItem => {
                if (routesItem.index === item) {
                  let it = Object.assign({}, routesItem);
                  parentArray.push(it);
                }
              }
            );
          }
        );
        // 过滤掉一级菜单下的二级菜单
        for (let pItem of parentArray) {
          pItem.children = pItem.children ? pItem.children.filter(n => child.indexOf(n.index) != -1) : null;
        }
        homeRoute.children = parentArray;
        router.addRoutes([homeRoute]);
        commit(types.PERM_LIST, parentArray);
        resolve(perm);
      });
    });
  }
};
const mutations = {
  [types.PERM_LIST] (state, data) {
    state.permList = data;
  }
};

例如,当获取到的用户权限为:[‘1’, ‘2-1’, ‘3’],那么生成的路由为:

  {
    path: '/home',
    component: home,
    icon: 'el-icon-home',
    index: '1',
    name: '系统首页',
    disabled: true
  }, {
    path: '/list',
    component: list,
    icon: 'el-icon-tickets',
    name: '菜单1',
    redirect: '/list1',
    index: '2',
    children: [
      {
        path: '/list1',
        name: '菜单列表1',
        component: list1,
        index: '2-1'
      }
    ]
  }, {
    path: '/userManage',
    component: userManage,
    icon: 'el-icon-ticket',
    name: '用户管理',
    index: '3'
  }

根据路由生成首页菜单

路由数组都出来了,那么生成菜单就不在话下了。菜单也是用到了element-ui的菜单

  <div class="sidebar">
    <!-- default-active:当前激活菜单的index ,collapse:是否折叠-->
    <el-menu class="sidebar-el-menu" :default-active="onRoutes" :collapse="collapse" background-color="#324157" text-color="#bfcbd9" active-text-color="#20a0ff" unique-opened router>
       <!--每个菜单项-->
       <template v-for="item in permList">
           <!--二级子菜单-->
            <template v-if="item.children">
                <el-submenu :index="item.path" :key="item.path">
                    <template slot="title">
                        <i :class="item.icon"></i>
                        <span slot="title">{{ item.name }}</span>
                    </template>
                    <template v-for="subItem in item.children">
                        <!--v-if,v-else:条件选择,加key属性会重新渲染-->
                        <el-submenu v-if="subItem.children" :index="subItem.path" :key="subItem.path">
                            <template slot="title">{{ subItem.name }}</template>
                            <el-menu-item v-for="(threeItem,i) in subItem.children" :key="i" :index="threeItem.path">
                                {{ threeItem.name }}
                            </el-menu-item>
                       </el-submenu>
                       <!--没有三级子菜单,所以全部走else条件-->
                        <el-menu-item v-else :index="subItem.path" :key="subItem.path">
                            {{ subItem.name }}
                        </el-menu-item>
                    </template>
                </el-submenu>
            </template>
            <template v-else>
                <el-menu-item :index="item.path" :key="item.path">
                    <i :class="item.icon"></i>
                    <span slot="title">{{ item.name }}</span>
                </el-menu-item>
            </template>
            </template>
    </el-menu>
  </div>

生成的菜单如下:

补充

我在网上查阅到的后台权限管理,都是跟角色挂钩的,无法满足我的需求,于是在反复思考下想到了这样的做法,有些不足的地方还需要继续补充和完善。例如:目前在菜单级别上,只是做了一二级菜单,没有三级菜单。在状态管理生成新的路由的代码片段感觉写的有点繁琐,有待优化。希望大家能提出意见,想要看源码的可以私聊我。原文地址:https://juejin.im/post/5c08c3ece51d451dde1b0c08

  • 3
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值