介绍及说明

1、背景介绍:最近因为公司的项目,对一个后台管理系统进行前端重构,原项目是SSM架构的前后端没有分离,前端用JSP和jQuery来写的,在完成第一期之后,我强烈要求前后端分离,并使用vue来组件化开发。所以经过几天的摸索完成了项目的整体搭建和基础建设。
2、项目要求:因为原先的项目的菜单都是后台来动态生成的,所以用vue来写也要从后台获取路由表,前端再处理成我们想要的路由格式,再完成侧边栏菜单;并且前端页面里有一个模块专门来管理生成菜单和权限(也就是前端自定义一些菜单信息传给后端,后端把数据存到数据库,并根据角色权限处理完数据再返回路由表给前端,前端就可以动态生成侧边栏菜单了)。

实现过程

首先本项目是基于vue-element-admin的后台管理模板( vue-element-admin),这个模板很多功能都有现成的,很方便,拉取下来之后就可以基于这个进行开发了,这个模板有很详细的文档说明( vue-element-admin使用文档),里面也有动态路由的集成方案,本项目选择的就是路由全部通过后端来生成,前端来自定义需要的路由。
步骤如下:
1、用户登录成功之后(登录的功能,模板里也写的很好,换成公司的登录接口就可以直接用),再根据用户名获取用户的权限,然后根据用户权限获取后端的路由数据:
1)权限处理和生成动态路由:src/permission.js文件

import router from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress' // 进度条
import 'nprogress/nprogress.css' // 进度条样式
import { getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'
// import { getRoutes } from './api/role'NProgress.configure({ showSpinner: false }) // NProgress Configurationconst whiteList = ['/login', '/auth-redirect'] // 没有重定向白名单router.beforeEach(async(to, from, next) => {// 开始进度条
NProgress.start()// 设置页面标题
document.title = getPageTitle(to.meta.title)// 确定用户是否已登录,获取token
const hasToken = getToken()if (hasToken) {if (to.path === '/login') {// 如果已登录,则重定向到主页next({ path: '/' })NProgress.done()} else {// 确定用户是否通过getInfo获得了他的权限角色const hasRoles = store.getters.roles && store.getters.roles.length > 0if (hasRoles) {next()} else {try {// 获取用户权限信息const { roles } = await store.dispatch('user/getInfo')// 根据角色生成可访问路由映射const accessRoutes = await store.dispatch('permission/generateRoutes', roles)// console.log(accessRoutes)// 动态添加可访问路由router.options.routes = router.options.routes.concat(accessRoutes)router.addRoutes(accessRoutes)// hack方法 以确保addRoutes是完整的next({ ...to, replace: true })// console.log(router)} catch (error) {// 删除令牌,进入登录页面重新登录await store.dispatch('user/resetToken')Message.error(error || 'Has Error')next(`/login?redirect=${to.path}`)NProgress.done()}}}
} else {/* 没有令牌*/if (whiteList.indexOf(to.path) !== -1) {// 去往免费的登录白名单next()} else {// 没有访问权限的其他页面被重定向到登录页面next(`/login?redirect=${to.path}`)NProgress.done()}
}
})router.afterEach(() => {// finish progress bar
NProgress.done()
})

2)获取用户权限的代码:src/store/modules/user.js

