vue实现后台管理权限系统及顶栏三级菜单显示功能


Posted in Javascript onJune 19, 2019

•效果演示地址

项目demo展示

vue实现后台管理权限系统及顶栏三级菜单显示功能

vue实现后台管理权限系统及顶栏三级菜单显示功能

重要功能总结

权限功能的实现

权限路由思路:

 根据用户登录的roles信息与路由中配置的roles信息进行比较过滤,生成可以访问的路由表,并通过router.addRoutes(store.getters.addRouters)动态添加可访问权限路由表,从而实现左侧和顶栏菜单的展示。

实现步骤:

1.在router/index.js中,给相应的菜单设置默认的roles信息;

如下:给"权限设置"菜单设置的权限为:meta:{roles: ['admin', 'editor']},及不同的角色都可以看到; 给其子菜单"页面权限",设置权限为:meta:{roles: ['admin']},及表示只有"admin"可以看到该菜单; 给其子菜单"按钮权限"设置权限为:meta:{roles: ['editor']},及表示只有"editor"可以看到该菜单。

2.通过router.beforeEach()和router.afterEach()进行路由过滤和权限拦截;

代码如下:

// permission judge function
function hasPermission(roles, permissionRoles) {
 if (roles.indexOf('admin') >= 0) return true // admin permission passed directly
 if (!permissionRoles) return true
 return roles.some(role => permissionRoles.indexOf(role) >= 0)
}
const whiteList = ['/login'] // 不重定向白名单

router.beforeEach((to, from, next) => {
 NProgress.start()
 // 设置浏览器头部标题
 const browserHeaderTitle = to.meta.title
 store.commit('SET_BROWSERHEADERTITLE', {
 browserHeaderTitle: browserHeaderTitle
 })
 // 点击登录时,拿到了token并存入了vuex;
 if (getToken()) {
 /* has token*/
 if (store.getters.isLock && to.path !== '/lock') {
 next({
 path: '/lock'
 })
 NProgress.done()
 } else if (to.path === '/login') {
 next({ path: '/' }) // 会匹配到path:'',后面的path:'*'还没有生成;
 NProgress.done() 
 } else {
 if (store.getters.roles.length === 0) {
 store.dispatch('GetInfo').then(res => { // 拉取用户信息
  const roles = res.roles
  store.dispatch('GenerateRoutes', { roles }).then(() => { // 根据roles权限生成可访问的路由表
  router.addRoutes(store.getters.addRouters) // 动态添加可访问权限路由表
  next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
  })
 }).catch((err) => {
  store.dispatch('FedLogOut').then(() => {
  Message.error(err || 'Verification failed, please login again')
  next({ path: '/' })
  })
 })
 } else {
 // 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
 if (hasPermission(store.getters.roles, to.meta.roles)) {
  next()//
 } else {
  next({ path: '/401', replace: true, query: { noGoBack: true }})
 }
 }
 }
 } else {
 if (whiteList.indexOf(to.path) !== -1) {
 next()
 } else {
 // 点击退出时,会定位到这里
 next('/login')
 NProgress.done()
 }
 }
})

router.afterEach(() => {
 NProgress.done() // 结束Progress
 setTimeout(() => {
 const browserHeaderTitle = store.getters.browserHeaderTitle
 setTitle(browserHeaderTitle)
 }, 0)
})

用户点击登录之后的业务逻辑分析:

1、用户调取登录接口,获取到token,进行路由跳转到首页;

2、通过路由导航钩子router.beforeEach((to,from,next)=>{})函数确定下一步的跳转逻辑,如下:
2.1、用户已经登录成功并返回token值;

 2.1.1、lock 锁屏场景; 

 2.1.2、用户重新定位到登录页面; 

  2.1.3、根据用户是否有roles信息,进行不同的业务逻辑,如下:  

    (1)、初始情况下,用户roles信息为空;

        通过store.dispatch('GetInfo')调取接口,获取用户信息;
        获取到roles信息后,将roles,name,avatar保存到vuex;
        同时,通过store.dispatch('GenerateRoutes', { roles })去重新过滤和生成路由,并将重新生成之后的权限路由'routes'保存到vuex;
        最后,通过router.addRoutes()合并路由表;  
        如果在获取用户信息接口时,出现错误,则调取store.dispatch('FedLogOut')接口,返回到login页面;
        用户FedLogOut之后,需要情况vuex和localStorage中的token信息;         

   (2)、用户已经拥有roles信息;

        点击页面路由,通过roles权限判断 hasPermission();
        如果用户有该路由权限,直接跳转对应的页面;如果没有权限,则跳转至401提示页面;

2.2、用户没有获取到token值;

  2.2.1、如果设置了白名单用户,则直接跳转到相应的页面;反之,则跳转至登录页面; 

