2023-11-24 10:32:04 +08:00
import type { AppRouteModule , AppRouteRecordRaw } from '@/router/types' ;
2021-03-17 00:10:16 +08:00
import type { Router , RouteRecordNormalized } from 'vue-router' ;
2020-12-03 21:49:32 +08:00
2023-11-24 10:32:04 +08:00
import { getParentLayout , LAYOUT , EXCEPTION_COMPONENT } from '@/router/constant' ;
2021-06-08 15:06:04 +08:00
import { cloneDeep , omit } from 'lodash-es' ;
2023-11-24 10:32:04 +08:00
import { warn } from '@/utils/log' ;
2021-03-17 00:10:16 +08:00
import { createRouter , createWebHashHistory } from 'vue-router' ;
2020-12-03 21:49:32 +08:00
2020-12-15 14:59:22 +08:00
export type LayoutMapKey = 'LAYOUT' ;
2023-11-24 10:32:04 +08:00
const IFRAME = ( ) = > import ( '@/views/sys/iframe/FrameBlank.vue' ) ;
2020-12-15 14:59:22 +08:00
2021-06-27 14:11:04 +08:00
const LayoutMap = new Map < string , ( ) = > Promise < typeof import ( ' * .vue ' ) > > ( ) ;
2021-06-11 00:29:39 +08:00
LayoutMap . set ( 'LAYOUT' , LAYOUT ) ;
LayoutMap . set ( 'IFRAME' , IFRAME ) ;
2020-12-15 14:59:22 +08:00
2021-03-17 00:10:16 +08:00
let dynamicViewsModules : Record < string , ( ) = > Promise < Recordable > > ;
2021-01-10 20:44:39 +08:00
2021-03-17 00:10:16 +08:00
// Dynamic introduction
2020-12-03 21:49:32 +08:00
function asyncImportRoute ( routes : AppRouteRecordRaw [ ] | undefined ) {
2021-03-02 06:59:38 +08:00
dynamicViewsModules = dynamicViewsModules || import . meta . glob ( '../../views/**/*.{vue,tsx}' ) ;
2020-12-03 21:49:32 +08:00
if ( ! routes ) return ;
routes . forEach ( ( item ) = > {
2021-06-11 00:29:39 +08:00
if ( ! item . component && item . meta ? . frameSrc ) {
item . component = 'IFRAME' ;
}
2020-12-03 21:49:32 +08:00
const { component , name } = item ;
const { children } = item ;
if ( component ) {
2021-09-23 00:05:58 +08:00
const layoutFound = LayoutMap . get ( component . toUpperCase ( ) ) ;
2021-06-11 00:29:39 +08:00
if ( layoutFound ) {
item . component = layoutFound ;
} else {
item . component = dynamicImport ( dynamicViewsModules , component as string ) ;
}
2020-12-03 21:49:32 +08:00
} else if ( name ) {
2021-03-17 00:10:16 +08:00
item . component = getParentLayout ( ) ;
2020-12-03 21:49:32 +08:00
}
children && asyncImportRoute ( children ) ;
} ) ;
}
2021-01-10 20:44:39 +08:00
function dynamicImport (
2021-03-17 00:10:16 +08:00
dynamicViewsModules : Record < string , ( ) = > Promise < Recordable > > ,
2021-08-24 22:41:48 +08:00
component : string ,
2021-01-10 20:44:39 +08:00
) {
const keys = Object . keys ( dynamicViewsModules ) ;
2021-01-09 23:28:52 +08:00
const matchKeys = keys . filter ( ( key ) = > {
2021-09-23 12:28:21 +08:00
const k = key . replace ( '../../views' , '' ) ;
const startFlag = component . startsWith ( '/' ) ;
const endFlag = component . endsWith ( '.vue' ) || component . endsWith ( '.tsx' ) ;
const startIndex = startFlag ? 0 : 1 ;
const lastIndex = endFlag ? k.length : k.lastIndexOf ( '.' ) ;
return k . substring ( startIndex , lastIndex ) === component ;
2021-01-09 23:28:52 +08:00
} ) ;
if ( matchKeys ? . length === 1 ) {
const matchKey = matchKeys [ 0 ] ;
2021-01-10 20:44:39 +08:00
return dynamicViewsModules [ matchKey ] ;
2021-09-23 00:05:58 +08:00
} else if ( matchKeys ? . length > 1 ) {
2021-01-09 23:28:52 +08:00
warn (
2021-08-24 22:41:48 +08:00
'Please do not create `.vue` and `.TSX` files with the same file name in the same hierarchical directory under the views folder. This will cause dynamic introduction failure' ,
2021-01-09 23:28:52 +08:00
) ;
return ;
2021-09-23 00:05:58 +08:00
} else {
2021-09-23 12:28:21 +08:00
warn ( '在src/views/下找不到`' + component + '.vue` 或 `' + component + '.tsx`, 请自行创建!' ) ;
2021-09-23 00:05:58 +08:00
return EXCEPTION_COMPONENT ;
2021-01-09 23:28:52 +08:00
}
}
2020-12-03 21:49:32 +08:00
// Turn background objects into routing objects
2022-06-16 19:02:10 +08:00
// 将背景对象变成路由对象
2020-12-03 21:49:32 +08:00
export function transformObjToRoute < T = AppRouteModule > ( routeList : AppRouteModule [ ] ) : T [ ] {
routeList . forEach ( ( route ) = > {
2021-06-27 14:11:04 +08:00
const component = route . component as string ;
if ( component ) {
if ( component . toUpperCase ( ) === 'LAYOUT' ) {
route . component = LayoutMap . get ( component . toUpperCase ( ) ) ;
2020-12-03 21:49:32 +08:00
} else {
route . children = [ cloneDeep ( route ) ] ;
route . component = LAYOUT ;
2023-11-03 11:53:33 +08:00
//某些情况下如果name如果没有值, 多个一级路由菜单会导致页面404
if ( ! route . name ) {
warn ( '找不到菜单对应的name, 请检查数据!' + JSON . stringify ( route ) ) ;
2023-10-31 11:44:50 +08:00
}
2023-11-03 11:53:33 +08:00
route . name = ` ${ route . name } Parent ` ;
2020-12-03 21:49:32 +08:00
route . path = '' ;
const meta = route . meta || { } ;
meta . single = true ;
meta . affix = false ;
route . meta = meta ;
}
2021-09-23 12:28:21 +08:00
} else {
warn ( '请正确配置路由:' + route ? . name + '的component属性' ) ;
2020-12-03 21:49:32 +08:00
}
route . children && asyncImportRoute ( route . children ) ;
} ) ;
2021-06-08 15:06:04 +08:00
return routeList as unknown as T [ ] ;
2020-12-03 21:49:32 +08:00
}
2021-03-17 00:10:16 +08:00
/ * *
* Convert multi - level routing to level 2 routing
2022-06-16 19:02:10 +08:00
* 将 多 级 路 由 转 换 为 2 级 路 由
2021-03-17 00:10:16 +08:00
* /
2021-03-23 01:06:32 +08:00
export function flatMultiLevelRoutes ( routeModules : AppRouteModule [ ] ) {
const module s : AppRouteModule [ ] = cloneDeep ( routeModules ) ;
2022-06-16 19:02:10 +08:00
2021-03-23 01:06:32 +08:00
for ( let index = 0 ; index < module s.length ; index ++ ) {
const routeModule = module s [ index ] ;
2022-06-16 19:02:10 +08:00
// 判断级别是否 多级 路由
2021-03-17 00:10:16 +08:00
if ( ! isMultipleRoute ( routeModule ) ) {
2022-06-16 19:02:10 +08:00
// 声明终止当前循环, 即跳过此次循环,进行下一轮
2021-03-17 00:10:16 +08:00
continue ;
}
2022-06-16 19:02:10 +08:00
// 路由等级提升
2021-03-17 00:10:16 +08:00
promoteRouteLevel ( routeModule ) ;
}
2021-03-23 01:06:32 +08:00
return module s ;
2021-03-17 00:10:16 +08:00
}
// Routing level upgrade
2022-06-16 19:02:10 +08:00
// 路由等级提升
2021-03-17 00:10:16 +08:00
function promoteRouteLevel ( routeModule : AppRouteModule ) {
// Use vue-router to splice menus
2022-06-16 19:02:10 +08:00
// 使用vue-router拼接菜单
// createRouter 创建一个可以被 Vue 应用程序使用的路由实例
2021-03-17 00:10:16 +08:00
let router : Router | null = createRouter ( {
2021-06-08 15:06:04 +08:00
routes : [ routeModule as unknown as RouteRecordNormalized ] ,
2021-03-17 00:10:16 +08:00
history : createWebHashHistory ( ) ,
} ) ;
2022-06-16 19:02:10 +08:00
// getRoutes: 获取所有 路由记录的完整列表。
2021-03-17 00:10:16 +08:00
const routes = router . getRoutes ( ) ;
2022-06-16 19:02:10 +08:00
// 将所有子路由添加到二级路由
2021-03-23 01:06:32 +08:00
addToChildren ( routes , routeModule . children || [ ] , routeModule ) ;
2021-03-17 00:10:16 +08:00
router = null ;
2022-06-16 19:02:10 +08:00
// omit lodash的函数 对传入的item对象的children进行删除
2021-06-08 15:06:04 +08:00
routeModule . children = routeModule . children ? . map ( ( item ) = > omit ( item , 'children' ) ) ;
2021-03-17 00:10:16 +08:00
}
// Add all sub-routes to the secondary route
2022-06-16 19:02:10 +08:00
// 将所有子路由添加到二级路由
2021-03-17 00:10:16 +08:00
function addToChildren (
routes : RouteRecordNormalized [ ] ,
children : AppRouteRecordRaw [ ] ,
2021-08-24 22:41:48 +08:00
routeModule : AppRouteModule ,
2021-03-17 00:10:16 +08:00
) {
for ( let index = 0 ; index < children . length ; index ++ ) {
const child = children [ index ] ;
const route = routes . find ( ( item ) = > item . name === child . name ) ;
2021-03-23 01:06:32 +08:00
if ( ! route ) {
continue ;
}
routeModule . children = routeModule . children || [ ] ;
if ( ! routeModule . children . find ( ( item ) = > item . name === route . name ) ) {
2021-06-08 15:06:04 +08:00
routeModule . children ? . push ( route as unknown as AppRouteModule ) ;
2021-03-23 01:06:32 +08:00
}
if ( child . children ? . length ) {
addToChildren ( routes , child . children , routeModule ) ;
2021-03-17 00:10:16 +08:00
}
}
}
// Determine whether the level exceeds 2 levels
2022-06-16 19:02:10 +08:00
// 判断级别是否超过2级
2021-03-17 00:10:16 +08:00
function isMultipleRoute ( routeModule : AppRouteModule ) {
2022-06-16 19:02:10 +08:00
// Reflect.has 与 in 操作符 相同, 用于检查一个对象(包括它原型链上)是否拥有某个属性
2021-03-17 00:10:16 +08:00
if ( ! routeModule || ! Reflect . has ( routeModule , 'children' ) || ! routeModule . children ? . length ) {
return false ;
}
const children = routeModule . children ;
let flag = false ;
for ( let index = 0 ; index < children . length ; index ++ ) {
const child = children [ index ] ;
if ( child . children ? . length ) {
flag = true ;
break ;
}
}
return flag ;
2020-12-03 21:49:32 +08:00
}