[
{
path: "/user",
component: 'Layout',
alwaysShow: true,
name: 'UserModule',
meta: {title: "用户管理", icon: "el-icon-s-tools"},
children: [
{ path: "user",
component: "user/user/index",
name: "UserModuleUser",
meta: {title: "用户列表"}
},
{ path: "role",
component: "user/role/index",
name: "UserModuleRole",
meta: {title: "角色列表"}
},
{ path: "center",
component: "user/center/index",
name: "UserModuleCenter",
hidden: true,
meta: {title: "个人中心"}
}
]
}
];
import { asyncRoutes,constantRoutes } from '@/router'
//constantRoutes 无权限控制页面
//asyncRoutes 权限控制页面
import { getInfo } from '@/api/user'
import Layout from '@/layout/index'
/**
* Use meta.role to determine if the current user has permission
* @param roles
* @param route
*/
function hasPermission(roles, route) {
if (route.meta && route.meta.roles) {
return roles.some(role => route.meta.roles.includes(role))
} else {
return true
}
}
/**
* Filter asynchronous routing tables by recursion//通过递归过滤异步路由表
* @param routes asyncRoutes
* @param roles
*/
export function filterAsyncRoutes(routes, roles) {
const res = []
routes.forEach(route => {
const tmp = {...route }//扩展运算符...
if (hasPermission(roles, tmp)) {
if (tmp.children) {
tmp.children = filterAsyncRoutes(tmp.children, roles)
}
res.push(tmp)
}
})
return res
}
const state = {
routes: [],
addRoutes: []
}
const mutations = {
SET_ROUTES: (state, routes) => {
state.addRoutes = routes
state.routes = constantRoutes.concat(routes)
}
}
const actions = {
generateRoutes({ commit }) {
return new Promise(resolve => {
// 向后端请求路由数据
getInfo().then(res => {
const accessedRoutes = filterAsyncRouter(res.data.menus)
accessedRoutes.push({path: '*', redirect: '/404', hidden: true})
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
})
})
}
}
//读取本地的菜单,测试环境可用。生产环境不行。
// const actions = {
// generateRoutes({ commit }, roles) {
// return new Promise(resolve => {
// let accessedRoutes
// if (roles.includes('admin')) {
// accessedRoutes = asyncRoutes || []
// } else {
// accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
// }
// commit('SET_ROUTES', accessedRoutes)
// resolve(accessedRoutes)
// })
// }
// }
// 遍历后台传来的路由字符串,转换为组件对象
export function filterAsyncRouter(asyncRouterMap) {
return asyncRouterMap.filter(route => {
if (route.component) {
// Layout组件特殊处理
if (route.component === 'Layout') {
route.component = Layout
} else {
route.component = loadView(route.component)
}
}
if (route.children != null && route.children.length != 0 && route.children && route.children.length) {
route.children = filterAsyncRouter(route.children)
}
return true
})
}
const loadView = (view) => require(`@/views/${view}`).default
export default {
namespaced: true,
state,
mutations,
actions
}
刷新页面,userInfo 两次请求优化为一次。
框架登录逻辑校验是
先通过 user/getInfo 获取用户信息(含用户角色 roles 数组)
然后将 roles 作为参数,请求 permission/generateRoutes 获取 路由
开发中:user/getInfo 和 permission/generateRoutes 调用的是同一个接口 userInfo。 使用 user/getInfo 就可以获取 角色(暂时用不上) 和路由。
考虑合并 src\store\modules\user.js 和 src\store\modules\permission.js 文件,改动有点麻烦,就使用以下的方式来减少一次请求。
if (hasToken) {
if (to.path === '/login') {
// if is logged in, redirect to the home page
next({ path: '/' })
NProgress.done() // hack: https://github.com/PanJiaChen/vue-element-admin/pull/2939
} else {
// determine whether the user has obtained his permission roles through getInfo
const hasRoles = store.getters.roles && store.getters.roles.length > 0
if (hasRoles) {
// 判断当前用户是否已拉取完user_info信息
next()
} else {
try {
// get user info
// note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
// const { roles } = await store.dispatch('user/getInfo')
const { menus } = await store.dispatch('user/getInfo')
// generate accessible routes map based on roles
const accessRoutes = await store.dispatch('permission/generateRoutes', menus)
// dynamically add accessible routes
router.addRoutes(accessRoutes)
// hack method to ensure that addRoutes is complete
// set the replace: true, so the navigation will not leave a history record
next({ ...to, replace: true })
} catch (error) {
// remove token and go to login page to re-login
await store.dispatch('user/resetToken')
Message.error(error.message)
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()
}
}
// get user info
getInfo({ commit, state }) {
// console.log('第一次触发 getInfo')
return new Promise((resolve, reject) => {
getInfo(state.token).then(response => {
const { data } = response
const { info } = response.data
const { roles } = response.data
const { menus } = response.data
if (!data) {
reject('用户信息不存在!')
}
const { username, photo } = info
if (!roles || roles.length <= 0) {
reject('getInfo: roles must be a non-null array!')
}
commit('SET_ROLES', roles)
commit('SET_MENUS', menus)
commit('SET_NAME', username)
commit('SET_AVATAR', photo)
resolve(data)
}).catch(error => {
reject(error)
})
})
},
// const actions = {
// generateRoutes({ commit },menus) {
// return new Promise(resolve => {
// // 向后端请求路由数据
// // console.log('第二次触发 getInfo')
// getInfo().then(res => {
// const accessedRoutes = filterAsyncRouter(res.data.menus)
// accessedRoutes.push({ path: '*', redirect: '/404', hidden: true })
// commit('SET_ROUTES', accessedRoutes)
// resolve(accessedRoutes)
// })
// })
// }
// }
// 优化 getInfo 同时获取了角色(没用上)和权限菜单 少请求一次 getInfo
const actions = {
generateRoutes({ commit }, menus) {
return new Promise(resolve => {
const accessedRoutes = filterAsyncRouter(menus)
accessedRoutes.push({ path: '*', redirect: '/404', hidden: true })
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
})
}
}
1、Critical dependency: the request of a dependency is an expression
const loadView = (view) => require(`@/views/${view}`).default
结尾的.default 别忘记加。
const loadView= (view) => import(`@/views/${view}.vue`)
.vue 后缀别忘记加。
2、import 不识别变量,是依赖的版本问题,没找到解决办法。所以用require。
3、缺少依赖,不识别 require,用require项目运行卡住不动,用import运行正常。
const loadView = (view) => require(`@/views/${view}`).default
vue-loader at least v13.0.0+
npm install -D vue-loader vue-template-compiler
https://github.com/PanJiaChen/vue-element-admin/issues/293