loki пре 3 година
родитељ
комит
27c7053561

+ 21 - 18
src/layout/components/Sidebar/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div :class="{'has-logo':showLogo}">
+  <div :class="{ 'has-logo': showLogo }">
     <logo v-if="showLogo" :collapse="isCollapse" />
     <el-scrollbar wrap-class="scrollbar-wrapper">
       <el-menu
@@ -12,45 +12,48 @@
         :collapse-transition="false"
         mode="vertical"
       >
-        <sidebar-item v-for="route in routes" :key="route.path" :item="route" :base-path="route.path" />
+        <sidebar-item
+          v-for="route in routes"
+          :key="route.path"
+          :item="route"
+          :base-path="route.path"
+        />
       </el-menu>
     </el-scrollbar>
   </div>
 </template>
 
 <script>
-import { mapGetters } from 'vuex'
-import Logo from './Logo'
-import SidebarItem from './SidebarItem'
-import variables from '@/styles/variables.scss'
+import { mapGetters } from 'vuex';
+import Logo from './Logo';
+import SidebarItem from './SidebarItem';
+import variables from '@/styles/variables.scss';
 
 export default {
   components: { SidebarItem, Logo },
   computed: {
-    ...mapGetters([
-      'sidebar'
-    ]),
+    ...mapGetters(['permission_routes', 'sidebar']),
     routes() {
-      return this.$router.options.routes
+      return this.$router.options.routes;
     },
     activeMenu() {
-      const route = this.$route
-      const { meta, path } = route
+      const route = this.$route;
+      const { meta, path } = route;
       // if set path, the sidebar will highlight the path you set
       if (meta.activeMenu) {
-        return meta.activeMenu
+        return meta.activeMenu;
       }
-      return path
+      return path;
     },
     showLogo() {
-      return this.$store.state.settings.sidebarLogo
+      return this.$store.state.settings.sidebarLogo;
     },
     variables() {
-      return variables
+      return variables;
     },
     isCollapse() {
-      return !this.sidebar.opened
+      return !this.sidebar.opened;
     }
   }
-}
+};
 </script>

+ 87 - 38
src/router/index.js

@@ -1,10 +1,10 @@
-import Vue from 'vue'
-import Router from 'vue-router'
+import Vue from 'vue';
+import Router from 'vue-router';
 
-Vue.use(Router)
+Vue.use(Router);
 
 /* Layout */
-import Layout from '@/layout'
+import Layout from '@/layout';
 
 /**
  * Note: sub-menu only appear when route children.length >= 1
@@ -47,12 +47,17 @@ export const constantRoutes = [
     path: '/',
     component: Layout,
     redirect: '/dashboard',
-    children: [{
-      path: 'dashboard',
-      name: 'Dashboard',
-      component: () => import('@/views/dashboard/index'),
-      meta: { title: 'Dashboard', icon: 'dashboard' }
-    }]
+    children: [
+      {
+        path: 'dashboard',
+        name: 'Dashboard',
+        component: () => import('@/views/dashboard/index'),
+        meta: {
+          title: 'Dashboard',
+          icon: 'dashboard'
+        }
+      }
+    ]
   },
 
   {
@@ -60,19 +65,28 @@ export const constantRoutes = [
     component: Layout,
     redirect: '/example/table',
     name: 'Example',
-    meta: { title: 'Example', icon: 'el-icon-s-help' },
+    meta: {
+      title: 'Example',
+      icon: 'el-icon-s-help'
+    },
     children: [
       {
         path: 'table',
         name: 'Table',
         component: () => import('@/views/table/index'),
-        meta: { title: 'Table', icon: 'table' }
+        meta: {
+          title: 'Table',
+          icon: 'table'
+        }
       },
       {
         path: 'tree',
         name: 'Tree',
         component: () => import('@/views/tree/index'),
-        meta: { title: 'Tree', icon: 'tree' }
+        meta: {
+          title: 'Tree',
+          icon: 'tree'
+        }
       }
     ]
   },
@@ -85,11 +99,27 @@ export const constantRoutes = [
         path: 'index',
         name: 'Form',
         component: () => import('@/views/form/index'),
-        meta: { title: 'Form', icon: 'form' }
+        meta: {
+          title: 'Form',
+          icon: 'form'
+        }
       }
     ]
   },
 
+  // 404 page must be placed at the end !!!
+  {
+    path: '*',
+    redirect: '/404',
+    hidden: true
+  }
+];
+
+/**
+ * asyncRoutes
+ * the routes that need to be dynamically loaded based on user roles
+ */
+export const asyncRoutes = [
   {
     path: '/nested',
     component: Layout,
@@ -104,31 +134,43 @@ export const constantRoutes = [
         path: 'menu1',
         component: () => import('@/views/nested/menu1/index'), // Parent router-view
         name: 'Menu1',
-        meta: { title: 'Menu1' },
+        meta: {
+          title: 'Menu1'
+        },
         children: [
           {
             path: 'menu1-1',
             component: () => import('@/views/nested/menu1/menu1-1'),
             name: 'Menu1-1',
-            meta: { title: 'Menu1-1' }
+            meta: {
+              title: 'Menu1-1'
+            }
           },
           {
             path: 'menu1-2',
             component: () => import('@/views/nested/menu1/menu1-2'),
             name: 'Menu1-2',
-            meta: { title: 'Menu1-2' },
+            meta: {
+              title: 'Menu1-2'
+            },
             children: [
               {
                 path: 'menu1-2-1',
-                component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1'),
+                component: () =>
+                  import('@/views/nested/menu1/menu1-2/menu1-2-1'),
                 name: 'Menu1-2-1',
-                meta: { title: 'Menu1-2-1' }
+                meta: {
+                  title: 'Menu1-2-1'
+                }
               },
               {
                 path: 'menu1-2-2',
-                component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2'),
+                component: () =>
+                  import('@/views/nested/menu1/menu1-2/menu1-2-2'),
                 name: 'Menu1-2-2',
-                meta: { title: 'Menu1-2-2' }
+                meta: {
+                  title: 'Menu1-2-2'
+                }
               }
             ]
           },
@@ -136,7 +178,9 @@ export const constantRoutes = [
             path: 'menu1-3',
             component: () => import('@/views/nested/menu1/menu1-3'),
             name: 'Menu1-3',
-            meta: { title: 'Menu1-3' }
+            meta: {
+              title: 'Menu1-3'
+            }
           }
         ]
       },
@@ -144,7 +188,9 @@ export const constantRoutes = [
         path: 'menu2',
         component: () => import('@/views/nested/menu2/index'),
         name: 'Menu2',
-        meta: { title: 'menu2' }
+        meta: {
+          title: 'menu2'
+        }
       }
     ]
   },