3、通过路由导航钩子函数router.afterEach(() => {}),做收尾工作,如下:
3.1、NProgress.done() // 结束Progress
3.2、获取到title并设置title;

详细代码,请参考src/permission.js

4、权限演示说明

测试账号:

(1). username: admin,password: 123456;admin拥有最高权限,可以查看所有的页面和按钮;

(2). username: editor,password: 123456;editor只有被赋予权限的页面和按钮才可以看到;

三级导航菜单顶部栏展示

vue实现后台管理权限系统及顶栏三级菜单显示功能

如图所示,在完成一般后台系统所具有的二级导航菜单功能之后,我发现其实很多的后台管理系统都有三级导航菜单,但是如果都把三级菜单放到左侧菜单做阶梯状排列,就会显得比较紧凑,因此我觉得把所有的三级菜单放到顶部是一个不错的选择。

开发需求:点击左侧菜单,找到其对应的菜单(顶栏菜单)排放于顶部导航栏;

开发步骤:

1、 定义顶部导航组件topMenu.vue;

通过element-ui,NavMenu 导航菜单来进行顶部菜单的展示,注意顶栏和侧栏设置的区别;同时将其引用于头部组件headNav.vue中;

2、定义顶栏路由数据router/topRouter.js;

格式如下:

export const topRouterMap = [
 {
 'parentName':'infoShow',
 'topmenulist':[
  {
  path: 'infoShow1',
  name: 'infoShow1',
  meta: {
   title: '个人信息子菜单1',
   icon: 'fa-asterisk',
   routerType: 'topmenu'
  },
  component: () => import('@/page/fundList/moneyData')
  }
 ]
 },
 {
 'parentName':'chinaTabsList',
 'topmenulist':[
  {
  path:'chinaTabsList1',
  name:'chinaTabsList1',
  meta:{
   title:'区域投资子菜单1',
   icon:'fa-asterisk',
   routerType:'topmenu'
  },
  component: () => import('@/page/fundList/moneyData')
  }
 ]
 }
]

定义topRouterMap为路由总数组;通过parentName来与左侧路由建立联系;通过topmenulist表示该顶栏路由的值;通过meta.routerType的值为"topmenu"或"leftmenu"来区分是顶栏路由,还是左侧路由;

3、 准备headNav.vue中渲染数据;

思路:点击左侧菜单,需要显示顶部对应的菜单。因为左侧菜单要和顶部菜单建立联系。我们知道导航菜单在用户登录时,会根据用户的role信息进行权限过滤;那么,在过滤权限路由数据之前,我们可以通过addTopRouter()将所有的三级菜单进行过滤添加,添加完成之后,继续进行角色过滤,可以保证将不具备权限的顶部菜单也过滤掉。

// 通过循环过滤,生成新的二级菜单
function addTopRouter(){
 asyncRouterMap.forEach( (item) => {
 if(item.children && item.children.length >= 1){
 item.children.forEach((sitem) => {
 topRouterMap.forEach((citem) => {
  if(sitem.name === citem.parentName){
  let newChildren = item.children.concat(citem.topmenulist);
  item.children = newChildren;
  }
 })
 })
 }
 })
 return asyncRouterMap;
}

4、点击左侧菜单过滤路由并显示对应数据;

在组件topMenu.vue中,用户默认进来或者点击左侧菜单,触发setLeftInnerMenu()函数,如下:

setLeftInnerMenu(){
 if(this.$route.meta.routerType == 'leftmenu'){ // 点击的为 左侧的2级菜单
 this.$store.dispatch(''ClickLeftInnerMenu,
  {'name':this.$route.name}
 );
 }else{ // 点击顶部的菜单
 this.$store.dispatch('ClickTopMenu',
  {'title':this.$route.meta.title}
 );
 }
}

通过当前路由this.$route.meta.routerType的值判断,用户是点击顶部菜单还是左侧菜单。如果点击顶部菜单,通过this.$store触发异步动作'ClickLeftInnerMenu'并传递参数'name',vuex中通过state.topRouters = filterTopRouters(state.routers,data)过滤当前路由信息;代码如下:

// 获取到当前路由对应顶部子菜单
 function filterTopRouters(data){
 let topRouters = topRouterMap.find((item)=>{
 return item.parentName === data.name
 })
 if(!mutils.isEmpty(topRouters)){
 return topRouters.topmenulist;
 }
}

topMenu.vue中,通过 computed:{ ...mapGetters(['topRouters'])}进行对应顶部路由数据的展示。用户每次点击左侧菜单时,顶部路由都进行了重新赋值并渲染,保证了数据的准确性。

5、顶部菜单完善;

当顶部菜单的数据量过大时,我们需要设置横向滚动条并设置滚动条的样式。
 如图:

