feat
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { DEFAULT_LAYOUT } from './routes/base'
|
||||
import { DEFAULT_LAYOUT, STANDALONE_LAYOUT } from './routes/base'
|
||||
import type { AppRouteRecordRaw } from './routes/types'
|
||||
import type { TreeNodeBase } from '@/utils/tree'
|
||||
|
||||
@@ -23,6 +23,8 @@ export interface ServerMenuItem extends TreeNodeBase {
|
||||
requiresAuth?: boolean
|
||||
roles?: string[]
|
||||
children?: ServerMenuItem[]
|
||||
is_full?: boolean // 是否为独立页面(不包含菜单栏)
|
||||
hide_menu?: boolean // 是否隐藏菜单栏
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
@@ -74,42 +76,60 @@ export function transformMenuToRoutes(menuItems: ServerMenuItem[]): AppRouteReco
|
||||
const routes: AppRouteRecordRaw[] = []
|
||||
|
||||
for (const item of menuItems) {
|
||||
// 根据 is_full 决定如何设置 component
|
||||
let routeComponent: AppRouteRecordRaw['component']
|
||||
|
||||
if (item.is_full) {
|
||||
// 独立页面:直接加载视图组件,不使用布局
|
||||
if (item.component) {
|
||||
routeComponent = loadViewComponent(item.component)
|
||||
} else {
|
||||
// 如果没有 component,使用默认重定向页面
|
||||
routeComponent = () => import('@/views/redirect/index.vue')
|
||||
}
|
||||
} else {
|
||||
// 非独立页面:使用默认布局
|
||||
routeComponent = DEFAULT_LAYOUT
|
||||
}
|
||||
|
||||
const route: AppRouteRecordRaw = {
|
||||
path: item.menu_path || '',
|
||||
name: item.title || item.name || `menu_${item.id}`,
|
||||
component: routeComponent,
|
||||
meta: {
|
||||
// ...item,
|
||||
locale: item.locale || item.title,
|
||||
requiresAuth: item.requiresAuth !== false,
|
||||
icon: item.icon || item?.menu_icon,
|
||||
order: item.sort_key ?? item.order,
|
||||
hideInMenu: item.hideInMenu,
|
||||
hideInMenu: item.hideInMenu || item.hide_menu,
|
||||
hideChildrenInMenu: item.hideChildrenInMenu,
|
||||
roles: item.roles,
|
||||
isNewTab: item.is_new_tab,
|
||||
},
|
||||
component: DEFAULT_LAYOUT,
|
||||
}
|
||||
|
||||
// 处理子菜单
|
||||
if (item.children && item.children.length > 0) {
|
||||
// 传递父级的 component 和 path 给子路由处理函数
|
||||
route.children = transformChildRoutes(item.children, item.component, item.menu_path)
|
||||
} else if (item.component) {
|
||||
// 一级菜单没有 children 但有 component,创建一个空路径的子路由
|
||||
const routeName = route.name
|
||||
route.children = [
|
||||
{
|
||||
path: item.menu_path || '',
|
||||
name: typeof routeName === 'string' ? `${routeName}Index` : `menu_${item.id}_index`,
|
||||
component: loadViewComponent(item.component),
|
||||
meta: {
|
||||
locale: item.locale || item.title,
|
||||
requiresAuth: item.requiresAuth !== false,
|
||||
isNewTab: item.is_new_tab,
|
||||
// 非独立页面需要处理子菜单
|
||||
if (!item.is_full) {
|
||||
if (item.children && item.children.length > 0) {
|
||||
// 传递父级的 component 和 path 给子路由处理函数
|
||||
route.children = transformChildRoutes(item.children, item.component, item.menu_path, false)
|
||||
} else if (item.component) {
|
||||
// 一级菜单没有 children 但有 component,创建一个空路径的子路由
|
||||
const routeName = route.name
|
||||
route.children = [
|
||||
{
|
||||
path: item.menu_path || '',
|
||||
name: typeof routeName === 'string' ? `${routeName}Index` : `menu_${item.id}_index`,
|
||||
component: loadViewComponent(item.component),
|
||||
meta: {
|
||||
locale: item.locale || item.title,
|
||||
requiresAuth: item.requiresAuth !== false,
|
||||
isNewTab: item.is_new_tab,
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
routes.push(route)
|
||||
@@ -158,12 +178,14 @@ function extractRelativePath(childPath: string, parentPath: string): string {
|
||||
* @param children 子菜单项
|
||||
* @param parentComponent 父级菜单的 component 字段(用于子菜单没有 component 时继承)
|
||||
* @param parentPath 父级菜单的路径(用于计算相对路径)
|
||||
* @param parentIsFull 父级菜单的 is_full 字段
|
||||
* @returns 子路由配置数组
|
||||
*/
|
||||
function transformChildRoutes(
|
||||
children: ServerMenuItem[],
|
||||
parentComponent?: string,
|
||||
parentPath?: string
|
||||
parentPath?: string,
|
||||
parentIsFull?: boolean
|
||||
): AppRouteRecordRaw[] {
|
||||
return children.map((child) => {
|
||||
// 优先使用子菜单自己的 component,否则继承父级的 component
|
||||
@@ -180,6 +202,7 @@ function transformChildRoutes(
|
||||
locale: child.locale || child.title,
|
||||
requiresAuth: child.requiresAuth !== false,
|
||||
roles: child.roles,
|
||||
hideInMenu: child.hideInMenu || child.hide_menu,
|
||||
},
|
||||
component: componentPath
|
||||
? loadViewComponent(componentPath)
|
||||
@@ -191,7 +214,8 @@ function transformChildRoutes(
|
||||
route.children = transformChildRoutes(
|
||||
child.children,
|
||||
child.component || parentComponent,
|
||||
childFullPath // 传递当前子菜单的完整路径作为下一层的父路径
|
||||
childFullPath, // 传递当前子菜单的完整路径作为下一层的父路径
|
||||
child.is_full || parentIsFull // 传递 is_full 标志
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { REDIRECT_ROUTE_NAME } from '@/router/constants'
|
||||
import type { RouteRecordRaw } from 'vue-router'
|
||||
|
||||
export const DEFAULT_LAYOUT = () => import('@/layout/default-layout.vue')
|
||||
export const STANDALONE_LAYOUT = () => import('@/layout/standalone-layout.vue')
|
||||
|
||||
export const REDIRECT_MAIN: RouteRecordRaw = {
|
||||
path: '/redirect',
|
||||
|
||||
@@ -73,6 +73,16 @@ const OPS: AppRouteRecordRaw = {
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'report/history',
|
||||
name: 'ReportHistory',
|
||||
component: () => import('@/views/ops/pages/report/history/index.vue'),
|
||||
meta: {
|
||||
locale: 'menu.ops.report.history',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
45
src/router/routes/modules/remote.ts
Normal file
45
src/router/routes/modules/remote.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { DEFAULT_LAYOUT } from '../base'
|
||||
import { AppRouteRecordRaw } from '../types'
|
||||
|
||||
const REMOTE: AppRouteRecordRaw = {
|
||||
path: '/dc',
|
||||
name: 'DC',
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: 'menu.dc',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-desktop',
|
||||
order: 99,
|
||||
hideInMenu: true,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'detail',
|
||||
name: 'DCDetail',
|
||||
component: () => import('@/views/ops/pages/dc/detail/index.vue'),
|
||||
meta: {
|
||||
locale: 'menu.dc.detail',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
hideInMenu: true,
|
||||
is_full: true,
|
||||
isNewTab: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'remote',
|
||||
name: 'DCRemote',
|
||||
component: () => import('@/views/ops/pages/dc/remote/index.vue'),
|
||||
meta: {
|
||||
locale: 'menu.dc.remote',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
hideInMenu: true,
|
||||
is_full: true,
|
||||
isNewTab: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export default REMOTE
|
||||
Reference in New Issue
Block a user