@@ -155,27 +201,30 @@ export const constantRoutes = [
     children: [
       {
         path: 'https://panjiachen.github.io/vue-element-admin-site/#/',
-        meta: { title: 'External Link', icon: 'link' }
+        meta: {
+          title: 'External Link',
+          icon: 'link'
+        }
       }
     ]
-  },
-
-  // 404 page must be placed at the end !!!
-  { path: '*', redirect: '/404', hidden: true }
-]
+  }
+];
 
-const createRouter = () => new Router({
-  // mode: 'history', // require service support
-  scrollBehavior: () => ({ y: 0 }),
-  routes: constantRoutes
-})
+const createRouter = () =>
+  new Router({
+    // mode: 'history', // require service support
+    scrollBehavior: () => ({
+      y: 0
+    }),
+    routes: constantRoutes
+  });
 
-const router = createRouter()
+const router = createRouter();
 
 // Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
 export function resetRouter() {
-  const newRouter = createRouter()
-  router.matcher = newRouter.matcher // reset router
+  const newRouter = createRouter();
+  router.matcher = newRouter.matcher; // reset router
 }
 
-export default router
+export default router;

+ 5 - 3
src/store/getters.js

@@ -3,6 +3,8 @@ const getters = {
   device: state => state.app.device,
   token: state => state.user.token,
   avatar: state => state.user.avatar,
-  name: state => state.user.name
-}
-export default getters
+  name: state => state.user.name,
+  roles: state => state.user.roles,
+  permission_routes: state => state.permission.routes
+};
+export default getters;

+ 20 - 14
src/store/index.js

@@ -1,19 +1,25 @@
-import Vue from 'vue'
-import Vuex from 'vuex'
-import getters from './getters'
-import app from './modules/app'
-import settings from './modules/settings'
-import user from './modules/user'
+import Vue from 'vue';
+import Vuex from 'vuex';
+import getters from './getters';
 
-Vue.use(Vuex)
+Vue.use(Vuex);
+
+// https://webpack.js.org/guides/dependency-management/#requirecontext
+const modulesFiles = require.context('./modules', true, /\.js$/);
+
+// you do not need `import app from './modules/app'`
+// it will auto require all vuex module from modules file
+const modules = modulesFiles.keys().reduce((modules, modulePath) => {
+  // set './app.js' => 'app'
+  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1');
+  const value = modulesFiles(modulePath);
+  modules[moduleName] = value.default;
+  return modules;
+}, {});
 
 const store = new Vuex.Store({
-  modules: {
-    app,
-    settings,
-    user
-  },
+  modules,
   getters
-})
+});
 
