// @/store export default { state: { permissionList: [] }, mutations: { updatePermissionList: (state, payload) => { state.permissionList = payload } }, actions: { getPermissionList: async ({ state, commit }) => { // 这里是为了防止重复获取 if (state.permissionList.length) return // 发送请求方法省略 const list = await api.getPermissionList() commit('updatePermissionList', list) } } }
// @/utils/permission import store from '@/store' /** * 判断是否拥有权限 * @param {Array<string>} permissions - 要判断的权限列表 */ function includePermission (permissions = []) { // 这里要判断的权限没有设置的话,就等于不需要权限,直接返回 true if (!permissions.length) return true const permissionList = store.state.permissionList return !!permissions.find(permission => permissionList.includes(permission)) }
重定向问题
以上我们解决了路由的基本配置与权限如何获取,怎么限制路由跳转,接下来我们要处理的就是重定向问题了。
这一点可能和我们项目本身架构有关,我们项目的侧边栏下还有子级,是以下图中的 tab 切换展现的,正常情况当点击药品管理后页面会重定向到入库管理的 tab 切换页面,但当入库管理没有权限时,则应该直接重定向到出库管理界面。
所以想实现以上的效果,我需要重写 router 的 redirect,做到可以动态判断(因为在我配置路由时并不知道当前用户的权限列表)
然后我查看了 vue-router 的文档,发现了 redirect 可以是一个方法,这样就可以解决重定向问题了。
,根据说明我们可以改写 redirect 如下:
// 我们需要引入判断权限方法 import { includePermission } from '@/utils/permission' const children = [ { path: 'list', name: 'UserList', label: '用户列表', meta: { permissions: ['U_1_1'] } }, { path: 'group', name: 'UserGroup', label: '用户组', meta: { permissions: ['U_1_2'] } } ] const routeDemo = { path: '/user', name: 'User', label: '用户', redirect: (to) => { if (includePermission(children[0].meta.permissions)) return { name: children[0].name } if (includePermission(children[1].meta.permissions)) return { name: children[1].name } }, children }
虽然问题解决了,但是发现这样写下去很麻烦,还要修改 router 的配置,所以我们使用一个方法生成:
// @/utils/permission /** * 创建重定向函数 * @param {Object} redirect - 重定向对象 * @param {string} redirect.name - 重定向的组件名称 * @param {Array<any>} children - 子列表 */ function createRedirectFn (redirect = {}, children = []) { // 避免缓存太大,只保留 children 的 name 和 permissions const permissionChildren = children.map(({ name = '', meta: { permissions = [] } = {} }) => ({ name, permissions })) return function (to) { // 这里一定不能在 return 的函数外面筛选,因为权限是异步获取的 const hasPermissionChildren = permissionChildren.filter(item => includePermission(item.permissions)) // 默认填写的重定向的 name const defaultName = redirect.name || '' // 如果默认重定向没有权限,则从 children 中选择第一个有权限的路由做重定向 const firstPermissionName = (hasPermissionChildren[0] || { name: '' }).name // 判断是否需要修改默认的重定向 const saveDefaultName = !!hasPermissionChildren.find(item => item.name === defaultName && defaultName) if (saveDefaultName) return { name: defaultName } else return firstPermissionName ? { name: firstPermissionName } : redirect } }
然后我们就可以改写为:
// 我们需要引入判断权限方法 import { includePermission, createRedirectFn } from '@/utils/permission' const children = [ { path: 'list', name: 'UserList', label: '用户列表', meta: { permissions: ['U_1_1'] } }, { path: 'group', name: 'UserGroup', label: '用户组', meta: { permissions: ['U_1_2'] } } ] const routeDemo = { path: '/user', name: 'User', label: '用户', redirect: createRedirectFn({ name: 'UserList' }, children), children }
这样稍微简洁一些,但我还是需要一个一个路由去修改,所以我又写了一个方法来递归 router 配置,并重写他们的 redirect: