对vue-element-admin从后台动态查询菜单并生成路由信息的新思路

本文介绍如何在Vue项目中实现从后端动态获取路由信息,并通过权限控制显示相应页面。通过修改permission模块和user API,实现了根据用户角色动态加载路由的功能。

 

其实需求很简单,就是要 vue-element-admin 项目动态的调用接口,后台查询后返回给前端项目,符合你的权限范围内的页面!

 

(21条消息) 对vue-element-admin从后台动态查询菜单并生成路由信息_acoolper的专栏-优快云博客

如上的一篇文章,受益匪浅,成功实现了我的需求。

 

但是我遇到了一个文章末尾评论区的通用问题,让我很不爽。

component: () => import(`@/views${item.url}/index`),

我的代码这么写始终报 Module build failed (from ./node_modules/eslint-loader/index.js): TypeError: Cannot read property 'range' of null

 

让我想到了另外的方法,规避问题:那就是,前台维护好 asyncRoutes , 根据后台请求返回的数据,对 asyncRoutes 进行字段重置。

 

time to show code

第一处修改:src/store/modules/permission.js

import { asyncRoutes, constantRoutes } from '@/router'
import { getRoutes } from '@/api/user'
 
/**
 * 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
  }
}
 
/**
 * 将后台查询的 routes 数据合并到原始的 routes 数据
 * @param asyncRoutes 原始 routes 数据
 * @param loadRoutes 后台查询到的 routes 数据
 */
export function dealLoadRoutes(asyncRoutes, loadRoutes) {
  loadRoutes.forEach(loadRoute => {
    // console.log("dealLoadRoutes:" + JSON.stringify(loadRoute))
    dealLoadRoute(asyncRoutes, loadRoute)
  })
}

/**
 * 同级别节点数据合并( path 相同则认为可以合并)
 * @param asyncRoutes 原始 routes 数据
 * @param loadRoute 后台查询到的 routes 数据,单条
 */
export function dealLoadRoute(asyncRoutes, loadRoute) {
  asyncRoutes.forEach(asyncRoute =>{
    // 原始路由配置如果和后台查询到的路由配置path相同,则关键字段替换
    if(asyncRoute.path == loadRoute.path){
      asyncRoute.id = loadRoute.id
      asyncRoute.name = loadRoute.name
      asyncRoute.meta.title = loadRoute.meta.title
      asyncRoute.meta.icon = loadRoute.meta.icon
      asyncRoute.meta.roles = loadRoute.meta.roles
      console.log("path_match:"+JSON.stringify(asyncRoute))
      // 处理children
      if(asyncRoute.children){
        dealLoadRoutes(asyncRoute.children, loadRoute.children)
      }
    }
  })
}
 
/**
 * 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 => {
      const loadRoutes = []
      // 先查询后台菜单数据并把数据合并到路由
      getRoutes(state.token).then(response => {
        let data = response
        if (response.code != 20000) {
          this.$message({
            message: 'routes数据加载异常',
            type: 0
          })
        } else {
          data = response.data
          Object.assign(loadRoutes, data)
          dealLoadRoutes(asyncRoutes, loadRoutes)
          let accessedRoutes
          if (roles.includes('admin')) {
            // alert(JSON.stringify(asyncRoutes))
            accessedRoutes = asyncRoutes || []
          } else {
            accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
          }
          commit('SET_ROUTES', accessedRoutes)
          resolve(accessedRoutes)
        }
        // generaMenu(asyncRoutes, data)
      }).catch(error => {
        console.log(error)
      })
    })
  }
}
 
export default {
  namespaced: true,
  state,
  mutations,
  actions
}

 

第二处修改:src/api/user.js

import request from '@/utils/request'

export function login(data) {
  return request({
    url: '/vue-element-admin/user/login',
    method: 'post',
    data
  })
}

export function getInfo(token) {
  return request({
    url: '/vue-element-admin/user/info',
    method: 'get',
    params: { token }
  })
}

export function logout() {
  return request({
    url: '/vue-element-admin/user/logout',
    method: 'post'
  })
}

export function getRoutes(token) {
  return request({
    url: '/vue-element-admin/routes',
    method: 'get'
  })
}

 

仅仅如上的两处修改。

另外附加 /vue-element-admin/routes 请求返回的数据格式

{
    "code":20000,
    "data":[
        {
            "id":3,
            "path":"/permission",
            "meta":{
                "title":"权限控制",
                "icon":"lock",
                "roles":["editor"]
            },
            "children":[
                {
                    "id":4,
                    "path":"page",
                    "meta":{
                        "title":"My Page Permission",
                        "icon":null,
                        "roles":["editor","admin"]
                    },
                    "children":[]
                },
                {
                    "id":5,
                    "path":"directive",
                    "meta":{
                        "title":"My Directive Permission",
                        "icon":null,
                        "roles":["admin"]
                    },
                    "children":[]
                },
                {
                    "id":6,
                    "path":"role",
                    "meta":{
                        "title":"My Role Permission",
                        "icon":null,
                        "roles":["admin"]
                    },
                    "children":[]
                }
            ]
        }
    ],
    "message":"成功"
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值