320 lines
13 KiB
JavaScript
320 lines
13 KiB
JavaScript
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 }
|