vue实现后台管理权限系统及顶栏三级菜单显示功能

mock数据详解

easy-mock使用

Easy Mock介绍:

•Easy Mock 是一个可视化,并且能快速生成 模拟数据 的持久化服务,
•Easy Mock 支持基于 Swagger 创建项目,以节省手动创建接口的时间;
•简单点说:Easy Mock就是一个在线创建mock的服务平台,帮你省去你 配置、安装、起服务、维护、多人协作Mock数据不互通等一系列繁琐的操作, 它能在不用1秒钟的时间内给你所要的一切。

详细使用方法,包含新建项目,基础语法,数据占位符,Swagger等介绍和使用,请参考详细文档

easy-mock,在本项目中的使用:

1.按照官方文档,创建个人项目vue-touzi-admin;

根据项目需要,创建的接口有:用户登录接口:"/user/login";获取用户信息接口:"/user/info";用户登出接口:"/user/logout";获取所有用户列表接口:"/user/getUserList";如图:

vue实现后台管理权限系统及顶栏三级菜单显示功能

登录接口在easy-mock端编写的逻辑如下:

{
 code: function({
 _req
 }) {
 if (_req.body.username === "admin" || _req.body.username === "editor" && _req.body.password === "123456") {
 return 200
 } else {
 return -1
 }
 },
 message: function({
 _req
 }) {
 if (_req.body.username !== "admin" || _req.body.username !== "editor") {
 return "账号或密码有误!"
 }
 },
 data: function({
 _req
 }) {
 if (_req.body.username == "admin" && _req.body.password === "123456") {
 return {
 code: 0,
 roles: ['admin'],
 token: 'admin',
 introduction: '我是超级管理员',
 name: 'Super Admin'
 }
 } else if (_req.body.username === 'editor' && _req.body.password === "123456") {
 return {
 code: 0,
 roles: ['editor'],
 token: 'editor',
 introduction: '我是编辑',
 name: 'Normal Editor'
 }
 } else {
 return "账号或密码有误!"
 }
 }
}

1.webpack中,开发环境和生产环境地址配置;生产环境,NODE_ENV: '"production"';如下:

module.exports = merge(prodEnv, {
 NODE_ENV: '"development"',
 API_BASE_URL: '"https://easy-mock.com/mock/5cd03667adb0973be6a3d8d1/api"',
})

3.接口封装实例;如下:

import request from '@/utils/axios'
export function login(username, password) {
 return request({
 url: process.env.API_BASE_URL+'/user/login',
 method: 'post',
 data: {
 username,
 password
 }
 })
}

mockjs使用

使用背景:

在使用easy-mock模拟数据的过程中,发现其对表格固定数据不能实现增删改等功能,因而选择了使用mockjs;

介绍及功能:

Mock.js是一款模拟数据生成器,旨在帮助前端攻城师独立于后端进行开发,帮助编写单元测试。提供了以下模拟功能:

1.根据数据模板生成模拟数据,通过mockjs提供的方法,你可以轻松地创造大量随机的文本,数字,布尔值,日期,邮箱,链接,图片,颜色等.

2.模拟 Ajax 请求,生成并返回模拟数据,mockjs可以进行强大的ajax拦截.能判断请求类型,获取到url,请求参数等.然后可以返回mock的假数据,或者你自己编好的json文件.功能强大易上手.

3.基于 HTML 模板生成模拟数据

mockjs在本项目中使用:

1.安装mockjs

npm install mockjs --save-dev

2.创建mock文件夹结构并定义相关的功能模块;如图:

vue实现后台管理权限系统及顶栏三级菜单显示功能

mockjs/index.js,负责定义相关的mock接口,如下:
import Mock from 'mockjs'
import tableAPI from './money'
// 设置全局延时 没有延时的话有时候会检测不到数据变化 建议保留
Mock.setup({
 timeout: '300-600'
})
// 资金相关
Mock.mock(/\/money\/get/, 'get', tableAPI.getMoneyList)
Mock.mock(/\/money\/remove/, 'get', tableAPI.deleteMoney)
Mock.mock(/\/money\/batchremove/, 'get', tableAPI.batchremoveMoney)
Mock.mock(/\/money\/add/, 'get', tableAPI.createMoney)
Mock.mock(/\/money\/edit/, 'get', tableAPI.updateMoney)

mockjs/money.js,则定义相关的函数,实现模拟数据的业务逻辑,比如资金流水数据的增删改查等;数据的生成规则请参照mockjs官网文档,上面有详细的语法说明;

3.在main.js中引入定义好的mockjs;如下:

import './mockjs'  //引用mock

4.mockjs,api接口封装;

src/api/money.js中,进行了统一的接口封装,在页面中调用对应函数,即可获取到相应的模拟数据。代码如下:

