权限管理
注:后台管理系统最为重要的一部分
静态组件:
分为三个组件
(该组件为添加用户和添加权限列表的)
用户管理:
角色管理:给角色添加权限的
菜单管理:
因为权限管理不同的用户进入该后台系统看到的页面也是不相同的,所以需要动态添加路由。
常量路由:
//常量路由:就是不关用户是什么角色,都可以看见的路由
//什么角色(超级管理员,普通员工):登录、404、首页
export const constantRoutes = [
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/404'),
hidden: true
},
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [{
path: 'dashboard',
name: 'Dashboard',
component: () => import('@/views/dashboard/index'),
meta: { title: '首页', icon: 'dashboard' }
}]
},
// // 404 page must be placed at the end !!!
// { path: '*', redirect: '/404', hidden: true }
]
异步路由:
//异步理由:不同的用户(角色),需要过滤筛选出的路由,称之为异步路由
//有的用户可以看见测试管理、有的看不见
export const asyncRoutes = [
{
path: '/product',
component: Layout,
name: 'Product',
meta: { title: '商品管理', icon: 'el-icon-goods' },
children: [{
path: 'tradmark',
name: 'Trademark',
component: () => import('@/views/product/tradmark'),
meta: { title: '品牌管理' }
},
{
path: 'attr',
name: 'Attr',
component: () => import('@/views/product/attr'),
meta: { title: '属性管理' }
},
{
path: 'spu',
name: 'Spu',
component: () => import('@/views/product/spu'),
meta: { title: 'spu' }
}, {
path: 'sku',
name: 'Sku',
component: () => import('@/views/product/sku'),
meta: { title: 'sku' }
}
]
},
{
name: 'Acl',
path: '/acl',
component: Layout,
redirect: '/acl/user/list',
meta: {
title: '权限管理',
icon: 'el-icon-lock'
},
children: [
{
name: 'User',
path: 'user/list',
component: () => import('@/views/acl/user/list'),
meta: {
title: '用户管理',
},
},
{
name: 'Role',
path: 'role/list',
component: () => import('@/views/acl/role/list'),
meta: {
title: '角色管理',
},
},
{
name: 'RoleAuth',
path: 'role/auth/:id',
component: () => import('@/views/acl/role/roleAuth'),
meta: {
activeMenu: '/acl/role/list',
title: '角色授权',
},
hidden: true,
},
{
name: 'Permission',
path: 'permission/list',
component: () => import('@/views/acl/permission/list'),
meta: {
title: '菜单管理',
},
},
]
},
{
path: '/test',
component: Layout,
name: 'Test',
meta: { title: '测试管理', icon: 'el-icon-goods' },
children: [
{
path: 'test1',
name: 'Test1',
component: () => import('@/views/Test/Test1'),
meta: { title: '测试管理1' }
},
{
path: 'test2',
name: 'Test2',
component: () => import('@/views/Test/Test2'),
meta: { title: '测试管理2' }
},
]
},
];
任意路由:
//任意路由:当路径出现错误的时候重定向404
export const anyRoutes = { path: '*', redirect: '/404', hidden: true };
重置路由:
用户切换时,需要重置路由
// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher // reset router
}
我们通过vuex实现动态路由的实现:
state
const getDefaultState = () => {
return {
token: getToken(),
name: '',
avatar: '',
routes: [],
roles: [],
buttons: [],
//保存服务器返回的routes与异步路由对比后的数据
asyncRouteslist: [],
//全部路由
alrouterlist: []
}
}
const state = getDefaultState()
action
// get user info
getInfo({ commit, state }) {
return new Promise((resolve, reject) => {
getInfo(state.token).then(response => {
const { data } = response
if (!data) {
return reject('Verification failed, please Login again.')
}
const { name, avatar, routes, roles, buttons } = data
commit('SET_NAME', name)
commit('SET_AVATAR', avatar)
commit('SET_ROUTES', routes)
commit('SET_ROLES', roles)
commit('SET_ASYNCROUTES', computedasyncouter(asyncRoutes, routes))
commit('SET_BUTTONS', buttons)
resolve(data)
}).catch(error => {
reject(error)
})
})
},
mutations
const mutations = {
RESET_STATE: (state) => {
Object.assign(state, getDefaultState())
},
SET_TOKEN: (state, token) => {
state.token = token
},
SET_NAME: (state, name) => {
state.name = name
},
SET_AVATAR: (state, avatar) => {
state.avatar = avatar
},
SET_ROUTES: (state, routes) => {
state.routes = routes
},
SET_ROLES: (state, roles) => {
state.roles = roles
},
SET_ASYNCROUTES: (state, asyncRouteslist) => {
//vuex保存当前用户的异步路由,注意,一个用户需要展示完成路由:常量、异步、任意路由
state.asyncRouteslist = asyncRouteslist
state.alrouterlist = constantRoutes.concat(state.asyncRouteslist, anyRoutes)
//添加新路由
router.addRoutes(state.alrouterlist)
},
SET_BUTTONS: (state, buttons) => {
state.buttons = buttons
}
}
动态添加路由 router.addRouter()
router.addRoutes(routes: Array)
动态添加更多的路由规则。参数必须是一个符合 routes 选项要求的数组。
const router = new VueRouter([
{
path: "/",
name: "Home",
component: Home
}
]);
let route=[
{
path: '/pageA',
name: 'pageA',
component: pageA,
}]
router.addRoutes(route);
export default router
实现服务器发过来的route与配置的路由对比实现不同用户使用不同权限
//配置对比路由方法
const computedasyncouter = (asyncRoutes, routes) => {
return asyncRoutes.filter(item => {
if (routes.indexOf(item.name) !== -1) {
//要递归因为有2、3级路由
if (item.children && item.children.length) {
item.children = computedasyncouter(item.children, routes)
}
return true;
}
})
}
permission.js
路由守卫:next({ …to, replace: true })可以解决页面刷新变空白的问题
用法:https://www.cnblogs.com/windok/p/14549677.html
router.beforeEach(async (to, from, next) => {
// start progress bar
NProgress.start()
// set page title
document.title = getPageTitle(to.meta.title)
// determine whether the user has logged in
const hasToken = getToken()
if (hasToken) {
if (to.path === '/login') {
// if is logged in, redirect to the home page
next({ path: '/' })
NProgress.done()
} else {
const hasGetUserInfo = store.getters.name
console.log(hasGetUserInfo);
if (hasGetUserInfo) {
next()
} else {
try {
// get user info
await store.dispatch('user/getInfo')
// next()
next({ ...to, replace: true }) //路由守卫***回来看
} catch (error) {
// remove token and go to login page to re-login
await store.dispatch('user/resetToken')
Message.error(error || 'Has Error')
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
}
} else {
/* has no token*/
if (whiteList.indexOf(to.path) !== -1) {
// in the free login whitelist, go directly
next()
} else {
// other pages that do not have permission to access are redirected to the login page.
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
})