vue-element-admin默认是按照路由meta.role角色,动态匹配的。但通常是不灵活的。总不能每次设置一个角色,前端还要动态配置。
相对理想的状态,是后台配置一个用户,设置role权限,权限绑定了你需要的路由模块。

本文讲述如何根据后台路由,动态渲染后台管理系统菜单栏。

下载模板

链接

修改配置

只需要把原先根据role匹配路由的方式,换成接口获取路由就行
store/modules/perimission.js.

import { constantRoutes } from '@/router'
// import { getRouters } from '@/api/menu'
import Layout from '@/layout'

const permission = {
  namespaced: true,
  state: {
    routes: [],
    addRoutes: []
  },
  mutations: {
    SET_ROUTES: (state, routes) => {
      state.addRoutes = routes
      state.routes = constantRoutes.concat(routes)
    }
  },
  actions: {
    // 生成路由
    generateRoutes({ commit }) {
      return new Promise(resolve => {
        // 向后端请求路由数据 模拟数据在router.js中选择一份路由复制出来,测试
        const accessRoutes = [  
          {
            path: '/icon',
            component: 'Layout',
            children: [
              {
                path: 'index',
                component: 'icons/index',
                name: 'Icons',
                meta: { title: 'Icons', icon: 'icon', noCache: true }
              }
            ]
          }
        ]

        const accessedRoutes = filterAsyncRouter(accessRoutes)

        commit('SET_ROUTES', accessedRoutes) // 左侧页面展示
        resolve(accessedRoutes)  // 此处返回值 router.addRouter()
      })
    }
  }
}

// 遍历后台传来的路由字符串,转换为组件对象
function filterAsyncRouter(asyncRouterMap) {
  return asyncRouterMap.filter(route => {
    if (route.component) {
      // Layout组件特殊处理
      if (route.component === 'Layout') {
        route.component = Layout
      } else {
        route.component = loadView(route.component)
      }
    }
    if (route.children != null && route.children && route.children.length) {
      route.children = filterAsyncRouter(route.children)
    }
    return true
  })
}

// export const loadView = view => {
//
//   return () => import(`@/views/${view}`);
// };

export const loadView = view => {
  // 路由懒加载
  return resolve => require(['@/views/' + view], resolve)
}

export default permission

在这里插入图片描述

在这里插入图片描述

router/index.js 可以不改

asyncRoutes() 按照个人需求,要不要  一般情况下一个基本配置路由,还有一个就是动态路由了

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

现在运行,看看测试的路由能不能打开,不出意外,完工。

现在为止前端的工作就完成了,感兴趣的可以接着看后端配置(菜鸡一个,如果有好的建议,欢迎交流)

路由数据以此为例

        const accessRoutes = [
          {
            path: '/icon',
            component: 'Layout',
            children: [
              {
                path: 'index',
                component: 'icons/index',
                name: 'Icons',
                meta: { title: 'Icons', icon: 'icon', noCache: true }
              }
            ]
          },
          {
            path: '/nested',
            component: 'Layout',
            redirect: '/nested/menu1/menu1-1',
            name: 'Nested',
            meta: {
              title: 'Nested Routes',
              icon: 'nested'
            },
            children: [
              {
                path: 'menu1',
                component: 'nested/menu1/index', // Parent router-view
                name: 'Menu1',
                meta: { title: 'Menu 1' },
                redirect: '/nested/menu1/menu1-1',
                children: [
                  {
                    path: 'menu1-1',
                    component: 'nested/menu1/menu1-1',
                    name: 'Menu1-1',
                    meta: { title: 'Menu 1-1' }
                  },
                  {
                    path: 'menu1-2',
                    component: 'nested/menu1/menu1-2',
                    name: 'Menu1-2',
                    redirect: '/nested/menu1/menu1-2/menu1-2-1',
                    meta: { title: 'Menu 1-2' },
                    children: [
                      {
                        path: 'menu1-2-1',
                        component: 'nested/menu1/menu1-2/menu1-2-1',
                        name: 'Menu1-2-1',
                        meta: { title: 'Menu 1-2-1' }
                      },
                      {
                        path: 'menu1-2-2',
                        component: 'nested/menu1/menu1-2/menu1-2-2',
                        name: 'Menu1-2-2',
                        meta: { title: 'Menu 1-2-2' }
                      }
                    ]
                  },
                  {
                    path: 'menu1-3',
                    component: 'nested/menu1/menu1-3',
                    name: 'Menu1-3',
                    meta: { title: 'Menu 1-3' }
                  }
                ]
              },
              {
                path: 'menu2',
                name: 'Menu2',
                component: 'nested/menu2/index',
                meta: { title: 'Menu 2' }
              }
            ]
          }
        ]

表(具体字段可以根据实际业务)

'use strict';

module.exports = app => {
  const { STRING, INTEGER, BOOLEAN } = app.Sequelize;

  const AdminRouter = app.model.define(
    'adminRouter',
    {
      id: { type: INTEGER, primaryKey: true, autoIncrement: true },
      pid: { type: INTEGER, allowNull: true, defaultValue: null},
      name: { type: STRING},
      path: { type:STRING, content: '路由地址'},
      component: { type: STRING, content: '路由页面路径'},
      title: { type: STRING(30), allowNull: true},
      order: { type: INTEGER, defaultValue: 0 },
      icon: { type: STRING},
      hidden: { type: BOOLEAN, content: '是否显示路由'}
    },
    {
      tableName: 'adminRouter',
      
    }
  );
    AdminRouter.associate = function(){
    app.model.AdminRouter.hasMany(app.model.AdminRouter,{ as: 'children',foreignKey: 'pid', targetKey: 'id'})
  }  // 关联
  return AdminRouter;
};


录入资料(手动)
在这里插入图片描述
查找数据以树形返回数据就行
service.js

"use strict";

const Service = require("egg").Service;

class AdminRouterService extends Service {
  async findAll(pid,query) {
    const { ctx } = this;
    let rootRouter = await ctx.model.AdminRouter.findAll({
      where: {
        pid,
      },
      ...query,
      include: {
        model: ctx.model.AdminRouter,
        as: 'children',
        required: false,
        include: {
          all: true,
          nested: true
        }
      }
    });
    return rootRouter;
  }
}

module.exports = AdminRouterService;

controller

'use strict';

function toInt(str) {
  if (typeof str === 'number') return str;
  if (!str) return str;
  return parseInt(str, 10) || 0;
}

const Controller = require('egg').Controller;

/**
 * @controller adminRouter 后台路由
 */

class AdminRouterController extends Controller {

  /**
   * @summary 获取后台路由列表
   * @description 分页获取文章列表
   * @router get /api/v1/adminRouter
   * @response 200 baseResponse successed
   */
  async index() {
    const { ctx, service } = this;
    const query = {
      order: [
        [ 'order', 'DESC' ],
      ],
      attributes: ['id','pid','name','path','component','hidden','title','icon']
    };
    const result = await service.adminRouter.findAll(null,query);
    ctx.body = service.httpResponse.response({ data: result, msg: '查找成功' });
  }

}

module.exports = AdminRouterController;

注意事项,比如title和icon是放在meta字段里的,我现在是分下的

在这里插入图片描述
我这边是前端再做个转化

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
收工

Logo

前往低代码交流专区

更多推荐