最近完成了我的后台管理系统权限功能的实现,同时觉得后台系统所有的菜单都左置,会限制菜单的扩展,因此我改进了三级菜单的显示。

  • 效果演示地址
  • github地址

权限功能的实现

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

实现步骤:

1.给相应的菜单设置默认的roles信息

在router/index.js中,给相应的菜单设置默认的roles信息; 如下:给"权限设置"菜单设置的权限为:meta:{roles: ['admin', 'editor']},及不同的角色都可以看到; 给其子菜单"页面权限",设置权限为:meta:{roles: ['admin']},及表示只有"admin"可以看到该菜单; 给其子菜单"按钮权限"设置权限为:meta:{roles: ['editor']},及表示只有"editor"可以看到该菜单。

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

代码如下:

// permission judge function
function hasPermission(roles, permissionRoles) {if (roles.indexOf('admin') >= 0) return true // admin permission passed directlyif (!permissionRoles) return truereturn roles.some(role => permissionRoles.indexOf(role) >= 0)
}
const whiteList = ['/login'] // 不重定向白名单router.beforeEach((to, from, next) => {NProgress.start()// 设置浏览器头部标题const browserHeaderTitle = to.meta.titlestore.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.rolesstore.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() // 结束ProgresssetTimeout(() => {const browserHeaderTitle = store.getters.browserHeaderTitlesetTitle(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只有被赋予权限的页面和按钮才可以看到;

三级导航菜单顶部栏展示

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

1.开发需求:

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

2.开发步骤:

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.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.顶部菜单完善;

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

mock数据详解

easy-mock使用

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

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

2.easy-mock,在本项目中的使用:
1. 按照官方文档,创建个人项目vue-touzi-admin;

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

登录接口在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 "账号或密码有误!"}}
}
复制代码
2. 开发环境和生产环境地址配置;

开发环境:NODE_ENV = development;生产环境,NODE_ENV =production;如下:

NODE_ENV = development
VUE_APP_URL = "https://easy-mock.com/mock/5cd03667adb0973be6a3d8d1/api"
复制代码
3.接口封装实例;

如下:

import request from '@/utils/axios'
import baseUrl  from '@/utils/env'
export function login(username, password) {return request({url: baseUrl.app_url+'/user/login',method: 'post',data: {username,password}})
}
复制代码

mockjs使用

1.使用背景:

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

2.介绍及功能:

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

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

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

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

3.mockjs在本项目中使用:
1. 安装mockjs
npm install mockjs --save-dev
复制代码
2.创建mock文件夹结构并定义相关的功能模块;

如图:

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-cli3.0 升级记录

由于项目早期使用vue-cli2.0构建项目,需要进行繁琐的webpack配置;vue-cli 3.0集成了webpack配置并在性能提升上做了很大优化。因为本项目使用vue-cli3.0进行构建和升级。现将相关注意事项总结如下,详细文档,请参考官网介绍。

1.vue-cli3.0使用前提介绍

Vue CLI 的包名称由 vue-cli 改成了 @vue/cli。 如果你已经全局安装了旧版本的 vue-cli (1.x 或 2.x),你需要先通过 npm uninstall vue-cli -g 或 yarn global remove vue-cli 卸载它。 Vue CLI 需要 Node.js 8.9 或更高版本 (推荐 8.11.0+)。你可以使用 nvm 或 nvm-windows 在同一台电脑中管理多个 Node 版本。

2.vue-cli3.0安装及使用

1.vue-cli3.x安装
npm install -g @vue/cli
# OR
yarn global add @vue/cli
复制代码

如果希望还保留 vue-cli2.x 的语法或使用 2.x 的模板,建议安装 cli-init

npm install -g @vue/cli-init
# OR
yarn global add @vue/cli-init
复制代码
2.使用 vue-cli3.x 创建项目

vue create 项目名称; 安装步骤选取相关的配置信息即可,直到完成。

3.新项目需要进行环境变量和模式配置

在根目录下新建文件.env.development和.env.production,分别表示开发环境和生成环境配置;主要用于定义环境变量,并通过npm run serve或npm run build集成到不同的环境中,供接口调用。代码如下:

.env.development

