style(diskMonitor): 统一磁盘监控页面样式规范
- 添加页面边距、表格样式和按钮样式约定到 AGENTS.md 文档 - 为任务详情抽屉组件添加卡片样式和表格结构优化 - 重构任务表格组件,增加搜索功能和列设置选项 - 移除独立的策略表单组件,整合到汇总页面 - 优化监控摘要组件的网格布局和样式 - 重新设计目标对话框的表单分组和禁用状态处理 - 统一所有组件使用 card、table-main 等标准类名 - 添加文件编码规范要求确保 UTF-8 编码一致性
This commit is contained in:
@@ -5,8 +5,9 @@ import { ElNotification } from 'element-plus'
|
||||
import { useUserStore } from '@/stores/modules/user'
|
||||
import { useAuthStore } from '@/stores/modules/auth'
|
||||
|
||||
// 引入 views 文件夹下所有 vue 文件
|
||||
const modules = import.meta.glob('@/views/**/*.vue')
|
||||
const VIEWS_ALIAS_PREFIX = '@/views'
|
||||
const VIEWS_SRC_PREFIX = '/src/views'
|
||||
const STATIC_ROUTE_NAMES = new Set([
|
||||
'layout',
|
||||
'login',
|
||||
@@ -14,6 +15,7 @@ const STATIC_ROUTE_NAMES = new Set([
|
||||
'tools',
|
||||
'toolWaveform',
|
||||
'toolMmsMapping',
|
||||
'toolAddData',
|
||||
'systemMonitor',
|
||||
'diskMonitor',
|
||||
'403',
|
||||
@@ -24,7 +26,7 @@ const STATIC_ROUTE_NAMES = new Set([
|
||||
let isInitializing = false
|
||||
|
||||
/**
|
||||
* 清除已有的动态路由
|
||||
* 清除已有的动态路由,避免重复注入。
|
||||
*/
|
||||
const clearDynamicRoutes = () => {
|
||||
const routes = router.getRoutes()
|
||||
@@ -36,13 +38,19 @@ const clearDynamicRoutes = () => {
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据菜单 component 路径查找对应的页面模块。
|
||||
* 兼容两种仓库写法:
|
||||
* 1. /foo/bar.vue
|
||||
* 2. /foo/bar/index.vue
|
||||
* 统一菜单 component 配置格式,只允许映射到 views 目录。
|
||||
*/
|
||||
const resolveComponentModule = (path: string) => {
|
||||
let normalizedPath = path.trim()
|
||||
const normalizeComponentPath = (path: string) => {
|
||||
let normalizedPath = path.trim().replace(/\\/g, '/')
|
||||
|
||||
if (normalizedPath.startsWith(VIEWS_ALIAS_PREFIX)) {
|
||||
normalizedPath = normalizedPath.slice(VIEWS_ALIAS_PREFIX.length)
|
||||
} else if (normalizedPath.startsWith(VIEWS_SRC_PREFIX)) {
|
||||
normalizedPath = normalizedPath.slice(VIEWS_SRC_PREFIX.length)
|
||||
} else if (normalizedPath.startsWith('src/views')) {
|
||||
normalizedPath = normalizedPath.slice('src/views'.length)
|
||||
}
|
||||
|
||||
if (!normalizedPath.startsWith('/')) {
|
||||
normalizedPath = '/' + normalizedPath
|
||||
}
|
||||
@@ -53,13 +61,31 @@ const resolveComponentModule = (path: string) => {
|
||||
normalizedPath = normalizedPath.slice(0, -1)
|
||||
}
|
||||
|
||||
const candidatePaths = [`/src/views${normalizedPath}.vue`, `/src/views${normalizedPath}/index.vue`]
|
||||
return normalizedPath
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据菜单 component 路径查找对应页面模块。
|
||||
* 兼容菜单资源里常见的多种写法,避免因为前缀或 index 差异导致误判。
|
||||
*/
|
||||
const resolveComponentModule = (path: string) => {
|
||||
const normalizedPath = normalizeComponentPath(path)
|
||||
const viewPath = normalizedPath.endsWith('/index') ? normalizedPath.slice(0, -'/index'.length) : normalizedPath
|
||||
const candidatePaths = Array.from(
|
||||
new Set([
|
||||
`${VIEWS_ALIAS_PREFIX}${normalizedPath}.vue`,
|
||||
`${VIEWS_ALIAS_PREFIX}${normalizedPath}/index.vue`,
|
||||
`${VIEWS_ALIAS_PREFIX}${viewPath}/index.vue`,
|
||||
`${VIEWS_SRC_PREFIX}${normalizedPath}.vue`,
|
||||
`${VIEWS_SRC_PREFIX}${normalizedPath}/index.vue`,
|
||||
`${VIEWS_SRC_PREFIX}${viewPath}/index.vue`
|
||||
])
|
||||
)
|
||||
|
||||
for (const candidatePath of candidatePaths) {
|
||||
const moduleLoader = modules[candidatePath]
|
||||
if (moduleLoader) {
|
||||
if (candidatePath in modules) {
|
||||
return {
|
||||
moduleLoader,
|
||||
moduleLoader: modules[candidatePath],
|
||||
resolvedPath: candidatePath
|
||||
}
|
||||
}
|
||||
@@ -72,7 +98,7 @@ const resolveComponentModule = (path: string) => {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 初始化动态路由
|
||||
* 初始化动态路由。
|
||||
*/
|
||||
export const initDynamicRouter = async () => {
|
||||
if (isInitializing) return Promise.reject(new Error('Dynamic router initialization in progress'))
|
||||
@@ -83,15 +109,13 @@ export const initDynamicRouter = async () => {
|
||||
const unresolvedRoutes: Array<{ name?: string; path?: string; component?: string; candidates: string[] }> = []
|
||||
|
||||
try {
|
||||
// 1. 获取菜单列表 && 按钮权限列表
|
||||
await authStore.getAuthMenuList()
|
||||
await authStore.getAuthButtonList()
|
||||
|
||||
// 2. 判断当前用户有没有菜单权限
|
||||
if (!authStore.authMenuListGet.length) {
|
||||
ElNotification({
|
||||
title: '无权限访问',
|
||||
message: '当前账号无任何菜单权限,请联系系统管理员!',
|
||||
message: '当前账号无任何菜单权限,请联系系统管理员',
|
||||
type: 'warning',
|
||||
duration: 3000
|
||||
})
|
||||
@@ -102,21 +126,17 @@ export const initDynamicRouter = async () => {
|
||||
return Promise.reject('No permission')
|
||||
}
|
||||
|
||||
// 3. 清理之前的动态路由
|
||||
clearDynamicRoutes()
|
||||
|
||||
// 4. 添加动态路由
|
||||
for (const item of authStore.flatMenuListGet) {
|
||||
// 删除 children 避免冗余嵌套
|
||||
if (item.children) delete item.children
|
||||
|
||||
// 处理组件映射
|
||||
// 动态菜单组件必须先映射成真实页面模块,否则 addRoute 后会直接落到 404。
|
||||
if (item.component && typeof item.component === 'string') {
|
||||
const { moduleLoader, resolvedPath } = resolveComponentModule(item.component)
|
||||
if (moduleLoader) {
|
||||
item.component = moduleLoader
|
||||
} else {
|
||||
// 动态路由组件一旦解析失败,对应菜单会落入 404,这里必须打印清楚候选路径。
|
||||
unresolvedRoutes.push({
|
||||
name: item.name,
|
||||
path: item.path,
|
||||
@@ -127,7 +147,6 @@ export const initDynamicRouter = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 类型守卫:确保满足 RouteRecordRaw 接口要求
|
||||
if (
|
||||
typeof item.path === 'string' &&
|
||||
(typeof item.component === 'function' || typeof item.redirect === 'string')
|
||||
@@ -147,7 +166,6 @@ export const initDynamicRouter = async () => {
|
||||
console.error('[dynamic-router] unresolved route components', unresolvedRoutes)
|
||||
}
|
||||
} catch (error) {
|
||||
// 当按钮 || 菜单请求出错时,重定向到登陆页
|
||||
userStore.setAccessToken('')
|
||||
userStore.setRefreshToken('')
|
||||
userStore.setExp(0)
|
||||
|
||||
Reference in New Issue
Block a user