vue-element-admin动态权限路由实现

vue-element-admin动态权限路由实现

这次项目的需求有个需要实现动态权限管理,所以需要动态路由,结合网上看到的以及自己实践出来的,做个小总结。
首先 vue-ele-admin 自带的权限管理是在路由表里写死的,在router/index.js中,asyncRoutes里通过roles属性可控制不同权限的人进入不同路由,但是我们现在得需求是动态的,路由是通过接口获取的,所以我们需要做些改动,具体有以下几点

1.在router/index中,constantRoutes保持不变,因为这些路由是所有用户均可以访问的,把原来的asyncRoutes删掉,新建dynamicRoutes,dynamicRoutes是这个项目里所有的路由,后面我们通过hidden属性来控制它是否显示,给每个路由增添一个url属性,一会请求后台接口的时候会把接口返回的数据与我们设置的url对比。

export const constantRoutes = [
  {
     
    path: '/redirect',
    component: Layout,
    hidden: true,
    children: [
      {
     
        path: '/redirect/:path(.*)',
        component: () => import('@/views/redirect/index')
      }
    ]
  },
  {
     
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true
  },
  {
     
    path: '/auth-redirect',
    component: () => import('@/views/login/auth-redirect'),
    hidden: true
  },
  {
     
    path: '/404',
    component: () => import('@/views/error-page/404'),
    hidden: true
  },
  {
     
    path: '/401',
    component: () => import('@/views/error-page/401'),
    hidden: true
  },
  {
     
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    children: [
      {
     
        path: 'dashboard',
        component: () => import('@/views/dashboard/index'),
        name: 'Dashboard',
        meta: {
      title: '系统主页', icon: 'dashboard' }
      }
    ]
  },
  {
     
    path: '/personal',
    component: Layout,
    hidden: true,
    children: [
      {
     
        path: 'person',
        component: () => import('@/views/person/index')
      }
    ]
  },
]
export const dynamicRoutes = [
  {
     
    path: '/device',
    component: Layout,
    redirect: '/device/index',
    name: 'Device',
    url:'/device',//here
    meta: {
     
      title: '设备管理',
      icon: 'lock',
    },
    children: [
      {
     
        path: 'index',
        component: () => import('@/views/device/dataView'),
        name: 'dataView',
        url: '/device/index',//here
        meta: {
     
          title: '数据指标',
        }
      },
      {
     
        path: 'deviceType',
        component: () => import('@/views/device/deviceType'),
        name: 'deviceType',
        url: '/device/deviceType',//here
        meta: {
     
          title: '设备类型',
         
        }
      },
      {
     
        path: 'deviceMonitor',
        component: () => import('@/views/device/deviceMonitor'),
        name: 'deviceMonitor',
        url: '/device/deviceMonitor',//here
        meta: {
     
          title: '设备监控'
         
        }
      }

    ]
  },
   // 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 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
}
export default router

2.在src/api下创建menu.js,请求后台数据

