vue实现后台管理权限系统及顶栏三级菜单显⽰功能
•
项⽬demo展⽰
重要功能总结
权限功能的实现
权限路由思路:
根据⽤户登录的roles信息与路由中配置的roles信息进⾏⽐较过滤,⽣成可以访问的路由表,并通
过router.s.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
storemit('SET_BROWSERHEADERTITLE', {
browserHeaderTitle: browserHeaderTitle
})
// 点击登录时,拿到了token并存⼊了vuex;
if (getToken()) {
/* has token*/
if (s.isLock && to.path !== '/lock') {
next({
path: '/lock'
})
NProgress.done()
} else if (to.path === '/login') {
next({ path: '/' }) // 会匹配到path:'',后⾯的path:'*'还没有⽣成;
NProgress.done()
} else {
if (les.length === 0) {
store.dispatch('GetInfo').then(res => { // 拉取⽤户信息
const roles = les
store.dispatch('GenerateRoutes', { roles }).then(() => { // 根据roles权限⽣成可访问的路由表
router.s.addRouters) // 动态添加可访问权限路由表
next({ ...to, replace: true }) // hack⽅法确保addRoutes已完成
})
}).catch((err) => {
store.dispatch('FedLogOut').then(() => {
<(err || 'Verification failed, please login again')
next({ path: '/' })
})
})
} else {
// 没有动态改变权限的需求可直接next() 删除下⽅权限判断↓
if (s.roles, les)) {
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 = s.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;
详细代码,请参考
4、权限演⽰说明
测试账号:
(1). username: admin,password: 123456;admin拥有最⾼权限,可以查看所有的页⾯和按钮;
(2). username: editor,password: 123456;editor只有被赋予权限的页⾯和按钮才可以看到;
三级导航菜单顶部栏展⽰
如图所⽰,在完成⼀般后台系统所具有的⼆级导航菜单功能之后,我发现其实很多的后台管理系统都
有三级导航菜单,但是如果都把三级菜单放到左侧菜单做阶梯状排列,就会显得⽐较紧凑,因此我觉得把所有的三级菜单放到顶部是⼀个不错的选择。
开发需求:点击左侧菜单,到其对应的菜单(顶栏菜单)排放于顶部导航栏;
开发步骤:
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表⽰该顶栏路由的值;通过uterType的值为"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 = pmenulist);
item.children = newChildren;
}
})
})
}
})
return asyncRouterMap;
}
4、点击左侧菜单过滤路由并显⽰对应数据;
在组件topMenu.vue中,⽤户默认进来或者点击左侧菜单,触发setLeftInnerMenu()函数,如下:
setLeftInnerMenu(){
if(this.$uterType == 'leftmenu'){ // 点击的为左侧的2级菜单
this.$store.dispatch(''ClickLeftInnerMenu,
{'name':this.$route.name}
);
}else{ // 点击顶部的菜单
this.$store.dispatch('ClickTopMenu',
{'title':this.$a.title}
);
}
}
通过当前路由this.$uterType的值判断,⽤户是点击顶部菜单还是左侧菜单。如果点击顶部菜单,通过this.$store触发异步动作'ClickLeftInnerMenu'并传递参数'name',vuex中通过pRouters = uters,data)过滤当前路由信息;代码如下:
// 获取到当前路由对应顶部⼦菜单
function filterTopRouters(data){
let topRouters = topRouterMap.find((item)=>{
return item.parentName === data.name
})
if(!mutils.isEmpty(topRouters)){
pmenulist;
}
}
topMenu.vue中,通过 computed:{ ...mapGetters(['topRouters'])}进⾏对应顶部路由数据的展⽰。⽤户每次点击左侧菜单时,顶部路由都进⾏了重新赋值并渲染,保证了数据的准确性。
5、顶部菜单完善;
当顶部菜单的数据量过⼤时,我们需要设置横向滚动条并设置滚动条的样式。
如图:
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";如图:
登录接⼝在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"';如下:
NODE_ENV: '"development"',
API_BASE_URL: '"easy-mock/mock/5cd03667adb0973be6a3d8d1/api"',
})
3.接⼝封装实例;如下:
import request from '@/utils/axios'
export function login(username, password) {
return request({
url: v.API_BASE_URL+'/user/login',
method: 'post',
data: {
username,
password
}
})
}
mockjs使⽤
使⽤背景:
在使⽤easy-mock模拟数据的过程中,发现其对表格固定数据不能实现增删改等功能,因⽽选择了使⽤mockjs;
介绍及功能:
是⼀款模拟数据⽣成器,旨在帮助前端攻城师独⽴于后端进⾏开发,帮助编写单元测试。提供了以下模拟功能:
1.根据数据模板⽣成模拟数据,通过mockjs提供的⽅法,你可以轻松地创造⼤量随机的⽂本,数字,布尔值,⽇期,邮箱,链接,图⽚,颜⾊等.
2.模拟 Ajax 请求,⽣成并返回模拟数据,mockjs可以进⾏强⼤的ajax拦截.能判断请求类型,获取到url,请求参数等.然后可以返回mock的假数据,或者你⾃⼰编好的json⽂件.功能强⼤易上⼿.
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论