From 03167ec81343fb8bf8967da13768a1137c89b24d Mon Sep 17 00:00:00 2001
From: zhou zhou <3272660260@qq.com>
Date: 星期三, 01 四月 2026 08:48:46 +0800
Subject: [PATCH] #前端
---
rsf-design/src/components/core/layouts/art-menus/art-sidebar-menu/style.scss | 10 ++
rsf-design/src/router/core/ComponentLoader.js | 39 +++++++++
rsf-design/src/router/core/MenuProcessor.js | 80 ++++++++++++++++++++
rsf-design/src/router/guards/beforeEach.js | 1
rsf-design/src/router/core/RouteRegistry.js | 53 +++++++++++++
5 files changed, 179 insertions(+), 4 deletions(-)
diff --git a/rsf-design/src/components/core/layouts/art-menus/art-sidebar-menu/style.scss b/rsf-design/src/components/core/layouts/art-menus/art-sidebar-menu/style.scss
index 1641584..2385966 100644
--- a/rsf-design/src/components/core/layouts/art-menus/art-sidebar-menu/style.scss
+++ b/rsf-design/src/components/core/layouts/art-menus/art-sidebar-menu/style.scss
@@ -42,6 +42,8 @@
flex-direction: column;
align-items: center;
justify-content: center;
+ box-sizing: border-box;
+ width: calc(100% - 16px);
margin: 8px;
overflow: hidden;
text-align: center;
@@ -52,11 +54,17 @@
display: flex !important;
align-items: center;
justify-content: center;
- width: 100%;
+ width: 24px;
+ height: 24px;
margin: 0 auto !important;
margin-right: auto !important;
margin-left: auto !important;
font-size: 20px;
+
+ :deep(svg) {
+ display: block;
+ margin: auto;
+ }
}
span {
diff --git a/rsf-design/src/router/core/ComponentLoader.js b/rsf-design/src/router/core/ComponentLoader.js
index eaf91b0..55f1490 100644
--- a/rsf-design/src/router/core/ComponentLoader.js
+++ b/rsf-design/src/router/core/ComponentLoader.js
@@ -2,6 +2,15 @@
class ComponentLoader {
constructor() {
this.modules = import.meta.glob('../../views/**/*.vue')
+ this.warmPromises = new Map()
+ }
+ resolveModule(componentPath) {
+ if (!componentPath) {
+ return null
+ }
+ const fullPath = `../../views${componentPath}.vue`
+ const fullPathWithIndex = `../../views${componentPath}/index.vue`
+ return this.modules[fullPath] || this.modules[fullPathWithIndex] || null
}
/**
* 鍔犺浇缁勪欢
@@ -10,10 +19,10 @@
if (!componentPath) {
return this.createEmptyComponent()
}
- const fullPath = `../../views${componentPath}.vue`
- const fullPathWithIndex = `../../views${componentPath}/index.vue`
- const module = this.modules[fullPath] || this.modules[fullPathWithIndex]
+ const module = this.resolveModule(componentPath)
if (!module) {
+ const fullPath = `../../views${componentPath}.vue`
+ const fullPathWithIndex = `../../views${componentPath}/index.vue`
console.error(
`[ComponentLoader] 鏈壘鍒扮粍浠�: ${componentPath}锛屽皾璇曡繃鐨勮矾寰�: ${fullPath} 鍜� ${fullPathWithIndex}`
)
@@ -22,6 +31,30 @@
return module
}
/**
+ * 棰勭儹缁勪欢妯″潡锛岄伩鍏嶉娆$偣鍑婚〉闈㈡椂鍐嶈Е鍙戝喎鍔犺浇銆�
+ */
+ warm(componentPath) {
+ const normalizedPath = typeof componentPath === 'string' ? componentPath.trim() : ''
+ if (!normalizedPath) {
+ return Promise.resolve(false)
+ }
+ if (this.warmPromises.has(normalizedPath)) {
+ return this.warmPromises.get(normalizedPath)
+ }
+ const module = this.resolveModule(normalizedPath)
+ if (!module) {
+ return Promise.resolve(false)
+ }
+ const warmTask = module()
+ .then(() => true)
+ .catch((error) => {
+ console.warn(`[ComponentLoader] 缁勪欢棰勭儹澶辫触: ${normalizedPath}`, error)
+ return false
+ })
+ this.warmPromises.set(normalizedPath, warmTask)
+ return warmTask
+ }
+ /**
* 鍔犺浇甯冨眬缁勪欢
*/
loadLayout() {
diff --git a/rsf-design/src/router/core/MenuProcessor.js b/rsf-design/src/router/core/MenuProcessor.js
index f031609..c750811 100644
--- a/rsf-design/src/router/core/MenuProcessor.js
+++ b/rsf-design/src/router/core/MenuProcessor.js
@@ -5,6 +5,34 @@
import { RoutesAlias } from '../routesAlias'
import { adaptBackendMenuTree } from '../adapters/backendMenuAdapter'
import { formatMenuTitle } from '@/utils'
+
+const WORKBENCH_PATH = '/dashboard/console'
+const WORKBENCH_ROOT_PATH = '/dashboard'
+
+const WORKBENCH_MENU = Object.freeze({
+ name: 'Dashboard',
+ path: WORKBENCH_ROOT_PATH,
+ component: RoutesAlias.Layout,
+ redirect: WORKBENCH_PATH,
+ meta: {
+ title: 'menus.dashboard.title',
+ icon: 'ri:home-smile-2-line'
+ },
+ children: [
+ {
+ name: 'Console',
+ path: 'console',
+ component: WORKBENCH_PATH,
+ meta: {
+ title: 'menus.dashboard.console',
+ icon: 'ri:home-smile-2-line',
+ keepAlive: false,
+ fixedTab: true
+ }
+ }
+ ]
+})
+
class MenuProcessor {
/**
* 鑾峰彇鑿滃崟鏁版嵁
@@ -17,6 +45,7 @@
} else {
menuList = await this.processBackendMenu()
}
+ menuList = this.prependWorkbenchMenu(menuList)
this.validateMenuPaths(menuList)
return this.normalizeMenuPaths(menuList)
}
@@ -206,5 +235,56 @@
}
return `/${path}`
}
+
+ prependWorkbenchMenu(menuList) {
+ if (!Array.isArray(menuList)) {
+ return [this.createWorkbenchMenu()]
+ }
+
+ const hasWorkbench = menuList.some((item) => this.containsWorkbenchMenu(item))
+ if (hasWorkbench) {
+ return menuList
+ }
+
+ return [this.createWorkbenchMenu(), ...menuList]
+ }
+
+ createWorkbenchMenu() {
+ return {
+ ...WORKBENCH_MENU,
+ meta: {
+ ...WORKBENCH_MENU.meta
+ },
+ children: WORKBENCH_MENU.children.map((child) => ({
+ ...child,
+ meta: {
+ ...child.meta
+ }
+ }))
+ }
+ }
+
+ isWorkbenchMenu(item) {
+ if (!item || typeof item !== 'object') {
+ return false
+ }
+ const path = String(item.path || '')
+ const component = String(item.component || '')
+ return (
+ path === WORKBENCH_ROOT_PATH ||
+ path === WORKBENCH_PATH ||
+ component === WORKBENCH_PATH
+ )
+ }
+
+ containsWorkbenchMenu(item) {
+ if (this.isWorkbenchMenu(item)) {
+ return true
+ }
+ if (!Array.isArray(item?.children) || item.children.length === 0) {
+ return false
+ }
+ return item.children.some((child) => this.containsWorkbenchMenu(child))
+ }
}
export { MenuProcessor }
diff --git a/rsf-design/src/router/core/RouteRegistry.js b/rsf-design/src/router/core/RouteRegistry.js
index 3132e78..cd59c62 100644
--- a/rsf-design/src/router/core/RouteRegistry.js
+++ b/rsf-design/src/router/core/RouteRegistry.js
@@ -1,6 +1,8 @@
import { ComponentLoader } from './ComponentLoader.js'
import { RouteValidator } from './RouteValidator.js'
import { RouteTransformer } from './RouteTransformer.js'
+const DEFAULT_WARMUP_LIMIT = 12
+const HOME_COMPONENT_PATH = '/dashboard/console'
class RouteRegistry {
constructor(router, options = {}) {
this.router = router
@@ -75,5 +77,56 @@
markAsRegistered() {
this.registered = true
}
+ /**
+ * 绌洪棽鏃堕鐑珮棰戦〉闈紝闄嶄綆鐧诲綍鍚庨娆″垏椤电殑鍐峰姞杞芥垚鏈��
+ */
+ warm(menuList, options = {}) {
+ const limit = Number.isFinite(options.limit) ? options.limit : DEFAULT_WARMUP_LIMIT
+ const paths = collectWarmupPaths(menuList, limit)
+ if (paths.length === 0) {
+ return
+ }
+ const schedule = globalThis.requestIdleCallback
+ ? (task) => globalThis.requestIdleCallback(task, { timeout: 1200 })
+ : (task) => setTimeout(task, 80)
+ schedule(() => {
+ void warmSequentially(paths, this.componentLoader)
+ })
+ }
+}
+function collectWarmupPaths(menuList, limit) {
+ const paths = []
+ const visited = new Set()
+ const walk = (items) => {
+ if (!Array.isArray(items)) {
+ return
+ }
+ for (const item of items) {
+ if (paths.length >= limit) {
+ return
+ }
+ const componentPath = typeof item?.component === 'string' ? item.component.trim() : ''
+ if (
+ componentPath &&
+ componentPath !== '/' &&
+ componentPath !== HOME_COMPONENT_PATH &&
+ !visited.has(componentPath) &&
+ !item?.meta?.isFirstLevel
+ ) {
+ visited.add(componentPath)
+ paths.push(componentPath)
+ }
+ if (Array.isArray(item?.children) && item.children.length > 0) {
+ walk(item.children)
+ }
+ }
+ }
+ walk(menuList)
+ return paths
+}
+async function warmSequentially(paths, componentLoader) {
+ for (const componentPath of paths) {
+ await componentLoader.warm(componentPath)
+ }
}
export { RouteRegistry }
diff --git a/rsf-design/src/router/guards/beforeEach.js b/rsf-design/src/router/guards/beforeEach.js
index 8a71148..ff63662 100644
--- a/rsf-design/src/router/guards/beforeEach.js
+++ b/rsf-design/src/router/guards/beforeEach.js
@@ -151,6 +151,7 @@
throw new Error('鑾峰彇鑿滃崟鍒楄〃澶辫触锛岃閲嶆柊鐧诲綍')
}
routeRegistry?.register(menuList)
+ routeRegistry?.warm(menuList)
const menuStore = useMenuStore()
menuStore.setMenuList(menuList)
menuStore.addRemoveRouteFns(routeRegistry?.getRemoveRouteFns() || [])
--
Gitblit v1.9.1