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 }