routerHelper.ts 5.9 KB

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