NODE_ENV = development
VUE_APP_URL = "https://easy-mock.com/mock/5cd03667adb0973be6a3d8d1/api"
复制代码

.env.production

NODE_ENV = production
VUE_APP_URL = "https://easy-mock.com/mock/5cd03667adb0973be6a3d8d1/api"
复制代码

使用方法,如本项目中,配置在utils/env.js中,代码如下:

// development和production环境是不同的
let app_url = process.env.VUE_APP_URL
export default {app_url
}
复制代码

由于我们使用easy-mock模拟数据,不存在跨域问题,所以不需要配置devServer.proxy,可以直接使用。在api中的使用方法如下:

import request from '@/utils/axios'
import baseUrl  from '@/utils/env'
export function login(username, password) {return request({url: baseUrl.app_url+'/user/login',method: 'post',data: {username,password}})
}
复制代码
4.使用vue.config.js编译打包详细配置

由于使用vue-cli3.x生成项目,webpack相关配置已经集成到node_module中,如果希望对 webpack 等进行细致化配置,需要在项目根目录下新建文件vue.config.js,具体配置可参考文档,下面是一份基本配置。

const TerserPlugin = require('terser-webpack-plugin')  // 用于在生成环境剔除debuger和console
const path = require('path');
const resolve = dir => {return path.join(__dirname, dir);
};const env = process.env.NODE_ENV
let target = process.env.VUE_APP_URL  // development和production环境是不同的module.exports = {publicPath: '/',outputDir: './dist',lintOnSave: false, // 关闭eslint// 打包时不生成.map文件productionSourceMap: false,devServer: {open: true,host: '0.0.0.0',port: 8808// 由于本项目数据通过easy-mock和mockjs模拟,不存在跨域问题,无需配置代理;// proxy: { //   '/v2': {//       target: target,//       changeOrigin: true//   }// }},// webpack相关配置chainWebpack: (config) => {config.entry.app = ['./src/main.js'];config.resolve.alias.set('@', resolve('src')).set('cps', resolve('src/components'))},configureWebpack:config => {// 为生产环境修改配置...if (process.env.NODE_ENV === 'production') {new TerserPlugin({cache: true,parallel: true,sourceMap: true, // Must be set to true if using source-maps in productionterserOptions: {compress: {drop_console: true,drop_debugger: true}}})} else {// 为开发环境修改配置...}},// 第三方插件配置pluginOptions: {}
}复制代码

项目配置完成好,安装好所有的依赖包。执行开发环境打包命令:npm run serve,即可运行项目;执行生成环境打包命令:npm run build,即可生成生产环境文件。

技术答疑

项目说明:

小爱ADMIN是完全开源免费的管理系统集成方案,可以直接应用于相关后台管理系统模板;很多重点地方都做了详细的注释和解释。如果你也一样喜欢前端开发,欢迎加入我们的讨论/学习群,群内可以提问答疑,分享学习资料; 欢迎加入答疑qq群:602515030

转载于:https://juejin.im/post/5d0b4d28f265da1baf7cf293

