vue 後臺系統權限管理

前言

最近在作一個後臺管理系統,通常的後臺系統都有權限管理這塊,下面我就分享下我實現權限管理這塊的思路。前端

技術棧及實現思路

首先說下這個系統前端用到的技術棧,vue全家桶,element-ui,axios。首先,用戶的權限是經過前端來進行配置的,那麼就須要一個頁面去進行用戶的權限配置。在用戶登陸以後,經過請求後臺查找該用戶的權限信息,而後返回到前端。前端拿到權限信息以後,動態配置路由,再生成出對應的菜單列表。vue

如何進行權限配置

權限分配頁面

毋庸置疑,權限是跟用戶掛鉤的。在用戶管理頁面,作一個受權頁面。以下圖: ios

樹結構用的是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']。element-ui

動態配置路由

我在main.js文件作了以下配置:axios

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.狀態管理的代碼以下。首先拿到用戶權限數組,而後分紅一級菜單跟二級菜單兩個數組。對一級菜單和默認的路由表進行遍歷,篩選出有權限的路由表,再過濾掉一級路由裏沒有權限的二級路由。api

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的菜單bash

<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>
複製代碼

生成的菜單以下:ide

補充

我在網上查閱到的後臺權限管理,都是跟角色掛鉤的,沒法知足個人需求,因而在反覆思考下想到了這樣的作法,有些不足的地方還須要繼續補充和完善。例如:目前在菜單級別上,只是作了一二級菜單,沒有三級菜單。在狀態管理生成新的路由的代碼片斷感受寫的有點繁瑣,有待優化。但願你們能提出意見。優化

相關文章
相關標籤/搜索