# 路由生成逻辑重构说明 ## 重构目标 将 Platform 中的通用路由生成逻辑提取到 shared 包中,使其他 web 服务也可以复用。 ## 架构设计 ### 职责划分 **Shared 包(shared/utils/route)** - ✅ 提供通用的路由生成方法 - ✅ 提供视图树构建方法 - ✅ 提供 localStorage 数据加载方法 - ✅ 不依赖特定的 router 实例 - ✅ 不依赖特定的组件加载方式 **Platform 包(platform/src/router/dynamicRoute.ts)** - ✅ 提供 Platform 特定的布局组件映射 - ✅ 提供 Platform 特定的组件加载器 - ✅ 调用 shared 中的通用方法 - ✅ 将生成的路由添加到 Platform 的 router 实例 ## 核心方法 ### Shared 包新增方法 #### 1. `generateSimpleRoutes()` ```typescript export function generateSimpleRoutes( views: TbSysViewDTO[], config: RouteGeneratorConfig, options?: GenerateSimpleRoutesOptions ): RouteRecordRaw[] ``` **功能**:生成简化的路由配置,适合直接添加到 router **参数**: - `views` - 视图列表 - `config` - 路由生成器配置(布局映射、组件加载器等) - `options` - 可选配置 - `asRootChildren` - 是否作为根路由的子路由 - `iframePlaceholder` - iframe 类型视图的占位组件 - `verbose` - 是否启用详细日志 **返回**:路由配置数组 #### 2. `loadViewsFromStorage()` ```typescript export function loadViewsFromStorage( storageKey?: string, viewsPath?: string ): TbSysViewDTO[] | null ``` **功能**:从 localStorage 加载视图数据 **参数**: - `storageKey` - localStorage 的 key(默认:'loginDomain') - `viewsPath` - 视图数据在对象中的路径(默认:'userViews',支持嵌套如 'user.views') **返回**:视图列表,如果不存在返回 null ### Platform 包简化后的方法 #### 1. `addDynamicRoutes()` ```typescript export function addDynamicRoutes(views: TbSysViewDTO[]) { // 使用 shared 中的通用方法生成路由 const routes = generateSimpleRoutes(views, routeConfig, routeOptions) // 将生成的路由添加到 Platform 的 router routes.forEach(route => { router.addRoute('Root', route) }) } ``` #### 2. `loadRoutesFromStorage()` ```typescript export function loadRoutesFromStorage(): boolean { // 使用 shared 中的通用方法加载视图数据 const views = loadViewsFromStorage('loginDomain', 'userViews') if (views) { addDynamicRoutes(views) return true } return false } ``` ## 使用示例 ### 在 Platform 中使用 ```typescript import { loadRoutesFromStorage, addDynamicRoutes } from '@/router/dynamicRoute' // 从 localStorage 加载并添加路由 loadRoutesFromStorage() // 或者手动传入视图数据 const views = [...] // 从 API 获取 addDynamicRoutes(views) ``` ### 在其他 Web 服务中使用 ```typescript import { generateSimpleRoutes, loadViewsFromStorage, type RouteGeneratorConfig } from 'shared/utils/route' import router from './router' // 1. 配置路由生成器 const config: RouteGeneratorConfig = { layoutMap: { 'MyLayout': () => import('./layouts/MyLayout.vue') }, viewLoader: (path) => { // 自定义组件加载逻辑 return () => import(`./views/${path}.vue`) } } // 2. 加载视图数据 const views = loadViewsFromStorage() // 3. 生成路由 if (views) { const routes = generateSimpleRoutes(views, config, { asRootChildren: true, verbose: true }) // 4. 添加到 router routes.forEach(route => { router.addRoute('Root', route) }) } ``` ## 配置说明 ### RouteGeneratorConfig ```typescript interface RouteGeneratorConfig { /** 布局组件映射表 */ layoutMap: Record Promise> /** 视图组件加载器 */ viewLoader: (componentPath: string) => (() => Promise) | null /** 静态路由列表(可选) */ staticRoutes?: RouteRecordRaw[] /** 404 组件(可选) */ notFoundComponent?: () => Promise } ``` ### GenerateSimpleRoutesOptions ```typescript interface GenerateSimpleRoutesOptions { /** 是否作为根路由的子路由(路径去掉前导 /) */ asRootChildren?: boolean /** iframe 类型视图的占位组件 */ iframePlaceholder?: () => Promise /** 是否启用详细日志 */ verbose?: boolean } ``` ## 优势 ### 1. 代码复用 - ✅ 通用逻辑只需维护一份 - ✅ 其他 web 服务可以直接使用 - ✅ 减少重复代码 ### 2. 职责清晰 - ✅ Shared 负责通用逻辑 - ✅ 各个服务负责特定配置 - ✅ 易于理解和维护 ### 3. 灵活性 - ✅ 通过配置注入实现定制化 - ✅ 支持多种使用方式 - ✅ 易于扩展 ### 4. 可测试性 - ✅ 通用方法独立测试 - ✅ 配置化便于 mock - ✅ 减少耦合 ## 迁移指南 如果其他服务想要使用 shared 中的路由生成逻辑: ### 步骤 1:准备配置 ```typescript // 1. 准备布局组件映射 const layoutMap = { 'MainLayout': () => import('./layouts/MainLayout.vue'), 'BlankLayout': () => import('./layouts/BlankLayout.vue') } // 2. 准备组件加载器 const VIEW_MODULES = import.meta.glob('./views/**/*.vue') const viewLoader = (path: string) => { const fullPath = `./views/${path}.vue` return VIEW_MODULES[fullPath] || null } // 3. 组装配置 const config: RouteGeneratorConfig = { layoutMap, viewLoader } ``` ### 步骤 2:加载视图数据 ```typescript import { loadViewsFromStorage } from 'shared/utils/route' // 从 localStorage 加载 const views = loadViewsFromStorage('loginDomain', 'userViews') // 或从 API 加载 // const views = await api.getUserViews() ``` ### 步骤 3:生成并添加路由 ```typescript import { generateSimpleRoutes } from 'shared/utils/route' if (views) { const routes = generateSimpleRoutes(views, config, { asRootChildren: true, verbose: process.env.NODE_ENV === 'development' }) routes.forEach(route => { router.addRoute('YourRootRouteName', route) }) } ``` ## 注意事项 1. **组件加载器**:每个服务的组件路径可能不同,需要自行实现 `viewLoader` 2. **布局组件**:需要提供服务特定的布局组件映射 3. **路由实例**:需要自行将生成的路由添加到服务的 router 实例 4. **iframe 支持**:如果需要支持 iframe 视图,需要提供占位组件 ## 文件变更 ### 新增文件 - `shared/src/utils/route/route-generator.ts` - 新增通用方法 ### 修改文件 - `shared/src/utils/route/index.ts` - 新增导出 - `shared/vite.config.ts` - 新增导出配置 - `shared/EXPOSES.md` - 更新文档 - `platform/src/router/dynamicRoute.ts` - 简化代码 - `platform/src/types/shared.d.ts` - 新增类型声明 ## 更新日志 ### 2025-12-12 - ✅ 将路由生成通用逻辑提取到 shared - ✅ 新增 `generateSimpleRoutes` 方法 - ✅ 新增 `loadViewsFromStorage` 方法 - ✅ 简化 Platform 的 dynamicRoute.ts - ✅ 更新文档和类型声明