用Vue-cli3+element+mockjs 实现后台管理权限系统及顶栏三级菜单显示相关推荐

  1. Vue使用elementUI实现一个后台管理

    Vue使用elementUI实现一个后台管理 功能效果 思路 功能分析 1.安装 2.main.vue 3.App.vue 4.views (1) Home.vue (2) Classify.vue ...

  2. NETCore Bootstrap Admin 通用后台管理权限 [1]: 前后台分离系统简介

    前言 从事软件开发这个行业现在已经有十几年了,项目无论大小权限认证.授权模块总是或多或少有功能需求的,这一块费时费力但是又存在于后台,使用最多的可能是运维人员所以处于出力不讨好的尴尬地位,每次有新的项 ...

  3. 基于员工管理权限系统的数据库设计完整版

    设计一个灵活.通用.方便的权限管理系统. 在这个系统中,我们需要对系统的所有资源进行权限控制,那么系统中的资源包括哪些呢?我们可以把这些资源简单概括为静态资源(功能操作.数据列)和动态资源(数据),也 ...

  4. icworks+D2Admin+vue+element UI 制作后台管理

    前言: icworks又名飞冰 海量可复用物料,通过 GUI 工具极速构建中后台应用.是阿里巴巴前端团队开源的一个产品,目的让前端开发简单而友好. 进入正题 使用以及构建项目非常简单 1.直接进入官网 ...

  5. 睿停车系统车场服务器,睿停车后台管理中心系统-用户手册-前台版本

    1业务管理业务管理鼠标移动至业务管理菜单出,即可看到下来的子菜单.业务管理模块分为业务办理.人事信息管理以及充值缴费中心三块内容.后文将对这三个子功能菜单详述.1.1业务管理业务管理点击业务管理子菜单 ...

  6. 帝国cms html广告,帝国后台管理-广告系统插件 - 搜外设计社

    广告系统说明 四种广告说明: 图片/FLASH广告:增加图片广告与FLASH广告. 文字广告:增加文字链接广告.如:帝国CMS下载 HTML广告:增加直接代码类型的广告.如:google广告 弹出广告 ...

  7. 如何搭建出类似央视C-Box的电视直播应用的后台管理支撑系统

    看网络电视直播已经逐渐替代了有线电视观看的传统方式,而是采用互联网电视IPTV/OTT-TV的方式,通过网络来观看电视频道节目. 这对于入户家庭可以说是一场观看电视方式的变革. 随着电视观看方式的变革 ...

  8. 后台管理权限管理(二) 权限按钮控制的实现

    先上图 在后台项目中,不同的登录者有不同的角色,可能上面的编辑.删除.详情这些按钮不是每个人都能点击的.不同的人登录系统有不同的操作权限.下面是他的实现方式. 首先,在store/modules下创建 ...

  9. 后台返回给前端数据拆分成三级菜单

    拿到的数据格式是 里面根据参数进行判断属于哪一级 根据catalogstep参数进行判断的层级 首先会定义三个新的数组 然后再进行三个数组的合并添加 最后返回的一个结果就是 这个里面注意的参数有pid ...

  10. 为element ui+Vue搭建的后台管理项目添加图标

    问题:使用element UI 及Vue 2.0搭建一个后台管理项目,想要在页面中为其添加对勾及叉的图标. 解决方案:问题涉及到为页面添加图标.有两种解决方案. (1)Element官网提供了Icon ...

最新文章

  1. layuiAdmin打开新窗口、新标签页
  2. java 推送数据给js,Node.js实现数据推送
  3. @Builder(toBuilder=true) 链式初始化对象、修改对象
  4. 重读GhostNet:使用轻量操作代替部分传统卷积层生成冗余特征以减少计算量
  5. Oracle技术之O7_DICTIONARY_ACCESSIBILITY(二)
  6. Visual Studio Code 11 月 Python 扩展更新
  7. springmvc项目,浏览器报404错误的问题
  8. nodejs 配置全局 globle 缓存 catch
  9. Kossel 升级记 - 混乱之始
  10. Dell PowerEdge RAID控制器存在一个潜在问题
  11. 测试用例的设计-面试常见问题(基础篇)
  12. php 上周日期,php获取本周和上周的开始日期和结束日期
  13. region proposal
  14. 塑源码是什么_朔源码燕窝就没有问题货吗?朔源码和非朔源码燕窝该如何选择?...
  15. python 免费空间_用python做大数据
  16. 关于自己开发财务管理系统的个人总结
  17. C语言的二维数组初始化的几种方式介绍(私藏大数组初始化方式)
  18. 上海亚商投顾:沪指逼近3300点 电力、光伏持续强势
  19. 将网页内容截屏的好工具
  20. 泊一盏心灯,悠然前行

热门文章

  1. Datawhale数据挖掘项目之task1
  2. 图论算法——加权有向图的数据结构
  3. 大淘宝的终极商业阶段
  4. 1.5 Linux文件目录创建与删除
  5. 1.7 非平衡数据的处理方法大全
  6. 3.7 TextRNN—TextRCNN—TextAttentionRNN—HAN—FastText—代码
  7. 三段话搞明白什么是Krylov子空间迭代法
  8. python与r语言处理excel数据_【R语言】批量读取Excel数据并合并(升级版)
  9. python输出文本文件_Python进阶02 文本文件的输入输出
  10. java回车不终止_java 在console行输入一串String后回车,仍无法停止。 下面的程序是计算相似度的,当用户输入关键字后...