Vue添加动态路由
2019-11-20 本文已影响0人
领带衬有黄金
需求
后台管理需要根据登陆的用户权限做菜单控制
思路
后台返回用户权限,保存到vuex中,判断权限是否有惨淡导航,如果有使用addRoutes添加到路由中。
路由声明处,需要声明动态路由和公共路由。
由权限去判断是否应该加入动态路由
store代码:
-->user.js
function isAddRoute(pers, route) {
return pers.some(per => per.code.split('_').pop() === route.path.split('/').pop())
}
function removeArrayData(arr) {
let i = arr.length - 1;
while (i >= 0) {
if (arr[i].path !== '/login' && arr[i].path !== '/' && arr[i].path !== '/404' && arr[i].path !== '*') {
arr.splice(i, 1)
}
i--
}
}
export function filterAsyncRoutes(pers, routes) {
const res = []
routes.forEach(route => {
const tmp = {...route}
if (isAddRoute(pers, tmp)) {
// 目前仅控制一级路由,子路由以后控制
// if (tmp.children) {
// tmp.children = filterAsyncRoutes(tmp.children, roles)
// }
res.push(tmp)
}
});
return res
}
const state = {
addRoutes: []
}
const mutations = {
// 移除用户
REMOVE: (state) => {
state.name = ''
state.addRoutes = []
//退出后,改变还原静态路由
removeArrayData(constantRoutes)
},
ADD_ROUTES: (state, routes) => {
state.addRoutes = routes
routes.forEach((i, index) => {
// 从第3+index个位置插入
constantRoutes.splice(3 + index, 0, i)
})
}
}
const actions = {
// get user info
getInfo({commit, state}) {
return new Promise((resolve, reject) => {
getInfo(state.token).then(res => {
const {data} = res
let pers = []
let admin_pers = []
if (!data) {
reject('Verification failed, please Login again.')
}
// const {name, phone, active, create_time, avatar} = data
commit('SET_INFO', data)
admin_pers = data.roles.map(item => item.pers)
for (let i in admin_pers) {
for (let j in admin_pers[i]) {
let target = pers.filter(item => item.code === admin_pers[i][j].code)
if (target.length === 0) {
// 判断如果角色中有相同的
pers.push(admin_pers[i][j])
}
}
}
const accessedRoutes = filterAsyncRoutes(pers, asyncRoutes)
// 将角色权限保存到vuex
commit('ADD_ROUTES', accessedRoutes)
resolve(data)
}).catch(error => {
reject(error)
})
})
},
// user logout
logout({commit, state}) {
return new Promise((resolve, reject) => {
logout(state.token).then(() => {
commit('SET_TOKEN', '')
commit('REMOVE')
removeToken()
resetRouter()
resolve()
}).catch(error => {
reject(error)
})
})
}
}
-->main.js
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 {
// 在vuex中保存有用户信息的,直接通过
const hasGetUserInfo = store.getters.name
if (hasGetUserInfo) {
// 判断路由是否在 database,在该路由下,即发送数据请求,保存到vuex
if (/database/.test(to.path)) {
ajax_get_db_types()
// await store.dispatch('db/action_get_types')
}
const hasAddRoutes = store.getters.addRoutes && store.getters.addRoutes.length > 0
if (hasAddRoutes) {
next()
}
} else {
/*没有用户信息*/
const hasAddRoutes = store.getters.addRoutes && store.getters.addRoutes.length > 0
if (hasAddRoutes) {
next()
} else {
// 判断用户角色
try {
if (/database/.test(to.path)) {
// 当路由来到database时,发送获取数据库分类请求,保存到vuex中
ajax_get_db_types()
}
// 首次保存用户信息 // 第一次请求保存用户信息到vuex中,并进入index页面,此时不做进入database的判断
await store.dispatch('user/getInfo');
// // constantRoutes.options.routes = newRoutes
router.addRoutes(store.getters.addRoutes)
// 解决路由刷新404界面
router.addRoutes([{path: '*', redirect: '/404', hidden: true}])
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()
}
}
})
-->router.js
import Layout from '@/layout'
export const constantRoutes = [
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
name: '404',
path: '/404',
component: () => import('@/views/404'),
hidden: true, meta: {title: '404'}
},
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [{
path: '/dashboard',
name: '首页',
component: () => import('@/views/dashboard/index'),
meta: {title: '首页', icon: 'dashboard', noCache: true, affix: true}
}]
},
// 匹配所有路由,如果匹配了上面的路由,就会直接跳转,否则跳转到404路由
// {path: '*', redirect: '/404', hidden: true}
]
export const asyncRoutes = [
{
path: '/database',
component: Layout,
redirect: '/database/databaselist',
name: '数据库管理',
meta: {title: '数据库管理', icon: 'nested'},
children: [
{
path: 'databaselist',
name: 'DatabaseList',
component: () => import('@/views/database/DatabaseList'),
meta: {title: '数据库分类', icon: '列表'}
},
{
path: 'databaserset',
name: 'DatabaseSet',
component: () => import('@/views/database/DatabaseSet'),
meta: {title: '数据库设置', icon: '设置'}
}
]
},
{
path: '/news',
component: Layout,
redirect: '/news/newslist',
name: '资讯快报管理',
meta: {title: '资讯快报管理', icon: '资讯'},
children: [
{
path: 'newslist',
name: 'NewsList',
component: () => import('@/views/news/NewsList'),
meta: {title: '资讯快报列表', icon: '列表'}
},
{
path: 'newsset',
name: 'NewsSet',
component: () => import('@/views/news/NewsSet'),
meta: {title: '资讯快报设置', icon: '设置'}
},
]
},
{
path: '/intelligence',
component: Layout,
redirect: '/intelligence/intelclass',
name: '情报智库管理',
meta: {title: '情报智库管理', icon: '数据情报'},
children: [
{
path: 'intellist',
name: 'Tree',
component: () => import('@/views/intelligence/IntelList'),
meta: {title: '情报列表', icon: '列表'}
},
{
path: 'intelclass',
name: 'IntelClass',
component: () => import('@/views/intelligence/IntelClass'),
meta: {title: '情报分类', icon: 'link'}
}
]
},
{
path: '/permission',
component: Layout,
redirect: '/permission/admins',
name: '管理员管理',
meta: {title: '管理员管理', icon: '用户,管理员_jurassic'},
children: [
{
path: 'admins',
name: 'Admins',
component: () => import('@/views/permission/Admins'),
meta: {title: '管理员列表', icon: '列表'}
},
{
path: 'roles',
name: 'Roles',
component: () => import('@/views/permission/Roles'),
meta: {title: '角色列表', icon: '会员'}
},
{
path: 'rules',
name: 'Rules',
component: () => import('@/views/permission/Rules'),
meta: {title: '权限列表', icon: '权限'}
}
]
},
{
path: '/vip',
component: Layout,
redirect: '/vip/viplist',
name: '会员管理',
meta: {title: '会员管理', icon: '会员中心'},
children: [
{
path: 'viplist',
name: 'VipList',
component: () => import('@/views/vip/VipList'),
meta: {title: '会员列表', icon: '列表'}
},
{
path: 'vippower',
name: 'VipPower',
component: () => import('@/views/vip/VipPower'),
meta: {title: '会员权限', icon: '权限'}
},
{
path: 'viporders',
name: 'VipOrders',
component: () => import('@/views/vip/VipOrders'),
meta: {title: '用户订单', icon: '订单'}
}
]
},
{
path: '/swiper',
component: Layout,
redirect: '/swiper/homeswiper',
name: '轮播图管理',
meta: {title: '轮播图管理', icon: 'eye-open'},
children: [
{
path: 'homeswiper',
name: 'HomeSwiper',
component: () => import('@/views/swiper/HomeSwiper'),
meta: {title: '前台首页轮播图', icon: '首页轮播图'}
},
{
path: 'newsswiper',
name: 'NewsSwiper',
component: () => import('@/views/swiper/NewsSwiper'),
meta: {title: '资讯首页轮播文章', icon: '首页轮播图'}
}
]
},
{
path: '/tools',
component: Layout,
redirect: '/tools/pricecontrol',
name: '工具管理',
meta: {title: '工具管理', icon: 'example'},
children: [
{
path: 'pricecontrol',
name: 'PriceControl',
component: () => import('@/views/tools/PriceControl'),
meta: {title: '价格上浮管理', icon: '数据情报'}
},
{
path: 'viewlog',
name: 'Viewlog',
component: () => import('@/views/tools/Viewlog'),
meta: {title: '日志查看', icon: 'eye'}
}
]
},
{
path: '/gallery',
component: Layout,
redirect: '/gallery/database',
name: '图库管理',
meta: {title: '图库管理', icon: 'example'},
children: [
{
path: 'database',
name: 'database',
component: () => import('@/views/gallery/Database'),
meta: {title: '数据图库', icon: '数据情报'}
},
{
path: 'intelligence',
name: 'intelligence',
component: () => import('@/views/gallery/Intelligence'),
meta: {title: '情报图库', icon: 'eye'}
}
]
},
]
const createRouter = () => new Router({
mode: 'history',
scrollBehavior: () => ({y: 0}),
routes: constantRoutes
})
const router = createRouter()
问题:
一:刷新404,不能在静态路由中添加
*
拦截没有的路由,需要手动传入router.addRoutes([{path: '*', redirect: '/404', hidden: true}])
二:访问动态路由404,需要将*
拦截的路由放在最后。