// 获取用户权限信息
getInfo({ commit, state }) {return new Promise((resolve, reject) => {getInfo(state.code).then(response => {const { data } = response// console.log(data)if (!data) {reject('验证失败,请重新登录.')}let roles = []roles = roles.concat(data.usrGroupcode)const name = data.userName// // 角色必须是非空数组if (!roles || roles.length <= 0) {reject('getInfo: 角色必须是非空数组!')}const avatar = data.userCodecommit('SET_NAME', name)commit('SET_ROLES', roles)commit('SET_CODE', avatar)const users = {roles: roles,introduction: '',code: avatar,name: name}// console.log(users)resolve(users)}).catch(error => {reject(error)})})
},

2、处理后端返回的路由信息并存到vuex里:src/store/modules/permission.js

import { constantRoutes } from '@/router'
import { getMenu } from '../../api/role'
import Layout from '@/layout'/*** 将后端content字段转成组件对象*/
function _import(file) {return () => import(`@/views/${file}/index.vue`)
}/*** 通过递归过滤异步路由表* @param routes asyncRoutes* @param roles*/
export function filterAsyncRoutes(routes) {const res = []// eslint-disable-next-line no-emptyfor (let i = 0; i < routes.length; i++) {res.push({path: routes[i].content === 'Layout' ? `/${routes[i].path}` : routes[i].path,component: routes[i].content === 'Layout' ? Layout : _import(routes[i].content),name: routes[i].path,meta: {title: routes[i].menuname,icon: routes[i].icon},children: routes[i].children && routes[i].children.length ? filterAsyncRoutes(routes[i].children) : []})}return res
}const state = {routes: constantRoutes,addRoutes: []
}const mutations = {SET_ROUTES: (state, routes) => {state.addRoutes = routesstate.routes = constantRoutes.concat(routes)}
}const actions = {generateRoutes({ commit }, roles) {return new Promise((resolve, reject) => {let accessedRouteslet asyncRoutes = []getMenu(roles[0]).then(res => {if (res.msg === 'SUCCESS') {asyncRoutes = res.data} else {asyncRoutes = []}// console.log(asyncRoutes)accessedRoutes = filterAsyncRoutes(asyncRoutes)// 最后添加const unfound = { path: '*', redirect: '/404', hidden: true }accessedRoutes.push(unfound)// console.log(accessedRoutes)// console.log('store:accessedRoutes')commit('SET_ROUTES', accessedRoutes)resolve(accessedRoutes)}).catch(error => {reject(error)})})}
}export default {namespaced: true,state,mutations,actions
}

基础路由和统一路由:src/router/index.js

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',name: 'home',meta: { title: '首页', affix: true },hidden: true,children: [{path: 'dashboard',component: () => import('@/views/dashboard'),hidden: true}]}]

3、然后再通过递归生成侧边栏菜单:src/layout
这个时候打印路由信息是可以得到正常的路由表信息;根据路由表生成侧边栏:
this.$router.options.routes 可以获取路由表信息,具体逻辑vue-element-admin模板里有现成的,这里就不解释了。

最后说一下后端返回的数据结构:

[{applicationid: 1035
children: [ //子节点,结构和当前一样0:{applicationid: 1035children: [0: {applicationid: 1035children: nullcontent: "system/system-management/menu"formid: 101100formtype: 1icon: ""inactived: 1memo: "EAM"menuid: 101100menuname: "菜单管理"parentmenuid: 101000parentrowid: "01KBGO"path: "menu"roles: ""rowid: "01KBGP"seq: 101100treecontrol: "01KBGP01KBGO01KBG9"}]content: "system/system-management"formid: 101000formtype: 1icon: ""inactived: 1memo: "EAM"menuid: 101000menuname: "系统设置"parentmenuid: 100000parentrowid: "01KBG9"path: "system-management"roles: ""rowid: "01KBGO"seq: 101000treecontrol: "01KBGO01KBG9"}
]
content: "Layout"  //对应组件的名称
formid: 100000
formtype: 1
icon: ""  //菜单的图标
inactived: 1  //是否启用
memo: "EAM"
menuid: 100000  //菜单的id
menuname: "系统管理"  //菜单的名称
parentmenuid: null  //父级菜单id
parentrowid: ""
path: "system"  //路由
roles: ""
rowid: "01KBG9"
seq: 100000  //排序
treecontrol: "01KBG9"
}]

使用Vue实现后台管理系统的动态路由以及侧边栏菜单相关推荐

  1. 【前端】Vue+Element UI案例:通用后台管理系统-登陆不同用户显示不同菜单、动态添加路由

    文章目录 目标 代码 0.动态地显示菜单:store 1.动态注册路由 2.解决刷新后摆平问题 总代码 本篇修改的代码文件 tab.js 参考视频: VUE项目,VUE项目实战,vue后台管理系统,前 ...

  2. SpringBoot实现分页查询——基于SpringBoot和Vue的后台管理系统项目系列博客(七)

    系列文章目录 系统功能演示--基于SpringBoot和Vue的后台管理系统项目系列博客(一) Vue2安装并集成ElementUI--基于SpringBoot和Vue的后台管理系统项目系列博客(二) ...

  3. SpringBoot实现代码生成器——基于SpringBoot和Vue的后台管理系统项目系列博客(十)

    系列文章目录 系统功能演示--基于SpringBoot和Vue的后台管理系统项目系列博客(一) Vue2安装并集成ElementUI--基于SpringBoot和Vue的后台管理系统项目系列博客(二) ...

  4. SpringBoot实现1对1、1对多、多对多关联查询——基于SpringBoot和Vue的后台管理系统项目系列博客(十八)

    系列文章目录 系统功能演示--基于SpringBoot和Vue的后台管理系统项目系列博客(一) Vue2安装并集成ElementUI--基于SpringBoot和Vue的后台管理系统项目系列博客(二) ...

  5. SpringBoot和Vue集成Markdown和多级评论——基于SpringBoot和Vue的后台管理系统项目系列博客(二十三)

    系列文章目录 系统功能演示--基于SpringBoot和Vue的后台管理系统项目系列博客(一) Vue2安装并集成ElementUI--基于SpringBoot和Vue的后台管理系统项目系列博客(二) ...

  6. Vue + ElementUI 后台管理系统实现主题风格切换

    一.目的 此次写作内容是在我之前发布一篇文章的基础上进行新增的. 上一篇文章:Vue + ElementUI 后台管理系统实现顶部一级菜单栏,左侧二级菜单栏_无解的菜鸟晖的博客-CSDN博客 这次要实 ...

  7. VUE项目后台管理系统(四)左边菜单动态展示,不仅可以折叠,而且点击不同的菜单,右边展示不同的页面

    目录 左边菜单动态的展示 左边菜单的属性介绍 遍历菜单 左边菜单折叠效果 不同的菜单右面展示不同的页面 左边菜单动态的展示 首先后端的接口要返回菜单的list集合,是json格式,我使用的是pytho ...

  8. 结合 服务器+后端+前端,完成 vue项目 后台管理系统

    目录 以上是项目的服务器php.后端.前端.已经可以正常运行 一 登录: 登录页进度条:戳这里Vue项目电商后台管理系统 nprogress--进度条_活在风浪里的博客-CSDN博客 二 侧导航 三 ...

  9. 【Vue】后台管理系统

    O 项目说明 1.脚手架 vite vue-cli ==> webpack 2.vite脚手架使用 官网:https://vitejs.cn/ Vue3 vite官网:https://cn.vi ...

最新文章

  1. 如何更好的创建Java对象
  2. CentOS 6.x 播放 mp3 音乐 —— 成功
  3. python零基础有用吗-10天搞定Python,告诉你有什么用?
  4. 信噪比与误码率的计算
  5. 深度探索va_start、va_arg、va_end
  6. RecyclerView 显示不全的问题.
  7. ee2prom擦除 c语言,浮点数在E2PROM中的存取方法.doc
  8. 刘庆敏 博客linux,Linux内核源码分析--zImage出生实录(Linux-3.0 ARMv7)
  9. redis队列(list)
  10. SRM 578 DIV 2
  11. php删除对象中的一个数组,PHP:从数组中删除对象
  12. Tableau可视化学习笔记:day03-04
  13. matplotlib tricks —— 平滑方法
  14. 互联网招聘数据分析处理与可视化
  15. 梦三国解析服务器spl文件头失败怎么解决,梦三国手游野区BUFF点解析 野区BUFF怎么的打...
  16. Unity使用PhotoShop制作磨砂玻璃材质
  17. QT笔记——Qt动态属性 之 unpolish() 和 polish()
  18. 【优秀毕设V2.0】基于树莓派的OpenCV-Python摄像头人脸追踪及手势识别、网络地址推流及远程控制系统(多功能系统、含演示视频)
  19. 强化学习笔记-01强化学习介绍
  20. STL - emplace 与 push 的区别

热门文章

  1. crmbePro二开 app打包手册
  2. 求人不如求己,有雄心壮志我们一起创业OK!(转)
  3. Vue之scoped限制优劣
  4. 几分钟教你做个原创视频,赚钱引流两不误
  5. 贝塞尔曲线与CSS3动画、SVG和canvas的基情
  6. 文件服务器归档制度,电子文件归档制度
  7. 火车票自动抢票新功能上线了!堪比抢票神器
  8. 「游戏建模」如何才能成为游戏建模师?
  9. 为什么要进行软件需求分析?通常对软件系统有哪些需求?
  10. Synergy软件的安装与使用