import request from '@/utils/axios'
export function getMoneyIncomePay(params) {
 return request({
 url: '/money/get',
 method: 'get',
 params: params
 })
}
export function addMoney(params) {
 return request({
 url: '/money/add',
 method: 'get',
 params: params
 })
}

5.组件中,接口调用,获取数据,渲染页面;

总结

以上所述是小编给大家介绍的vue实现后台管理权限系统及顶栏三级菜单显示功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Javascript 相关文章推荐
[JS源码]超长文章自动分页(客户端版)
Jan 09 Javascript
5款Javascript颜色选择器
Oct 25 Javascript
JS匀速运动演示示例代码
Nov 26 Javascript
extjs4 treepanel动态改变行高度示例
Dec 17 Javascript
Jquery Ajax解析XML数据(同步及异步调用)简单实例
Feb 12 Javascript
AngularJS实现表单手动验证和表单自动验证
Dec 09 Javascript
javascript 实现动态侧边栏实例详解
Nov 11 Javascript
vue脚手架vue-cli的学习使用教程
Jun 06 Javascript
Angular4.x通过路由守卫进行路由重定向实现根据条件跳转到相应的页面(推荐)
May 10 Javascript
浅谈在node.js进入文件目录的问题
May 13 Javascript
JS实现的点击按钮图片上下滚动效果示例
Jan 28 Javascript
详解如何理解vue的key属性
Apr 14 Javascript
JavaScript箭头函数中的this详解
Jun 19 #Javascript
基于Node.js的大文件分片上传示例
Jun 19 #Javascript
详解在Angular4中使用ng2-baidu-map的方法
Jun 19 #Javascript
了解Javascript中函数作为对象的魅力
Jun 19 #Javascript
利用vue-i18n实现多语言切换效果的方法
Jun 19 #Javascript
使用JQuery自动完成插件Auto Complete详解
Jun 18 #jQuery
使用异步controller与jQuery实现卷帘式分页
Jun 18 #jQuery
You might like
smarty静态实验表明,网络上是错的~呵呵
2006/11/25 PHP
Adodb的十个实例(清晰版)
2006/12/31 PHP
php mssql扩展SQL查询中文字段名解决方法
2012/10/15 PHP
解析php 版获取重定向后的地址(代码)
2013/06/26 PHP
php中动态调用函数的方法
2015/03/16 PHP
php中使用gd库实现远程图片下载实例
2015/05/12 PHP
Zend Framework入门知识点小结
2016/03/19 PHP
php构造方法中析构方法在继承中的表现
2016/04/12 PHP
php读取qqwry.dat ip地址定位文件的类实例代码
2016/11/15 PHP
浅谈PHP中try{}catch{}的使用方法
2016/12/09 PHP
自己整理的一个javascript日期处理函数
2010/10/16 Javascript
js定时器怎么写?就是在特定时间执行某段程序
2013/10/11 Javascript
JavaScript使用Replace进行字符串替换的方法
2015/04/14 Javascript
JavaScript实现仿网易通行证表单验证
2015/05/25 Javascript
使用vue的transition完成滑动过渡的示例代码
2018/06/25 Javascript
vue webpack开发访问后台接口全局配置的方法
2018/09/18 Javascript
详解ng-alain动态表单SF表单项设置必填和正则校验
2019/06/11 Javascript
基于Nuxt.js项目的服务端性能优化与错误检测(容错处理)
2019/10/23 Javascript
node后端服务保活的实现
2019/11/10 Javascript
python基于twisted框架编写简单聊天室
2018/01/02 Python
Tensorflow 同时载入多个模型的实例讲解
2018/07/27 Python
Python设计模式之工厂方法模式实例详解
2019/01/18 Python
python实现二维数组的对角线遍历
2019/03/02 Python
Python3 解决读取中文文件txt编码的问题
2019/12/20 Python
查看keras各种网络结构各层的名字方式
2020/06/11 Python
使用matplotlib的pyplot模块绘图的实现示例
2020/07/12 Python
python3爬虫中引用Queue的实例讲解
2020/11/24 Python
利用CSS3实现进度条的两种姿势详解
2017/03/21 HTML / CSS
写一个方法,输入一个文件名和一个字符串,统计这个字符串在这个文件中出现的次数
2016/04/13 面试题
就业推荐自我鉴定
2013/10/06 职场文书
招商业务员岗位职责
2013/12/16 职场文书
党员个人剖析材料2014
2014/10/08 职场文书
试用期自我评价范文
2015/03/10 职场文书
现役军人家属慰问信
2015/03/24 职场文书
医学生自荐信范文(2016精选篇)
2016/01/28 职场文书
python基础学习之生成器与文件系统知识总结
2021/05/25 Python