@@ -19,35 +19,82 @@ function isExternalUrl(val) {
1919 return  typeof  val  ===  'string'  &&  / ^ ( h t t p s ? : ) ? \/ \/ / . 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