feat
This commit is contained in:
@@ -13,6 +13,6 @@ export const DEFAULT_ROUTE_NAME = 'Workplace'
|
||||
|
||||
export const DEFAULT_ROUTE = {
|
||||
title: 'menu.dashboard.workplace',
|
||||
name: DEFAULT_ROUTE_NAME,
|
||||
fullPath: '/dashboard/workplace',
|
||||
name: 'overview',
|
||||
fullPath: '/overview',
|
||||
}
|
||||
|
||||
@@ -1,40 +1,73 @@
|
||||
import NProgress from 'nprogress' // progress bar
|
||||
import type { Router, RouteRecordNormalized } from 'vue-router'
|
||||
import type { Router, RouteLocationRaw } from 'vue-router'
|
||||
|
||||
import usePermission from '@/hooks/permission'
|
||||
import { useAppStore, useUserStore } from '@/store'
|
||||
import { NOT_FOUND, WHITE_LIST } from '../constants'
|
||||
import { appRoutes } from '../routes'
|
||||
|
||||
// 标记菜单是否正在加载,防止重复加载
|
||||
let isMenuLoading = false
|
||||
// 标记菜单是否已加载
|
||||
let isMenuLoaded = false
|
||||
|
||||
export default function setupPermissionGuard(router: Router) {
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
const appStore = useAppStore()
|
||||
const userStore = useUserStore()
|
||||
const Permission = usePermission()
|
||||
const permissionsAllow = Permission.accessRouter(to)
|
||||
|
||||
if (appStore.menuFromServer) {
|
||||
// 针对来自服务端的菜单配置进行处理
|
||||
// Handle routing configuration from the server
|
||||
|
||||
// 根据需要自行完善来源于服务端的菜单配置的permission逻辑
|
||||
// Refine the permission logic from the server's menu configuration as needed
|
||||
if (!appStore.appAsyncMenus.length && !WHITE_LIST.find((el) => el.name === to.name)) {
|
||||
await appStore.fetchServerMenuConfig()
|
||||
}
|
||||
const serverMenuConfig = [...appStore.appAsyncMenus, ...WHITE_LIST]
|
||||
|
||||
let exist = false
|
||||
while (serverMenuConfig.length && !exist) {
|
||||
const element = serverMenuConfig.shift()
|
||||
if (element?.name === to.name) exist = true
|
||||
|
||||
if (element?.children) {
|
||||
serverMenuConfig.push(...(element.children as unknown as RouteRecordNormalized[]))
|
||||
}
|
||||
}
|
||||
if (exist && permissionsAllow) {
|
||||
// 检查是否在白名单中
|
||||
if (WHITE_LIST.find((el) => el.name === to.name)) {
|
||||
next()
|
||||
} else next(NOT_FOUND)
|
||||
NProgress.done()
|
||||
return
|
||||
}
|
||||
console.log('[Permission Guard] Menu not loaded, loading...')
|
||||
|
||||
// 检查动态路由是否已加载(使用标志位而非菜单长度,更可靠)
|
||||
if (!isMenuLoaded && !isMenuLoading) {
|
||||
console.log('[Permission Guard] Menu not loaded, loading...')
|
||||
// 设置加载标志
|
||||
isMenuLoading = true
|
||||
try {
|
||||
// 动态路由未加载,先获取菜单配置并注册路由
|
||||
await appStore.fetchServerMenuConfig()
|
||||
// 标记加载完成
|
||||
isMenuLoaded = true
|
||||
console.log('[Permission Guard] Menu loaded, redirecting to:', to.path)
|
||||
// 路由注册后需要重新导航到当前路径
|
||||
next({ path: to.path, query: to.query, params: to.params, replace: true } as RouteLocationRaw)
|
||||
} catch (error) {
|
||||
console.error('[Permission Guard] Failed to load menu:', error)
|
||||
isMenuLoading = false
|
||||
next(NOT_FOUND)
|
||||
} finally {
|
||||
isMenuLoading = false
|
||||
}
|
||||
NProgress.done()
|
||||
return
|
||||
}
|
||||
|
||||
// 如果正在加载菜单,等待加载完成
|
||||
if (isMenuLoading) {
|
||||
next({ path: to.path, query: to.query, params: to.params, replace: true } as RouteLocationRaw)
|
||||
NProgress.done()
|
||||
return
|
||||
}
|
||||
|
||||
// 动态路由已加载,直接放行
|
||||
// 因为路由已经通过 addRoute 注册,Vue Router 会自动匹配
|
||||
if (permissionsAllow) {
|
||||
next()
|
||||
} else {
|
||||
next(NOT_FOUND)
|
||||
}
|
||||
} else {
|
||||
// eslint-disable-next-line no-lonely-if
|
||||
if (permissionsAllow) next()
|
||||
|
||||
@@ -4,7 +4,7 @@ import { createRouter, createWebHashHistory } from 'vue-router'
|
||||
|
||||
import createRouteGuard from './guard'
|
||||
import { appRoutes } from './routes'
|
||||
import { NOT_FOUND_ROUTE, REDIRECT_MAIN } from './routes/base'
|
||||
import { DEFAULT_LAYOUT, NOT_FOUND_ROUTE, REDIRECT_MAIN } from './routes/base'
|
||||
|
||||
NProgress.configure({ showSpinner: false }) // NProgress Configuration
|
||||
|
||||
@@ -25,7 +25,7 @@ const router = createRouter({
|
||||
},
|
||||
...appRoutes,
|
||||
REDIRECT_MAIN,
|
||||
NOT_FOUND_ROUTE,
|
||||
// NOT_FOUND_ROUTE,
|
||||
],
|
||||
scrollBehavior() {
|
||||
return { top: 0 }
|
||||
|
||||
@@ -1,5 +1,194 @@
|
||||
import { DEFAULT_LAYOUT } from './routes/base'
|
||||
import type { AppRouteRecordRaw } from './routes/types'
|
||||
import type { TreeNodeBase } from '@/utils/tree'
|
||||
|
||||
/**
|
||||
* 服务器返回的菜单数据结构
|
||||
*/
|
||||
export interface ServerMenuItem extends TreeNodeBase {
|
||||
id: number | string
|
||||
parent_id: number | string | null
|
||||
name?: string
|
||||
title?: string // 菜单标题
|
||||
title_en?: string // 英文标题
|
||||
code?: string // 菜单编码
|
||||
menu_path?: string // 菜单路径,如 '/overview'
|
||||
component?: string // 组件路径,如 'ops/pages/overview'
|
||||
icon?: string
|
||||
locale?: string
|
||||
sort_key?: number // 排序字段
|
||||
order?: number
|
||||
hideInMenu?: boolean
|
||||
hideChildrenInMenu?: boolean
|
||||
requiresAuth?: boolean
|
||||
roles?: string[]
|
||||
children?: ServerMenuItem[]
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
// 预定义的视图模块映射(用于 Vite 动态导入)
|
||||
const viewModules = import.meta.glob('@/views/**/*.vue')
|
||||
|
||||
/**
|
||||
* 动态加载视图组件
|
||||
* @param componentPath 组件路径,如 'ops/pages/overview' 或 'ops/pages/overview/index'
|
||||
* @returns 动态导入的组件
|
||||
*/
|
||||
export function loadViewComponent(componentPath: string) {
|
||||
// 将路径转换为完整的视图路径
|
||||
// 如果路径不以 /index 结尾,自动补全
|
||||
let fullPath = componentPath
|
||||
if (!fullPath.endsWith('/index') && !fullPath.endsWith('.vue')) {
|
||||
fullPath = `${fullPath}/index`
|
||||
}
|
||||
|
||||
// 构建完整的文件路径
|
||||
const filePath = `/src/views/${fullPath}.vue`
|
||||
|
||||
// 从预加载的模块中查找
|
||||
const modulePath = Object.keys(viewModules).find((path) => path.endsWith(filePath) || path === filePath)
|
||||
|
||||
if (modulePath && viewModules[modulePath]) {
|
||||
return viewModules[modulePath]
|
||||
}
|
||||
|
||||
// 如果找不到,返回一个默认组件或抛出错误
|
||||
console.warn(`View component not found: ${filePath}`)
|
||||
return () => import('@/views/redirect/index.vue')
|
||||
}
|
||||
|
||||
/**
|
||||
* 将服务器菜单数据转换为路由配置
|
||||
* @param menuItems 服务器返回的菜单项(树状结构)
|
||||
* @returns 路由配置数组
|
||||
*/
|
||||
export function transformMenuToRoutes(menuItems: ServerMenuItem[]): AppRouteRecordRaw[] {
|
||||
const routes: AppRouteRecordRaw[] = []
|
||||
|
||||
for (const item of menuItems) {
|
||||
const route: AppRouteRecordRaw = {
|
||||
path: item.menu_path || '',
|
||||
name: item.title || item.name || `menu_${item.id}`,
|
||||
meta: {
|
||||
locale: item.locale || item.title,
|
||||
requiresAuth: item.requiresAuth !== false,
|
||||
icon: item.icon,
|
||||
order: item.sort_key ?? item.order,
|
||||
hideInMenu: item.hideInMenu,
|
||||
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
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
routes.push(route)
|
||||
}
|
||||
|
||||
return routes
|
||||
}
|
||||
|
||||
/**
|
||||
* 将路径转换为相对路径(去掉开头的 /)
|
||||
* @param path 路径
|
||||
* @returns 相对路径
|
||||
*/
|
||||
function toRelativePath(path: string): string {
|
||||
if (!path) return ''
|
||||
// 去掉开头的 /
|
||||
return path.startsWith('/') ? path.slice(1) : path
|
||||
}
|
||||
|
||||
/**
|
||||
* 从完整路径中提取子路由的相对路径
|
||||
* 例如:父路径 '/dashboard',子路径 '/dashboard/workplace' -> 'workplace'
|
||||
* @param childPath 子菜单的完整路径
|
||||
* @param parentPath 父菜单的路径
|
||||
* @returns 相对路径
|
||||
*/
|
||||
function extractRelativePath(childPath: string, parentPath: string): string {
|
||||
if (!childPath) return ''
|
||||
|
||||
// 如果子路径以父路径开头,提取相对部分
|
||||
if (parentPath && childPath.startsWith(parentPath)) {
|
||||
let relativePath = childPath.slice(parentPath.length)
|
||||
// 去掉开头的 /
|
||||
if (relativePath.startsWith('/')) {
|
||||
relativePath = relativePath.slice(1)
|
||||
}
|
||||
return relativePath
|
||||
}
|
||||
|
||||
// 否则转换为相对路径
|
||||
return toRelativePath(childPath)
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换子路由配置
|
||||
* @param children 子菜单项
|
||||
* @param parentComponent 父级菜单的 component 字段(用于子菜单没有 component 时继承)
|
||||
* @param parentPath 父级菜单的路径(用于计算相对路径)
|
||||
* @returns 子路由配置数组
|
||||
*/
|
||||
function transformChildRoutes(
|
||||
children: ServerMenuItem[],
|
||||
parentComponent?: string,
|
||||
parentPath?: string
|
||||
): AppRouteRecordRaw[] {
|
||||
return children.map((child) => {
|
||||
// 优先使用子菜单自己的 component,否则继承父级的 component
|
||||
const componentPath = child.component || parentComponent
|
||||
|
||||
// 计算子路由的相对路径
|
||||
const childFullPath = child.menu_path || child.path || ''
|
||||
const relativePath = extractRelativePath(childFullPath, parentPath || '')
|
||||
|
||||
const route: AppRouteRecordRaw = {
|
||||
path: relativePath,
|
||||
name: child.title || child.name || `menu_${child.id}`,
|
||||
meta: {
|
||||
locale: child.locale || child.title,
|
||||
requiresAuth: child.requiresAuth !== false,
|
||||
roles: child.roles,
|
||||
},
|
||||
component: componentPath
|
||||
? loadViewComponent(componentPath)
|
||||
: () => import('@/views/redirect/index.vue'),
|
||||
}
|
||||
|
||||
// 递归处理子菜单的子菜单
|
||||
if (child.children && child.children.length > 0) {
|
||||
route.children = transformChildRoutes(
|
||||
child.children,
|
||||
child.component || parentComponent,
|
||||
childFullPath // 传递当前子菜单的完整路径作为下一层的父路径
|
||||
)
|
||||
}
|
||||
|
||||
return route
|
||||
})
|
||||
}
|
||||
|
||||
// 本地菜单数据 - 接口未准备好时使用
|
||||
export const localMenuData: AppRouteRecordRaw[] = [{
|
||||
@@ -20,10 +209,8 @@ export const localMenuData: AppRouteRecordRaw[] = [{
|
||||
meta: {
|
||||
locale: 'menu.dashboard.workplace',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
/** simple */
|
||||
{
|
||||
path: 'monitor',
|
||||
name: 'Monitor',
|
||||
@@ -31,10 +218,8 @@ export const localMenuData: AppRouteRecordRaw[] = [{
|
||||
meta: {
|
||||
locale: 'menu.dashboard.monitor',
|
||||
requiresAuth: true,
|
||||
roles: ['admin'],
|
||||
},
|
||||
},
|
||||
/** simple end */
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -46,687 +231,15 @@ export const localMenuData: AppRouteRecordRaw[] = [{
|
||||
requiresAuth: true,
|
||||
icon: 'icon-home',
|
||||
order: 1,
|
||||
hideChildrenInMenu: true,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'OverviewIndex',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
component: () => import('@/views/ops/pages/overview/index.vue'),
|
||||
meta: {
|
||||
locale: '系统概况',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/visual',
|
||||
name: 'VisualDashboard',
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: '可视化大屏管理',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-apps',
|
||||
order: 2,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'component',
|
||||
name: 'VisualComponent',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '大屏管理',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'view-publish',
|
||||
name: 'ViewPublish',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '已发布大屏列表',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/dc',
|
||||
name: 'DataCenter',
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: '服务器及PC管理',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-storage',
|
||||
order: 3,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'pc',
|
||||
name: 'OfficePC',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '办公PC管理',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'server',
|
||||
name: 'ServerManagement',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '服务器管理',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/dc/cluster',
|
||||
name: 'ClusterCollection',
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: '集群采集控制中心',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-settings',
|
||||
order: 4,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'database',
|
||||
name: 'DatabaseCollection',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '数据库采集管理',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'middleware',
|
||||
name: 'MiddlewareCollection',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '中间件采集管理',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'network',
|
||||
name: 'NetworkDeviceCollection',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '网络设备采集管理',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/monitor',
|
||||
name: 'Monitor',
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: '综合监控',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-desktop',
|
||||
order: 5,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'log',
|
||||
name: 'LogMonitor',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '日志监控',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'virtualization',
|
||||
name: 'VirtualizationMonitor',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '虚拟化监控',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'storage',
|
||||
name: 'StorageMonitor',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '存储设备监控',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'network',
|
||||
name: 'NetworkMonitor',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '网络设备监控',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'power',
|
||||
name: 'PowerMonitor',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '电力/UPS/空调/温湿度',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'url',
|
||||
name: 'URLMonitor',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: 'URL监控',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'guard',
|
||||
name: 'GuardMonitor',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '消防/门禁/漏水/有害气体',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'security',
|
||||
name: 'SecurityMonitor',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '安全设备监控',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/netarch',
|
||||
name: 'NetworkArchitecture',
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: '网络架构管理',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-nav',
|
||||
order: 6,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'auto-topo',
|
||||
name: 'AutoTopo',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '自动感知拓扑图',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'topo-group',
|
||||
name: 'TopoGroup',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '拓扑管理',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'traffic',
|
||||
name: 'TrafficAnalysis',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '流量分析管理',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'ip',
|
||||
name: 'IPAddress',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: 'IP地址管理',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/alert',
|
||||
name: 'Alert',
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: '告警管理',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-bulb',
|
||||
order: 7,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'setting',
|
||||
name: 'AlertSetting',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '告警策略管理',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'tackle',
|
||||
name: 'AlertTackle',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '告警受理处理',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'history',
|
||||
name: 'AlertHistory',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '告警历史',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'template',
|
||||
name: 'AlertTemplate',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '告警模版',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'notice',
|
||||
name: 'AlertNotice',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '告警通知设置',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'level',
|
||||
name: 'AlertLevel',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '告警级别管理',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/feedback',
|
||||
name: 'Feedback',
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: '工单管理',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-list',
|
||||
order: 8,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'all',
|
||||
name: 'AllTickets',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '所有工单',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'undo',
|
||||
name: 'PendingTickets',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '我的工单',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/datacenter',
|
||||
name: 'DataCenterManagement',
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: '数据中心管理',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-drive-file',
|
||||
order: 9,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'rack',
|
||||
name: 'RackManagement',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '机柜管理',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'house',
|
||||
name: 'DataCenterHouse',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '数据中心',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'floor',
|
||||
name: 'FloorManagement',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '楼层管理',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/assets',
|
||||
name: 'Assets',
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: '资产管理',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-apps',
|
||||
order: 10,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'classify',
|
||||
name: 'AssetClassify',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '设备分类管理',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'device',
|
||||
name: 'AssetDevice',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '设备管理',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'supplier',
|
||||
name: 'AssetSupplier',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '供应商管理',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/kb',
|
||||
name: 'KnowledgeBase',
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: '知识库管理',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-file',
|
||||
order: 11,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'items',
|
||||
name: 'KnowledgeItems',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '知识管理',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'tags',
|
||||
name: 'KnowledgeTags',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '标签管理',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'review',
|
||||
name: 'KnowledgeReview',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '我的审核',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'favorite',
|
||||
name: 'KnowledgeFavorite',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '我的收藏',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'recycle',
|
||||
name: 'KnowledgeRecycle',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '回收站',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/report',
|
||||
name: 'Report',
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: '报告管理',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-nav',
|
||||
order: 12,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'host',
|
||||
name: 'ServerReport',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '服务器报告',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'fault',
|
||||
name: 'FaultReport',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '故障报告',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'device',
|
||||
name: 'DeviceReport',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '网络设备报告',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'traffic',
|
||||
name: 'TrafficReport',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '流量统计报告',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'history',
|
||||
name: 'HistoryReport',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '历史报告',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'statistics',
|
||||
name: 'StatisticsReport',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '统计报告',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/system-settings',
|
||||
name: 'SystemSettings',
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: '系统设置',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-settings',
|
||||
order: 13,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'system-monitoring',
|
||||
name: 'SystemMonitoring',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '系统监控',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'system-logs',
|
||||
name: 'SystemLogs',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '系统日志',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'account-management',
|
||||
name: 'AccountManagement',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '用户管理',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'menu-management',
|
||||
name: 'MenuManagement',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '菜单设置',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'license-center',
|
||||
name: 'LicenseCenter',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '许可授权中心',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/help',
|
||||
name: 'HelpCenter',
|
||||
component: DEFAULT_LAYOUT,
|
||||
meta: {
|
||||
locale: '帮助中心',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-bulb',
|
||||
order: 14,
|
||||
hideChildrenInMenu: true,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'HelpCenterIndex',
|
||||
component: () => import('@/views/redirect/index.vue'),
|
||||
meta: {
|
||||
locale: '帮助中心',
|
||||
requiresAuth: true,
|
||||
roles: ['*'],
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user