123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- import type { RouteLocationNormalized, Router, RouteRecordNormalized } from 'vue-router'
- import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
- import { isUrl } from '@/utils/is'
- import { cloneDeep, omit } from 'lodash-es'
- const modules = import.meta.glob('../views/**/*.{vue,tsx}')
- /**
- * 注册一个异步组件
- * @param componentPath 例:/bpm/oa/leave/detail
- */
- export const registerComponent = (componentPath: string) => {
- for (const item in modules) {
- if (item.includes(componentPath)) {
- // 使用异步组件的方式来动态加载组件
- // @ts-ignore
- return defineAsyncComponent(modules[item])
- }
- }
- }
- /* Layout */
- export const Layout = () => import('@/layout/Layout.vue')
- export const getParentLayout = () => {
- return () =>
- new Promise((resolve) => {
- resolve({
- name: 'ParentLayout'
- })
- })
- }
- // 按照路由中meta下的rank等级升序来排序路由
- export const ascending = (arr: any[]) => {
- arr.forEach((v) => {
- if (v?.meta?.rank === null) v.meta.rank = undefined
- if (v?.meta?.rank === 0) {
- if (v.name !== 'home' && v.path !== '/') {
- console.warn('rank only the home page can be 0')
- }
- }
- })
- return arr.sort((a: { meta: { rank: number } }, b: { meta: { rank: number } }) => {
- return a?.meta?.rank - b?.meta?.rank
- })
- }
- export const getRawRoute = (route: RouteLocationNormalized): RouteLocationNormalized => {
- if (!route) return route
- const { matched, ...opt } = route
- return {
- ...opt,
- matched: (matched
- ? matched.map((item) => ({
- meta: item.meta,
- name: item.name,
- path: item.path
- }))
- : undefined) as RouteRecordNormalized[]
- }
- }
- // 后端控制路由生成
- export const generateRoute = (routes: AppCustomRouteRecordRaw[]): AppRouteRecordRaw[] => {
- const res: AppRouteRecordRaw[] = []
- const modulesRoutesKeys = Object.keys(modules)
- for (const route of routes) {
- const meta = {
- title: route.name,
- icon: route.icon,
- hidden: !route.visible,
- noCache: !route.keepAlive,
- alwaysShow:
- route.children &&
- route.children.length === 1 &&
- (route.alwaysShow !== undefined ? route.alwaysShow : true)
- }
- // 路由地址转首字母大写驼峰,作为路由名称,适配keepAlive
- let data: AppRouteRecordRaw = {
- path: route.path,
- name:
- route.componentName && route.componentName.length > 0
- ? route.componentName
- : toCamelCase(route.path, true),
- redirect: route.redirect,
- meta: meta
- }
- //处理顶级非目录路由
- if (!route.children && route.parentId == 0 && route.component) {
- data.component = Layout
- data.meta = {}
- data.name = toCamelCase(route.path, true) + 'Parent'
- data.redirect = ''
- meta.alwaysShow = true
- const childrenData: AppRouteRecordRaw = {
- path: '',
- name:
- route.componentName && route.componentName.length > 0
- ? route.componentName
- : toCamelCase(route.path, true),
- redirect: route.redirect,
- meta: meta
- }
- const index = route?.component
- ? modulesRoutesKeys.findIndex((ev) => ev.includes(route.component))
- : modulesRoutesKeys.findIndex((ev) => ev.includes(route.path))
- childrenData.component = modules[modulesRoutesKeys[index]]
- data.children = [childrenData]
- } else {
- // 目录
- if (route.children) {
- data.component = Layout
- data.redirect = getRedirect(route.path, route.children)
- // 外链
- } else if (isUrl(route.path)) {
- data = {
- path: '/external-link',
- component: Layout,
- meta: {
- name: route.name
- },
- children: [data]
- } as AppRouteRecordRaw
- // 菜单
- } else {
- // 对后端传component组件路径和不传做兼容(如果后端传component组件路径,那么path可以随便写,如果不传,component组件路径会根path保持一致)
- const index = route?.component
- ? modulesRoutesKeys.findIndex((ev) => ev.includes(route.component))
- : modulesRoutesKeys.findIndex((ev) => ev.includes(route.path))
- data.component = modules[modulesRoutesKeys[index]]
- }
- if (route.children) {
- data.children = generateRoute(route.children)
- }
- }
- res.push(data as AppRouteRecordRaw)
- }
- return res
- }
- export const getRedirect = (parentPath: string, children: AppCustomRouteRecordRaw[]) => {
- if (!children || children.length == 0) {
- return parentPath
- }
- const path = generateRoutePath(parentPath, children[0].path)
- // 递归子节点
- if (children[0].children) return getRedirect(path, children[0].children)
- }
- const generateRoutePath = (parentPath: string, path: string) => {
- if (parentPath.endsWith('/')) {
- parentPath = parentPath.slice(0, -1) // 移除默认的 /
- }
- if (!path.startsWith('/')) {
- path = '/' + path
- }
- return parentPath + path
- }
- export const pathResolve = (parentPath: string, path: string) => {
- if (isUrl(path)) return path
- const childPath = path.startsWith('/') || !path ? path : `/${path}`
- return `${parentPath}${childPath}`.replace(/\/\//g, '/')
- }
- // 路由降级
- export const flatMultiLevelRoutes = (routes: AppRouteRecordRaw[]) => {
- const modules: AppRouteRecordRaw[] = cloneDeep(routes)
- for (let index = 0; index < modules.length; index++) {
- const route = modules[index]
- if (!isMultipleRoute(route)) {
- continue
- }
- promoteRouteLevel(route)
- }
- return modules
- }
- // 层级是否大于2
- const isMultipleRoute = (route: AppRouteRecordRaw) => {
- if (!route || !Reflect.has(route, 'children') || !route.children?.length) {
- return false
- }
- const children = route.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
- }
- // 生成二级路由
- const promoteRouteLevel = (route: AppRouteRecordRaw) => {
- let router: Router | null = createRouter({
- routes: [route as RouteRecordRaw],
- history: createWebHashHistory()
- })
- const routes = router.getRoutes()
- addToChildren(routes, route.children || [], route)
- router = null
- route.children = route.children?.map((item) => omit(item, 'children'))
- }
- // 添加所有子菜单
- const addToChildren = (
- routes: RouteRecordNormalized[],
- children: AppRouteRecordRaw[],
- routeModule: AppRouteRecordRaw
- ) => {
- for (let index = 0; index < children.length; index++) {
- const child = children[index]
- const route = routes.find((item) => item.name === child.name)
- if (!route) {
- continue
- }
- routeModule.children = routeModule.children || []
- if (!routeModule.children.find((item) => item.name === route.name)) {
- routeModule.children?.push(route as unknown as AppRouteRecordRaw)
- }
- if (child.children?.length) {
- addToChildren(routes, child.children, routeModule)
- }
- }
- }
- const toCamelCase = (str: string, upperCaseFirst: boolean) => {
- str = (str || '')
- .replace(/-(.)/g, function (group1: string) {
- return group1.toUpperCase()
- })
- .replaceAll('-', '')
- if (upperCaseFirst && str) {
- str = str.charAt(0).toUpperCase() + str.slice(1)
- }
- return str
- }
|