-export default store
+export default store;

+ 76 - 0
src/store/modules/permission.js

@@ -0,0 +1,76 @@
+import { asyncRoutes, constantRoutes } from '@/router';
+
+/**
+ * Use meta.role to determine if the current user has permission
+ * @param roles
+ * @param route
+ */
+function hasPermission(roles, route) {
+  if (route.meta && route.meta.roles) {
+    return roles.some(role => route.meta.roles.includes(role));
+  } else {
+    return true;
+  }
+}
+
+/**
+ * Filter asynchronous routing tables by recursion
+ * @param routes asyncRoutes
+ * @param roles
+ */
+export function filterAsyncRoutes(routes, roles) {
+  const res = [];
+
+  routes.forEach(route => {
+    const tmp = { ...route };
+    if (hasPermission(roles, tmp)) {
+      if (tmp.children) {
+        tmp.children = filterAsyncRoutes(tmp.children, roles);
+      }
+      res.push(tmp);
+    }
+  });
+
+  return res;
+}
+
+const state = {
+  routes: [],
+  addRoutes: []
+};
+
+const mutations = {
+  SET_ROUTES: (state, routes) => {
+    state.addRoutes = routes;
+    state.routes = constantRoutes.concat(routes);
+  }
+};
+
+const actions = {
+  generateRoutes({ commit }, roles) {
+    console.warn(roles);
+    return new Promise(resolve => {
+      let accessedRoutes = asyncRoutes;
+      commit('SET_ROUTES', []);
+      // commit('SET_ROUTES', accessedRoutes);
+      // resolve(accessedRoutes);
+    });
+    // return new Promise(resolve => {
+    //   let accessedRoutes = asyncRoutes;
+    //   if (roles.includes('admin')) {
+    //     accessedRoutes = asyncRoutes || [];
+    //   } else {
+    //     accessedRoutes = filterAsyncRoutes(asyncRoutes, roles);
+    //   }
+    //   commit('SET_ROUTES', accessedRoutes);
+    //   resolve(accessedRoutes);
+    // });
+  }
+};
+
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions
+};

+ 19 - 6
src/store/modules/user.js

@@ -1,12 +1,13 @@
 import { login, logout, getInfo } from '@/api/user';
 import { getToken, setToken, removeToken } from '@/utils/auth';
-import { resetRouter } from '@/router';
+import router, { resetRouter } from '@/router';
 
 const getDefaultState = () => {
   return {
     token: getToken(),
     name: '',
-    avatar: ''
+    avatar: '',
+    roles: []
   };
 };
 
@@ -22,6 +23,9 @@ const mutations = {
   SET_NAME: (state, name) => {
     state.name = name;
   },
+  SET_ROLES: (state, roles) => {
+    state.roles = roles;
+  },
   SET_AVATAR: (state, avatar) => {
     state.avatar = avatar;
   }
@@ -32,9 +36,11 @@ const actions = {
   login({ commit }, userInfo) {
     const { username, password } = userInfo;
     return new Promise((resolve, reject) => {
-      login({ username: username.trim(), password: password })
+      login({
+        username: username.trim(),
+        password: password
+      })
         .then(response => {
-          console.warn(response);
           const { data } = response;
           if (data.token) {
             commit('SET_TOKEN', data.token);
@@ -54,17 +60,22 @@ const actions = {
   getInfo({ commit, state }) {
     return new Promise((resolve, reject) => {
       getInfo(state.token)
-        .then(response => {
+        .then(async response => {
           const { data } = response;
 
           if (!data) {
             return reject('Verification failed, please Login again.');
           }
 
-          const { name, avatar } = data;
+          const { name, avatar, roles } = data;
 
+          // const roles = [];
+
+          commit('SET_ROLES', roles);
           commit('SET_NAME', name);
           commit('SET_AVATAR', avatar);
+
+          dispatch('permission/generateRoutes');
           resolve(data);
         })
         .catch(error => {
@@ -81,6 +92,7 @@ const actions = {
           removeToken(); // must remove  token  first
           resetRouter();
           commit('RESET_STATE');
+          commit('SET_ROLES', []);
           resolve();
         })
         .catch(error => {
@@ -94,6 +106,7 @@ const actions = {
     return new Promise(resolve => {
       removeToken(); // must remove  token  first
       commit('RESET_STATE');
+      commit('SET_ROLES', []);
       resolve();
     });
   }