feat(router): Add dynamic routing
parent
95a2bd884d
commit
b218ccc9cc
@ -1,9 +1,16 @@
|
|||||||
<script setup lang="ts"></script>
|
<script setup lang="ts">
|
||||||
|
// import { computed } from 'vue'
|
||||||
|
// const getCaches = computed((): string[] => {
|
||||||
|
// return []
|
||||||
|
// })
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section>
|
<RouterView>
|
||||||
<router-view v-slot="{ Component, route }">
|
<template #default="{ Component, route }">
|
||||||
<component :is="Component" :key="route.fullPath" />
|
<KeepAlive>
|
||||||
</router-view>
|
<Component :is="Component" :key="route.fullPath" />
|
||||||
</section>
|
</KeepAlive>
|
||||||
|
</template>
|
||||||
|
</RouterView>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -1,27 +0,0 @@
|
|||||||
import ParentLayout from '@/components/ParentView/index.vue'
|
|
||||||
import type { RouteLocationNormalized, RouteRecordNormalized } from 'vue-router'
|
|
||||||
|
|
||||||
export const getParentLayout = (name: string) => {
|
|
||||||
return () =>
|
|
||||||
new Promise((resolve) => {
|
|
||||||
resolve({
|
|
||||||
...ParentLayout,
|
|
||||||
name
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getRoute(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[]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,192 @@
|
|||||||
|
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||||
|
import type { Router, RouteLocationNormalized, RouteRecordNormalized } from 'vue-router'
|
||||||
|
import { isUrl } from '@/utils/is'
|
||||||
|
import { useCache } from '@/hooks/web/useCache'
|
||||||
|
import { useAppStoreWithOut } from '@/store/modules/app'
|
||||||
|
import { omit, cloneDeep } from 'lodash-es'
|
||||||
|
|
||||||
|
const appStore = useAppStoreWithOut()
|
||||||
|
|
||||||
|
const { wsCache } = useCache()
|
||||||
|
|
||||||
|
const modules = import.meta.glob('../../views/**/*.{vue,tsx}')
|
||||||
|
|
||||||
|
/* Layout */
|
||||||
|
const Layout = () => import('@/layout/index.vue')
|
||||||
|
|
||||||
|
export const getParentLayout = () => {
|
||||||
|
return () =>
|
||||||
|
new Promise((resolve) => {
|
||||||
|
resolve({
|
||||||
|
name: 'ParentLayout'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRoute(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 function generateRoutesFn1(
|
||||||
|
routes: AppRouteRecordRaw[],
|
||||||
|
basePath = '/'
|
||||||
|
): AppRouteRecordRaw[] {
|
||||||
|
const res: AppRouteRecordRaw[] = []
|
||||||
|
|
||||||
|
for (const route of routes) {
|
||||||
|
// skip some route
|
||||||
|
if (route.meta && route.meta.hidden && !route.meta.showMainRoute) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
let data: Nullable<AppRouteRecordRaw> = null
|
||||||
|
|
||||||
|
let onlyOneChild: Nullable<string> = null
|
||||||
|
|
||||||
|
if (route.children && route.children.length === 1 && !route.meta.alwaysShow) {
|
||||||
|
onlyOneChild = (
|
||||||
|
isUrl(route.children[0].path)
|
||||||
|
? route.children[0].path
|
||||||
|
: pathResolve(pathResolve(basePath, route.path), route.children[0].path)
|
||||||
|
) as string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 权限过滤,通过获取登录信息里面的角色权限,动态的渲染菜单。
|
||||||
|
const list = wsCache.get(appStore.getUserInfo).checkedNodes
|
||||||
|
// 开发者可以根据实际情况进行扩展
|
||||||
|
for (const item of list) {
|
||||||
|
// 通过路径去匹配
|
||||||
|
if (isUrl(item.path) && (onlyOneChild === item.path || route.path === item.path)) {
|
||||||
|
data = Object.assign({}, route)
|
||||||
|
} else {
|
||||||
|
const routePath = pathResolve(basePath, onlyOneChild || route.path)
|
||||||
|
if (routePath === item.path || (route.meta && route.meta.followRoute === item.path)) {
|
||||||
|
data = Object.assign({}, route)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// recursive child routes
|
||||||
|
if (route.children && data) {
|
||||||
|
data.children = generateRoutesFn1(route.children, pathResolve(basePath, data.path))
|
||||||
|
}
|
||||||
|
if (data) {
|
||||||
|
res.push(data as AppRouteRecordRaw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// 后端控制路由生成
|
||||||
|
export function generateRoutesFn2(routes: AppRouteRecordRaw[]): AppRouteRecordRaw[] {
|
||||||
|
const res: AppRouteRecordRaw[] = []
|
||||||
|
|
||||||
|
for (const route of routes) {
|
||||||
|
const data: AppRouteRecordRaw = {
|
||||||
|
path: route.path,
|
||||||
|
name: route.name,
|
||||||
|
redirect: route.redirect,
|
||||||
|
meta: route.meta
|
||||||
|
}
|
||||||
|
if (route.component) {
|
||||||
|
// 动态加载路由文件,可根据实际情况进行自定义逻辑
|
||||||
|
const component = route.component as string
|
||||||
|
data.component =
|
||||||
|
component === '#'
|
||||||
|
? Layout
|
||||||
|
: component.includes('##')
|
||||||
|
? getParentLayout()
|
||||||
|
: modules[`../../${route.component}.vue`] || modules[`../../${route.component}.tsx`]
|
||||||
|
}
|
||||||
|
// recursive child routes
|
||||||
|
if (route.children) {
|
||||||
|
data.children = generateRoutesFn2(route.children)
|
||||||
|
}
|
||||||
|
res.push(data as AppRouteRecordRaw)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pathResolve(parentPath: string, path: string) {
|
||||||
|
return `${parentPath}/${path}`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 路由降级
|
||||||
|
export function 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
|
||||||
|
function 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 路由降级
|
||||||
|
function promoteRouteLevel(route: AppRouteRecordRaw) {
|
||||||
|
let router: Router | null = createRouter({
|
||||||
|
routes: [route as unknown as RouteRecordNormalized],
|
||||||
|
history: createWebHashHistory()
|
||||||
|
})
|
||||||
|
|
||||||
|
const routes = router.getRoutes()
|
||||||
|
addToChildren(routes, route.children || [], route)
|
||||||
|
router = null
|
||||||
|
|
||||||
|
route.children = route.children?.map((item) => omit(item, 'children'))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加所有子菜单
|
||||||
|
function 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts"></script>
|
<script setup lang="ts"></script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>Menu11</div>
|
<div>Menu111</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Loading…
Reference in New Issue