Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit d0829fb

Browse files
Merge pull request #2123 from Azir-11/dev-286
refactor(路由管理): 优化路由添加逻辑,增强路径处理和顶级路由注册
2 parents fd03e44 + c7f3504 commit d0829fb

File tree

1 file changed

+58
-10
lines changed

1 file changed

+58
-10
lines changed

‎web/src/permission.js‎

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,35 +19,82 @@ function isExternalUrl(val) {
1919
return typeof val === 'string' && /^(https?:)?\/\//.test(val)
2020
}
2121

22-
// 将 n 级菜单扁平化为:一级 layout + 二级页面组件
23-
function addRouteByChildren(route, segments = []) {
22+
// 工具函数:统一路径归一化
23+
function normalizeAbsolutePath(p) {
24+
const s = '/' + String(p || '')
25+
return s.replace(/\/+/g, '/')
26+
}
27+
28+
function normalizeRelativePath(p) {
29+
return String(p || '').replace(/^\/+/, '')
30+
}
31+
32+
// 安全注册:仅在路由名未存在时注册顶级路由
33+
function addTopLevelIfAbsent(r) {
34+
if (!router.hasRoute(r.name)) {
35+
router.addRoute(r)
36+
}
37+
}
38+
39+
// 将 n 级菜单扁平化为:
40+
// - 常规:一级 layout + 二级页面组件
41+
// - 若某节点 meta.defaultMenu === true:该节点为顶级(不包裹在 layout 下),其子节点作为该顶级的二级页面组件
42+
function addRouteByChildren(route, segments = [], parentName = null) {
2443
// 跳过外链根节点
2544
if (isExternalUrl(route?.path) || isExternalUrl(route?.name) || isExternalUrl(route?.component)) {
2645
return
2746
}
2847

2948
// 顶层 layout 仅用于承载,不参与路径拼接
3049
if (route?.name === 'layout') {
31-
route.children?.forEach((child) => addRouteByChildren(child, []))
50+
route.children?.forEach((child) => addRouteByChildren(child, [], null))
51+
return
52+
}
53+
54+
// 如果标记为 defaultMenu,则该路由应作为顶级路由(不包裹在 layout 下)
55+
if (route?.meta?.defaultMenu === true && parentName === null) {
56+
const fullPath = [...segments, route.path].filter(Boolean).join('/')
57+
const children = route.children ? [...route.children] : []
58+
const newRoute = { ...route, path: fullPath }
59+
delete newRoute.children
60+
delete newRoute.parent
61+
// 顶级路由使用绝对路径
62+
newRoute.path = normalizeAbsolutePath(newRoute.path)
63+
64+
// 若已存在同名路由则整体跳过(之前应已处理过其子节点)
65+
if (router.hasRoute(newRoute.name)) return
66+
addTopLevelIfAbsent(newRoute)
67+
68+
// 若该 defaultMenu 节点仍有子节点,继续递归处理其子节点(挂载到该顶级路由下)
69+
if (children.length) {
70+
// 重置片段,使其成为顶级下的二级相对路径
71+
children.forEach((child) => addRouteByChildren(child, [], newRoute.name))
72+
}
3273
return
3374
}
3475

3576
// 还有子节点,继续向下收集路径片段(忽略外链片段)
3677
if (route?.children && route.children.length) {
3778
const nextSegments = isExternalUrl(route.path) ? segments : [...segments, route.path]
38-
route.children.forEach((child) => addRouteByChildren(child, nextSegments))
79+
route.children.forEach((child) => addRouteByChildren(child, nextSegments,parentName))
3980
return
4081
}
4182

42-
// 叶子节点:注册为 layout 的二级子路由
83+
// 叶子节点:注册为其父(defaultMenu 顶级或 layout)的二级子路由
4384
const fullPath = [...segments, route.path].filter(Boolean).join('/')
4485
const newRoute = { ...route, path: fullPath }
4586
delete newRoute.children
4687
delete newRoute.parent
4788
// 子路由使用相对路径,避免 /layout/layout/... 的问题
48-
newRoute.path = newRoute.path.replace(/^\/+/, '')
49-
50-
router.addRoute('layout', newRoute)
89+
newRoute.path = normalizeRelativePath(newRoute.path)
90+
91+
if (parentName) {
92+
// 挂载到 defaultMenu 顶级路由下
93+
router.addRoute(parentName, newRoute)
94+
} else {
95+
// 常规:挂载到 layout 下
96+
router.addRoute('layout', newRoute)
97+
}
5198
}
5299

53100
// 处理路由加载
@@ -60,7 +107,8 @@ const setupRouter = async (userStore) => {
60107
const baseRouters = routerStore.asyncRouters || []
61108
const layoutRoute = baseRouters[0]
62109
if (layoutRoute?.name === 'layout' && !router.hasRoute('layout')) {
63-
router.addRoute(layoutRoute)
110+
const bareLayout = { ...layoutRoute, children: [] }
111+
router.addRoute(bareLayout)
64112
}
65113

66114
// 扁平化:将 layout.children 与其余顶层异步路由一并作为二级子路由注册到 layout 下
@@ -73,7 +121,7 @@ const setupRouter = async (userStore) => {
73121
if (r?.name !== 'layout') toRegister.push(r)
74122
})
75123
}
76-
toRegister.forEach((r) => addRouteByChildren(r, []))
124+
toRegister.forEach((r) => addRouteByChildren(r, [],null))
77125
return true
78126
} catch (error) {
79127
console.error('Setup router failed:', error)

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /