实现admin用户可以看到所有的菜单
    image.png
    实现test用户看到只属于自己的菜单
    image.png

    整体逻辑:
    1.src\router\index.js constantRoutes 列表放公共路由,asyncRoutes 放所有的路由
    2.用户的登录的时候获取用户的role,然后跟asyncRoutes列表过滤属于自己的路由。
    3.router.addRoutes加载自己的路由
    4.vuex管理路由表,侧边栏渲染vuex里面的路由表

    src\router\index.js 新增异步路由asyncRoutes,404页面必须放异步路由最后面。

    1. import Vue from 'vue'
    2. import Router from 'vue-router'
    3. Vue.use(Router)
    4. /* Layout */
    5. import Layout from '@/layout'
    6. /**
    7. * Note: sub-menu only appear when route children.length >= 1
    8. * Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
    9. *
    10. * hidden: true if set true, item will not show in the sidebar(default is false)
    11. * alwaysShow: true if set true, will always show the root menu
    12. * if not set alwaysShow, when item has more than one children route,
    13. * it will becomes nested mode, otherwise not show the root menu
    14. * redirect: noRedirect if set noRedirect will no redirect in the breadcrumb
    15. * name:'router-name' the name is used by <keep-alive> (must set!!!)
    16. * meta : {
    17. roles: ['admin','editor'] control the page roles (you can set multiple roles)
    18. title: 'title' the name show in sidebar and breadcrumb (recommend set)
    19. icon: 'svg-name' the icon show in the sidebar
    20. breadcrumb: false if set false, the item will hidden in breadcrumb(default is true)
    21. activeMenu: '/example/list' if set path, the sidebar will highlight the path you set
    22. }
    23. */
    24. /**
    25. * constantRoutes
    26. * a base page that does not have permission requirements
    27. * all roles can be accessed
    28. */
    29. export const constantRoutes = [
    30. {
    31. path: '/login',
    32. component: () => import('@/views/login/index'),
    33. hidden: true
    34. },
    35. {
    36. path: '/404',
    37. component: () => import('@/views/404'),
    38. hidden: true
    39. },
    40. {
    41. path: '/403',
    42. component: () => import('@/views/403'),
    43. hidden: true
    44. },
    45. {
    46. path: '/',
    47. component: Layout,
    48. redirect: '/dashboard',
    49. children: [{
    50. path: 'dashboard',
    51. name: 'Dashboard',
    52. component: () => import('@/views/dashboard/index'),
    53. meta: { title: 'dashboard', icon: 'dashboard' }
    54. }]
    55. }
    56. ]
    57. export const asyncRoutes = [
    58. {
    59. path: '/example',
    60. component: Layout,
    61. redirect: '/example/table',
    62. name: 'Example',
    63. meta: { title: 'Example', icon: 'example', roles: ['admin', 'test'] },
    64. children: [
    65. {
    66. path: 'table',
    67. name: 'Table',
    68. component: () => import('@/views/table/index'),
    69. meta: { title: 'Table', icon: 'table', roles: ['admin'] }
    70. },
    71. {
    72. path: 'tree',
    73. name: 'Tree',
    74. component: () => import('@/views/tree/index'),
    75. meta: { title: 'Tree', icon: 'tree' }
    76. }
    77. ]
    78. },
    79. {
    80. path: '/article',
    81. component: Layout,
    82. children: [
    83. {
    84. path: 'index',
    85. name: 'Article',
    86. component: () => import('@/views/article/index'),
    87. meta: { title: '文章管理', icon: 'form', roles: ['admin'] }
    88. }
    89. ]
    90. },
    91. {
    92. path: '/svn',
    93. component: Layout,
    94. children: [
    95. {
    96. path: 'index',
    97. name: 'Svn',
    98. component: () => import('@/views/svn/index'),
    99. meta: { title: 'SVN用户管理', icon: 'form', roles: ['admin'] }
    100. }
    101. ]
    102. },
    103. // {
    104. // path: 'external-link',
    105. // component: Layout,
    106. // children: [
    107. // {
    108. // path: 'https://panjiachen.github.io/vue-element-admin-site/#/',
    109. // meta: { title: '外部链接', icon: 'link', roles: ['test'] }
    110. // }
    111. // ]
    112. // },
    113. // {
    114. // path: '/form',
    115. // component: Layout,
    116. // children: [
    117. // {
    118. // path: 'index',
    119. // name: 'Form',
    120. // component: () => import('@/views/form/index'),
    121. // meta: { title: 'Form', icon: 'form' }
    122. // }
    123. // ]
    124. // },
    125. // {
    126. // path: '/nested',
    127. // component: Layout,
    128. // redirect: '/nested/menu1',
    129. // name: 'Nested',
    130. // meta: {
    131. // title: 'Nested',
    132. // icon: 'nested'
    133. // },
    134. // children: [
    135. // {
    136. // path: 'menu1',
    137. // component: () => import('@/views/nested/menu1/index'), // Parent router-view
    138. // name: 'Menu1',
    139. // meta: { title: 'Menu1' },
    140. // children: [
    141. // {
    142. // path: 'menu1-1',
    143. // component: () => import('@/views/nested/menu1/menu1-1'),
    144. // name: 'Menu1-1',
    145. // meta: { title: 'Menu1-1' }
    146. // },
    147. // {
    148. // path: 'menu1-2',
    149. // component: () => import('@/views/nested/menu1/menu1-2'),
    150. // name: 'Menu1-2',
    151. // meta: { title: 'Menu1-2' },
    152. // children: [
    153. // {
    154. // path: 'menu1-2-1',
    155. // component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1'),
    156. // name: 'Menu1-2-1',
    157. // meta: { title: 'Menu1-2-1' }
    158. // },
    159. // {
    160. // path: 'menu1-2-2',
    161. // component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2'),
    162. // name: 'Menu1-2-2',
    163. // meta: { title: 'Menu1-2-2' }
    164. // }
    165. // ]
    166. // },
    167. // {
    168. // path: 'menu1-3',
    169. // component: () => import('@/views/nested/menu1/menu1-3'),
    170. // name: 'Menu1-3',
    171. // meta: { title: 'Menu1-3' }
    172. // }
    173. // ]
    174. // },
    175. // {
    176. // path: 'menu2',
    177. // component: () => import('@/views/nested/menu2/index'),
    178. // meta: { title: 'menu2' }
    179. // }
    180. // ]
    181. // },
    182. // 404 page must be placed at the end !!!
    183. { path: '*', redirect: '/404', hidden: true }
    184. ]
    185. const createRouter = () => new Router({
    186. // mode: 'history', // require service support
    187. scrollBehavior: () => ({ y: 0 }), // 当切换到新路由时,想要页面滚到顶部
    188. routes: constantRoutes
    189. })
    190. const router = createRouter()
    191. // Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
    192. export function resetRouter() {
    193. const newRouter = createRouter()
    194. router.matcher = newRouter.matcher // reset router
    195. }
    196. export default router

    src\store\modules\user.js
    state新增roles: []
    mutations新增SET_ROLES
    image.png

        // 当前用户的权限<br />        constroles = data.Roles<br />        commit('SET_ROLES', roles)<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1414647/1636615318819-55a2bdc4-1aa1-4288-ab6b-49d10e582b97.png#clientId=u82fd9659-c7cd-4&from=paste&height=488&id=u2ba680f9&margin=%5Bobject%20Object%5D&name=image.png&originHeight=488&originWidth=1510&originalType=binary&ratio=1&size=68811&status=done&style=none&taskId=u734ee731-3415-4b7c-9124-7abb3ecbb72&width=1510)<br />        commit('SET_ROLES', '')<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1414647/1636615365529-d38bd707-3ec1-4380-bfdd-c01445f43f6a.png#clientId=u82fd9659-c7cd-4&from=paste&height=296&id=u2b149cf2&margin=%5Bobject%20Object%5D&name=image.png&originHeight=296&originWidth=1341&originalType=binary&ratio=1&size=36253&status=done&style=none&taskId=ucd92147e-313b-403e-bfd8-417f98dcb53&width=1341)
    
    import { login, logout, getInfo, refreshToken } from '@/api/user'
    import { getToken, setToken, removeToken, getTokenExpire, setTokenExpire, removeTokenExpire } from '@/utils/auth'
    import { resetRouter } from '@/router'
    
    const state = {
      token: getToken(),
      name: '',
      avatar: '',
      tokenExpire: getTokenExpire(),
      roles: []
    }
    
    const mutations = {
      SET_TOKEN: (state, token) => {
        state.token = token
      },
      SET_NAME: (state, name) => {
        state.name = name
      },
      SET_AVATAR: (state, avatar) => {
        state.avatar = avatar
      },
      SET_TOKENEXPIRE: (state, token) => {
        state.tokenExpire = token
      },
      SET_ROLES: (state, roles) => {
        state.roles = roles
      }
    }
    
    const actions = {
      // user login
      login({ commit }, userInfo) {
        const { username, password } = userInfo
        return new Promise((resolve, reject) => {
          login({ username: username.trim(), password: password }).then(response => {
            const data = response
            commit('SET_TOKEN', data.token)
            commit('SET_TOKENEXPIRE', data.expire)
            setToken(data.token)
            setTokenExpire(data.expire)
            resolve()
          }).catch(error => {
            reject(error)
          })
        })
      },
    
      refreshToken({ commit }) {
        return new Promise((resolve, reject) => {
          refreshToken().then(response => {
            const data = response
            commit('SET_TOKEN', data.token)
            commit('SET_TOKENEXPIRE', data.expire)
            setToken(data.token)
            setTokenExpire(data.expire)
            resolve()
          }).catch(error => {
            reject(error)
          })
        })
      },
    
      // get user info
      getInfo({ commit }) {
        return new Promise((resolve, reject) => {
          getInfo().then(response => {
            const data = response.data
            if (!data) {
              reject('Verification failed, please Login again.')
            }
            const { Name, Avatar } = data
            // 当前用户的权限
            const roles = data.Roles
            commit('SET_ROLES', roles)
            commit('SET_NAME', Name)
            commit('SET_AVATAR', Avatar)
            resolve(data)
          }).catch(error => {
            reject(error)
          })
        })
      },
    
      // user logout
      logout({ commit, state }) {
        return new Promise((resolve, reject) => {
          logout(state.token).then(() => {
            commit('SET_TOKEN', '')
            commit('SET_ROLES', '')
            commit('SET_TOKENEXPIRE', '')
            removeToken()
            removeTokenExpire()
            resetRouter()
            resolve()
          }).catch(error => {
            reject(error)
          })
        })
      },
    
      // remove token
      resetToken({ commit }) {
        return new Promise(resolve => {
          commit('SET_ROLES', '')
          commit('SET_TOKEN', '')
          commit('SET_TOKENEXPIRE', '')
          removeToken()
          removeTokenExpire()
          resolve()
        })
      }
    }
    
    export default {
      namespaced: true,
      state,
      mutations,
      actions
    }
    

    src\store\getters.js
    image.png

    const getters = {
      sidebar: state => state.app.sidebar,
      device: state => state.app.device,
      token: state => state.user.token,
      avatar: state => state.user.avatar,
      name: state => state.user.name,
      visitedViews: state => state.tagsView.visitedViews, // 这个是新增的
      cachedViews: state => state.tagsView.cachedViews, // 这个是新增的
      roles: state => state.user.roles,
      permission_routes: state => state.permission.routes
    }
    export default getters
    

    src\store\index.js
    modules新增permission
    image.png

    复制vue-admin完整文件到src\store\modules\permission.js

    import { asyncRoutes, constantRoutes } from '@/router'
    
    /**
     * Use meta.role to determine if the current user has permission
     * 使用 meta.role 判断当前用户是否有权限
     * @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) {
        return new Promise(resolve => {
          let accessedRoutes
          // admin 获得全部路由 这里可以写您的逻辑
          if (roles.includes('admin')) {
            accessedRoutes = asyncRoutes || []
          } else {
            accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
          }
          commit('SET_ROUTES', accessedRoutes)
          resolve(accessedRoutes)
        })
      }
    }
    
    export default {
      namespaced: true,
      state,
      mutations,
      actions
    }
    

    src\permission.js
    路由守卫文件在获取用户信息之后,异步挂在路由。
    awaitstore.dispatch(‘user/getInfo’)
    // 对应store/modules/user.js、根据登录的账号设置权限
    constroles = store.getters.roles
    // 可以访问的路由
    constaccessRoutes = awaitstore.dispatch(‘permission/generateRoutes’, roles)
    console.log(‘当前账号的权限页面(非公共页面)’, accessRoutes)
    router.addRoutes(accessRoutes)
    next({ …to, replace:true })
    image.png

    src\layout\components\Sidebar\index.vue
    最后修改侧边栏,循环路由
    image.png

    改为

    computed新增’permission_routes’
    image.png
    src\layout\components\Sidebar\index.vue

    <template>
      <div :class="{'has-logo':showLogo}">
        <logo v-if="showLogo" :collapse="isCollapse" />
        <el-scrollbar wrap-class="scrollbar-wrapper">
          <el-menu
            :default-active="activeMenu"
            :collapse="isCollapse"
            :background-color="variables.menuBg"
            :text-color="variables.menuText"
            :unique-opened="false"
            :active-text-color="variables.menuActiveText"
            :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 permission_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'
    
    export default {
      components: { SidebarItem, Logo },
      computed: {
        ...mapGetters([
          'sidebar',
          'permission_routes'
        ]),
        routes() {
          return this.$router.options.routes
        },
        activeMenu() {
          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 path
        },
        showLogo() {
          return this.$store.state.settings.sidebarLogo
        },
        variables() {
          return variables
        },
        isCollapse() {
          return !this.sidebar.opened
        }
      }
    }
    </script>
    

    至此实现了。。。。