import request from '@/utils/request'
export function getMenus() {
     
  return request({
     
    url: '/api-user/func/my_menus',
    method: 'get',
  })

这个接口返回的数据即为我们能看到的页面,看不到的页面不返回,返回的数据格式如下

{
     "data":[{
     "id":1,"parentId":null,"funcName":"设备管理","url":"/device",,"childList":null},{
     "id":2,"parentId":null,"funcName":"数据指标","url":"/device/index",,"childList":null},{
     "id":3,"parentId":null,"funcName":"设备类型","url":"/device/deviceType",,"childList":null},{
     "id":4,"parentId":null,"funcName":"设备台账","url":"/device/deviceBook",,"childList":null},{
     "id":5,"parentId":null,"funcName":"设备监控","url":"/device/deviceMonitor",,"childList":null},{
     "id":6,"parentId":null,"funcName":"运维管理","url":"/management",,"childList":null},{
     "id":7,"parentId":null,"funcName":"报警列表","url":"/management/index",,"childList":null},{
     "id":8,"parentId":null,"funcName":"数据统计","url":"/management/dataToatl",,"childList":null},{
     "id":9,"parentId":null,"funcName":"客户管理","url":"/customer/index",,"childList":null},{
     "id":10,"parentId":null,"funcName":"系统设置","url":"/permission",,"childList":null},{
     "id":11,"parentId":null,"funcName":"用户管理","url":"/permission/page",,"childList":null},{
     "id":12,"parentId":null,"funcName":"角色管理","url":"/permission/role",,"childList":null},{
     "id":13,"parentId":null,"funcName":"操作日志","url":"/permission/directive",,"childList":null},{
     "id":14,"parentId":null,"funcName":"详情","url":"/device/deviceBook/detail",,"childList":null}],"code":0,"msg":"查询成功"}

3.在src/store/modules下新建menu.js,这个是为了把获得的路由表存进vuex中,并在里面对路由进行一些处理,menu.js内容如下

import {
      getMenus } from '@/api/menu'
import {
      getToken } from '@/utils/auth'
import {
      constantRoutes,dynamicRoutes } from '@/router/index'

const getDefaultState = () => {
     
  return {
     
    token: getToken(),
    menuList: []
  }
}

const state = getDefaultState()

const mutations = {
     
  SET_MENUS: (state, menu) => {
     
    state.menuList = menu
  }
}
// 动态菜单还是定义在前端,后台只会返回有权限的菜单列表,通过遍历我们预先在路由表里定义好的菜单数据,没有的将对于菜单进行隐藏
export function generaMenu(routes, srvMenus) {
     
  for (let i = 0; i < routes.length; i++) {
     
    const routeItem = routes[i]
    var showItem = false
    for (let j = 0; j < srvMenus.length; j++) {
     
      const srvItem = srvMenus[j]
      // 前后端数据通过 url 属性来匹配
      if (routeItem.url !== undefined && routeItem.url === srvItem.url) {
     
        showItem = true
        routes[i]['hidden'] = false
        break
      }
    }
    if (showItem === false) {
     
      routes[i]['hidden'] = true
    }

    if (routeItem['children'] !== undefined && routeItem['children'].length > 0) {
     
      generaMenu(routes[i]['children'], srvMenus)
    }
  }
}

const actions = {
     
 
  getMenus({
      commit }) {
     
    return new Promise((resolve, reject) => {
     
      getMenus(state.token).then(response => {
     
        const {
      data } = response
      
        console.log(response)
        if (!data) {
     
          reject('Verification failed, please Login again.')
        }

        const srvMenus = data
        let  pushRouter = dynamicRoutes
        generaMenu(pushRouter, srvMenus)
        commit('SET_MENUS', constantRoutes.concat(pushRouter))//将创建完成的路由表存在menuList中
        resolve(pushRouter)
      }).catch(error => {
     
        reject(error)
      })
    })
  }
}

export default {
     
  namespaced: true,
  state,
  mutations,
  actions
}

4.在stroe/getters.js 新增menuList: state => state.menu.menuList
5.在src/permission.js 中
vue-element-admin动态权限路由实现_第1张图片
这样现在登录应该可以进入首页了,但是进入首页发现侧边栏为什么为空,逻辑应该没问题啊,经过排查,在src/layout/Sidebar/index.vue中,
这里permission_routes应该改为我们生成的路由,代码如下

<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 menuList" :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([
      'menuList',
      'sidebar'
    ]),
    activeMenu() {
     
      const route = this.$route
      const {
      meta, path } = route
      // if set path, the sidebar will highlight the path you set
      if(path == '/device/deviceBook/detail' ){
      //侧边栏选择三级路由时一二级路由高亮
        return '/device/deviceBook'
      }
      if(path == '/management/index/detail'){
     
        return '/management/index'

      }
      if (meta.activeMenu) {
     
        return meta.activeMenu
      }
      return path
    },
    showLogo() {
     
      return this.$store.state.settings.sidebarLogo
    },
    variables() {
     
      return variables
    },
    isCollapse() {
     
      return !this.sidebar.opened
    }
  }
}
</script>

到这,动态路由已经好了,因为第一次做动态路由。走了很多歪路,在此记录一下。

你可能感兴趣的:(vue,javascript,vue.js)