github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/static_source/admin/src/utils/routerHelper.ts (about)

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