routerHelper.ts 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import { createRouter, createWebHashHistory } from 'vue-router'
  2. import type { Router, RouteLocationNormalized, RouteRecordNormalized, RouteMeta } from 'vue-router'
  3. import { isUrl } from '@/utils/is'
  4. import { omit, cloneDeep } from 'lodash-es'
  5. const modules = import.meta.glob('../views/**/*.{vue,tsx}')
  6. /* Layout */
  7. export const Layout = () => import('@/layout/Layout.vue')
  8. export const getParentLayout = () => {
  9. return () =>
  10. new Promise((resolve) => {
  11. resolve({
  12. name: 'ParentLayout'
  13. })
  14. })
  15. }
  16. export const getRawRoute = (route: RouteLocationNormalized): RouteLocationNormalized => {
  17. if (!route) return route
  18. const { matched, ...opt } = route
  19. return {
  20. ...opt,
  21. matched: (matched
  22. ? matched.map((item) => ({
  23. meta: item.meta,
  24. name: item.name,
  25. path: item.path
  26. }))
  27. : undefined) as RouteRecordNormalized[]
  28. }
  29. }
  30. // 前端控制路由生成
  31. export const generateRoutesFn1 = (
  32. routes: AppRouteRecordRaw[],
  33. keys: string[],
  34. basePath = '/'
  35. ): AppRouteRecordRaw[] => {
  36. const res: AppRouteRecordRaw[] = []
  37. for (const route of routes) {
  38. const meta = route.meta as RouteMeta
  39. // skip some route
  40. if (meta.hidden && !meta.showMainRoute) {
  41. continue
  42. }
  43. let data: Nullable<AppRouteRecordRaw> = null
  44. let onlyOneChild: Nullable<string> = null
  45. if (route.children && route.children.length === 1 && !meta.alwaysShow) {
  46. onlyOneChild = (
  47. isUrl(route.children[0].path)
  48. ? route.children[0].path
  49. : pathResolve(pathResolve(basePath, route.path), route.children[0].path)
  50. ) as string
  51. }
  52. // 开发者可以根据实际情况进行扩展
  53. for (const item of keys) {
  54. // 通过路径去匹配
  55. if (isUrl(item) && (onlyOneChild === item || route.path === item)) {
  56. data = Object.assign({}, route)
  57. } else {
  58. const routePath = pathResolve(basePath, onlyOneChild || route.path)
  59. if (routePath === item || meta.followRoute === item) {
  60. data = Object.assign({}, route)
  61. }
  62. }
  63. }
  64. // recursive child routes
  65. if (route.children && data) {
  66. data.children = generateRoutesFn1(route.children, keys, pathResolve(basePath, data.path))
  67. }
  68. if (data) {
  69. res.push(data as AppRouteRecordRaw)
  70. }
  71. }
  72. return res
  73. }
  74. // 后端控制路由生成
  75. export const generateRoutesFn2 = (routes: AppCustomRouteRecordRaw[]): AppRouteRecordRaw[] => {
  76. const res: AppRouteRecordRaw[] = []
  77. for (const route of routes) {
  78. const data: AppRouteRecordRaw = {
  79. path: route.path,
  80. name: route.name,
  81. redirect: route.redirect,
  82. meta: route.meta
  83. }
  84. if (route.component) {
  85. const comModule = modules[`../${route.component}.vue`] || modules[`../${route.component}.tsx`]
  86. const component = route.component as string
  87. if (!comModule && !component.includes('#')) {
  88. console.error(`未找到${route.component}.vue文件或${route.component}.tsx文件,请创建`)
  89. } else {
  90. // 动态加载路由文件,可根据实际情况进行自定义逻辑
  91. data.component =
  92. component === '#' ? Layout : component.includes('##') ? getParentLayout() : comModule
  93. }
  94. }
  95. // recursive child routes
  96. if (route.children) {
  97. data.children = generateRoutesFn2(route.children)
  98. }
  99. res.push(data as AppRouteRecordRaw)
  100. }
  101. return res
  102. }
  103. export const pathResolve = (parentPath: string, path: string) => {
  104. const childPath = path.startsWith('/') || !path ? path : `/${path}`
  105. return `${parentPath}${childPath}`.replace(/\/\//g, '/')
  106. }
  107. // 路由降级
  108. export const flatMultiLevelRoutes = (routes: AppRouteRecordRaw[]) => {
  109. const modules: AppRouteRecordRaw[] = cloneDeep(routes)
  110. for (let index = 0; index < modules.length; index++) {
  111. const route = modules[index]
  112. if (!isMultipleRoute(route)) {
  113. continue
  114. }
  115. promoteRouteLevel(route)
  116. }
  117. return modules
  118. }
  119. // 层级是否大于2
  120. const isMultipleRoute = (route: AppRouteRecordRaw) => {
  121. if (!route || !Reflect.has(route, 'children') || !route.children?.length) {
  122. return false
  123. }
  124. const children = route.children
  125. let flag = false
  126. for (let index = 0; index < children.length; index++) {
  127. const child = children[index]
  128. if (child.children?.length) {
  129. flag = true
  130. break
  131. }
  132. }
  133. return flag
  134. }
  135. // 生成二级路由
  136. const promoteRouteLevel = (route: AppRouteRecordRaw) => {
  137. let router: Router | null = createRouter({
  138. routes: [route as unknown as RouteRecordNormalized],
  139. history: createWebHashHistory()
  140. })
  141. const routes = router.getRoutes()
  142. addToChildren(routes, route.children || [], route)
  143. router = null
  144. route.children = route.children?.map((item) => omit(item, 'children'))
  145. }
  146. // 添加所有子菜单
  147. const addToChildren = (
  148. routes: RouteRecordNormalized[],
  149. children: AppRouteRecordRaw[],
  150. routeModule: AppRouteRecordRaw
  151. ) => {
  152. for (let index = 0; index < children.length; index++) {
  153. const child = children[index]
  154. const route = routes.find((item) => item.name === child.name)
  155. if (!route) {
  156. continue
  157. }
  158. routeModule.children = routeModule.children || []
  159. if (!routeModule.children.find((item) => item.name === route.name)) {
  160. routeModule.children?.push(route as unknown as AppRouteRecordRaw)
  161. }
  162. if (child.children?.length) {
  163. addToChildren(routes, child.children, routeModule)
  164. }
  165. }
  166. }