middle-admin-ant/src/utils/routerUtil.js

320 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import routerMap from '@/router/router.map'
import { mergeI18nFromRoutes } from '@/utils/i18n'
import Router from 'vue-router'
import deepMerge from 'deepmerge'
import basicOptions from '@/router/async/config.async'
//应用配置 初始化
let appOptions = {
router: undefined,
i18n: undefined,
store: undefined
}
/**
* 设置应用配置
* @param options
*/
function setAppOptions(options) { // 设置应用配置
const { router, store, i18n } = options // 获取路由、状态管理、国际化
appOptions.router = router // 路由
appOptions.store = store // 状态管理
appOptions.i18n = i18n // 国际化
}
/**
* 根据 路由配置 和 路由组件注册 解析路由
* @param routesConfig 路由配置
* @param routerMap 本地路由组件注册配置
*/
function parseRoutes(routesConfig, routerMap) { // 解析路由
let routes = [] // 初始化路由为空数组
routesConfig.forEach(item => { // 遍历路由配置
// 获取注册在 routerMap 中的 router初始化 routeCfg
let router = undefined, routeCfg = {} // 初始化路由和路由配置
if (typeof item === 'string') { // 如果路由配置是字符串
router = routerMap[item] // 从 routerMap 中获取路由
routeCfg = { path: (router && router.path) || item, router: item } // 路由配置获取路由的 path 和 router
} else if (typeof item === 'object') { // 如果路由配置是对象
router = routerMap[item.router] // 从 routerMap 中获取路由
routeCfg = item // 路由配置为 item
}
if (!router) { // 如果没有获取到路由 或者是路由不为数组及对象
console.warn(`can't find register for router ${routeCfg.router}, please register it in advance.`) // 打印警告
router = typeof item === 'string' ? { path: item, name: item } : item // 如果路由配置是字符串,路由为 {path: item, name: item},否则为 item
}
// 从 router 和 routeCfg 解析路由
const meta = { // 路由元信息
authority: router.authority, // 路由权限
icon: router.icon, // 图标
page: router.page, // 页面
link: router.link, // 链接
params: router.params, // 参数
query: router.query, // 查询
...router.meta // 路由元信息
}
const cfgMeta = { // 路由配置元信息
authority: routeCfg.authority, // 路由权限
icon: routeCfg.icon, // 图标
page: routeCfg.page, // 页面
link: routeCfg.link, // 链接
params: routeCfg.params, // 参数
query: routeCfg.query, // 查询
...routeCfg.meta // 路由元信息
}
Object.keys(cfgMeta).forEach(key => { // 遍历路由配置元信息
if (cfgMeta[key] === undefined || cfgMeta[key] === null || cfgMeta[key] === '') { // 如果路由配置元信息的值为 undefined、null、''
delete cfgMeta[key] // 删除路由配置元信息的值
}
})
Object.assign(meta, cfgMeta) // 合并路由元信息和路由配置元信息
const route = {
path: routeCfg.path || router.path || routeCfg.router, // 路由路径
name: routeCfg.name || router.name, // 路由名称
component: router.component, // 路由组件
redirect: routeCfg.redirect || router.redirect, // 重定向
meta: { ...meta, authority: meta.authority || '*' } // 路由元信息
}
if (routeCfg.invisible || router.invisible) { // 如果路由配置或者路由不可见
route.meta.invisible = true
}
if (routeCfg.children && routeCfg.children.length > 0) { // 如果路由配置有子路由
route.children = parseRoutes(routeCfg.children, routerMap)
}
routes.push(route)
})
return routes
}
// 根据权限过滤路由
function filterRoutesConfig(routes, permissions) {
const res = []
routes.forEach(route => {
const tmp = { ...route }
if (hasPermission(permissions, tmp)) {
if (tmp.children) {
tmp.children = filterRoutesConfig(tmp.children, permissions)
}
res.push(tmp)
}
})
return res
}
// 判断是否有权限
function hasPermission(permissions, route) {
if (route.meta && route.meta.authority.permission) {
return permissions.some(permission => {
return route.meta.authority.permission === '' || route.meta.authority.permission === permission
})
} else {
return true
}
}
/**
* 加载路由
* @param routesConfig {RouteConfig[]} 路由配置
*/
function loadRoutes(routesConfig) { // 加载路由
//兼容 0.6.1 以下版本
/*************** 兼容 version < v0.6.1 *****************/
// if (arguments.length > 0) { // 如果arguments的数量大于0
// const arg0 = arguments[0] // 获取第一个参数
// console.log("+++++arg0:",arg0)
// if (arg0.router || arg0.i18n || arg0.store) {
// routesConfig = arguments[1]
// console.log("+++++arguments[1]:",arguments[1])
// console.error('the usage of signature loadRoutes({router, store, i18n}, routesConfig) is out of date, please use the new signature: loadRoutes(routesConfig).')
// console.error('方法签名 loadRoutes({router, store, i18n}, routesConfig) 的用法已过时, 请使用新的方法签名 loadRoutes(routesConfig)。')
// }
// }
/*************** 兼容 version < v0.6.1 *****************/
// 应用配置
const { router, store, i18n } = appOptions
const Permission = store.getters['account/permissions'] // 获取权限
if (routesConfig) { // 如果routesConfig已经存在
store.commit('account/setRoutesConfig', routesConfig) // 通过store的account模块的setRoutesConfig方法更新路由配置
} else {
routesConfig = store.getters['account/routesConfig'] // 通过store的account模块的routesConfig方法获取路由配置
}
// 如果 routesConfig 有值,则更新到本地,否则从本地获取
// 根据权限过滤路由配置
const filteredRoutesConfig = filterRoutesConfig(routesConfig, Permission) // 根据权限过滤路由配置
// console.log("=====filteredRoutesConfig:", filteredRoutesConfig)
filteredRoutesConfig
// routesConfig = filteredRoutesConfig // 路由配置等于过滤后的路由配置
// 如果开启了异步路由,则加载异步路由配置
const asyncRoutes = store.state.setting.asyncRoutes // 获取store的setting模块的asyncRoutes
if (asyncRoutes) { // 如果动态路由存在
console.log("routesConfig && routesConfig.length > 0", routesConfig.length > 0)
if (routesConfig && routesConfig.length > 0) { // 如果本地路由配置存在 并且 数量大于0
const routes = parseRoutes(routesConfig, routerMap) // 解析路由
// 合并路由 生成路由表
const finalRoutes = mergeRoutes(basicOptions.routes, routes)
// 格式化路由
formatRoutes(finalRoutes)
console.log('最终路由表finalRoutes:', finalRoutes) // 最终路由表
router.options = { ...router.options, routes: finalRoutes } // 路由配置
router.matcher = new Router({ ...router.options, routes: [] }).matcher // 重置路由
// router.addRoutes(finalRoutes) // 添加路由
for (let x of finalRoutes) {
router.addRoute(x)
}
}
}
// 提取路由国际化数据
mergeI18nFromRoutes(i18n, router.options.routes) // 合并路由国际化数据
// 初始化Admin后台菜单数据
const rootRoute = router.options.routes.find(item => item.path === '/') // 获取根路由
const menuRoutes = rootRoute && rootRoute.children // 获取根路由的子路由
if (menuRoutes) { // 如果子路由存在
store.commit('setting/setMenuData', menuRoutes) // 通过store的setting模块的setMenuData方法更新菜单数据
}
}
/**
* 合并路由
* @param target {Route[]}
* @param source {Route[]}
* @returns {Route[]}
*/
function mergeRoutes(target, source) { // 合并路由
const routesMap = {} // 路由映射表
target.forEach(item => routesMap[item.path] = item) // 将target中的路由添加到路由映射表中
source.forEach(item => routesMap[item.path] = item) // 将source中的路由添加到路由映射表中
return Object.values(routesMap) // 返回路由映射表的值
}
/**
* 深度合并路由
* @param target {Route[]}
* @param source {Route[]}
* @returns {Route[]}
*/
function deepMergeRoutes(target, source) {
// 映射路由数组
const mapRoutes = routes => { // 映射路由数组
const routesMap = {} // 路由映射表
routes.forEach(item => { // 遍历路由
routesMap[item.path] = { // 将路由添加到路由映射表中
...item,
children: item.children ? mapRoutes(item.children) : undefined // 如果路由有子路由则递归调用mapRoutes方法
}
})
return routesMap // 返回路由映射表
}
const tarMap = mapRoutes(target) // 映射target
const srcMap = mapRoutes(source) // 映射source
// 合并路由
const merge = deepMerge(tarMap, srcMap)
// 转换为 routes 数组
const parseRoutesMap = routesMap => {
return Object.values(routesMap).map(item => {
if (item.children) {
item.children = parseRoutesMap(item.children)
} else {
delete item.children
}
return item
})
}
return parseRoutesMap(merge)
}
/**
* 格式化路由
* @param routes 路由配置
*/
function formatRoutes(routes) { // 格式化路由
routes.forEach(route => { // 遍历路由
const { path } = route // 获取路由的path
if (!path.startsWith('/') && path !== '*') { // 如果路由的path不是以/开头 并且 不是*
route.path = '/' + path // 将路由的path添加/
}
})
formatAuthority(routes) // 将路由的authority属性转换为meta.authority属性
}
/**
* 格式化路由的权限配置
* @param routes 路由
* @param pAuthorities 父级路由权限配置集合
*/
function formatAuthority(routes, pAuthorities = []) { // 格式化路由的权限配置
routes.forEach(route => { // 遍历路由
const meta = route.meta // 获取路由的meta
const defaultAuthority = pAuthorities[pAuthorities.length - 1] || { permission: '*' } // 获取默认权限 首先获取父级路由权限配置集合的最后一个元素,如果没有则获取{permission: '*'}
if (meta) { // 如果meta存在
let authority = {} // 权限
if (!meta.authority) { // 如果meta.authority不存在
authority = defaultAuthority // 权限为默认权限
} else if (typeof meta.authority === 'string') { // 如果meta.authority是字符串
authority.permission = meta.authority // 权限的permission为meta.authority
} else if (typeof meta.authority === 'object') { // 如果meta.authority是对象
authority = meta.authority // 权限为meta.authority
const { role } = authority // 获取权限的role
if (typeof role === 'string') { // 如果权限的role是字符串
authority.role = [role] // 权限的role为数组
}
if (!authority.permission && !authority.role) { // 如果权限的permission和role都不存在
authority = defaultAuthority // 权限为默认权限
}
}
meta.authority = authority // 将权限赋值给meta.authority
} else { // 如果meta不存在
const authority = defaultAuthority // 权限为默认权限
route.meta = { authority } // 将权限赋值给meta
}
route.meta.pAuthorities = pAuthorities // 将父级路由权限配置集合赋值给meta.pAuthorities
if (route.children) { // 如果路由有子路由 递归调用formatAuthority方法
formatAuthority(route.children, [...pAuthorities, route.meta.authority])
}
})
}
/**
* 从路由 path 解析 i18n key
* @param path
* @returns {*}
*/
function getI18nKey(path) { // 从路由 path 解析 i18n key
const keys = path.split('/').filter(item => !item.startsWith(':') && item != '') // 获取路由的path将path以/分割,过滤掉以:开头的元素,过滤掉空元素
keys.push('name') // 将name添加到keys中
return keys.join('.') // 将keys以.连接
}
/**
* 加载导航守卫 进度条
* @param guards
* @param options
*/
function loadGuards(guards, options) { // 加载导航守卫 guards
const { beforeEach, afterEach } = guards // 解构出 beforeEach 和 afterEach
const { router } = options // 解构出 router
beforeEach.forEach(guard => { // 遍历 beforeEach
if (guard && typeof guard === 'function') { // 如果guard存在 并且 guard是函数
router.beforeEach((to, from, next) => guard(to, from, next, options)) // 调用router.beforeEach方法
}
})
afterEach.forEach(guard => { // 遍历 afterEach
if (guard && typeof guard === 'function') { // 如果guard存在 并且 guard是函数
router.afterEach((to, from) => guard(to, from, options)) // 调用router.afterEach方法
}
})
}
export { parseRoutes, loadRoutes, formatAuthority, getI18nKey, loadGuards, deepMergeRoutes, formatRoutes, setAppOptions }