Files

7.0 KiB
Raw Permalink Blame History

路由生成逻辑重构说明

重构目标

将 Platform 中的通用路由生成逻辑提取到 shared 包中,使其他 web 服务也可以复用。

架构设计

职责划分

Shared 包shared/utils/route

  • 提供通用的路由生成方法
  • 提供视图树构建方法
  • 提供 localStorage 数据加载方法
  • 不依赖特定的 router 实例
  • 不依赖特定的组件加载方式

Platform 包platform/src/router/dynamicRoute.ts

  • 提供 Platform 特定的布局组件映射
  • 提供 Platform 特定的组件加载器
  • 调用 shared 中的通用方法
  • 将生成的路由添加到 Platform 的 router 实例

核心方法

Shared 包新增方法

1. generateSimpleRoutes()

export function generateSimpleRoutes(
    views: TbSysViewDTO[],
    config: RouteGeneratorConfig,
    options?: GenerateSimpleRoutesOptions
): RouteRecordRaw[]

功能:生成简化的路由配置,适合直接添加到 router

参数

  • views - 视图列表
  • config - 路由生成器配置(布局映射、组件加载器等)
  • options - 可选配置
    • asRootChildren - 是否作为根路由的子路由
    • iframePlaceholder - iframe 类型视图的占位组件
    • verbose - 是否启用详细日志

返回:路由配置数组

2. loadViewsFromStorage()

export function loadViewsFromStorage(
    storageKey?: string,
    viewsPath?: string
): TbSysViewDTO[] | null

功能:从 localStorage 加载视图数据

参数

  • storageKey - localStorage 的 key默认'loginDomain'
  • viewsPath - 视图数据在对象中的路径(默认:'userViews',支持嵌套如 'user.views'

返回:视图列表,如果不存在返回 null

Platform 包简化后的方法

1. addDynamicRoutes()

export function addDynamicRoutes(views: TbSysViewDTO[]) {
    // 使用 shared 中的通用方法生成路由
    const routes = generateSimpleRoutes(views, routeConfig, routeOptions)
    
    // 将生成的路由添加到 Platform 的 router
    routes.forEach(route => {
        router.addRoute('Root', route)
    })
}

2. loadRoutesFromStorage()

export function loadRoutesFromStorage(): boolean {
    // 使用 shared 中的通用方法加载视图数据
    const views = loadViewsFromStorage('loginDomain', 'userViews')
    
    if (views) {
        addDynamicRoutes(views)
        return true
    }
    
    return false
}

使用示例

在 Platform 中使用

import { loadRoutesFromStorage, addDynamicRoutes } from '@/router/dynamicRoute'

// 从 localStorage 加载并添加路由
loadRoutesFromStorage()

// 或者手动传入视图数据
const views = [...] // 从 API 获取
addDynamicRoutes(views)

在其他 Web 服务中使用

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

interface RouteGeneratorConfig {
    /** 布局组件映射表 */
    layoutMap: Record<string, () => Promise<any>>
    
    /** 视图组件加载器 */
    viewLoader: (componentPath: string) => (() => Promise<any>) | null
    
    /** 静态路由列表(可选) */
    staticRoutes?: RouteRecordRaw[]
    
    /** 404 组件(可选) */
    notFoundComponent?: () => Promise<any>
}

GenerateSimpleRoutesOptions

interface GenerateSimpleRoutesOptions {
    /** 是否作为根路由的子路由(路径去掉前导 / */
    asRootChildren?: boolean
    
    /** iframe 类型视图的占位组件 */
    iframePlaceholder?: () => Promise<any>
    
    /** 是否启用详细日志 */
    verbose?: boolean
}

优势

1. 代码复用

  • 通用逻辑只需维护一份
  • 其他 web 服务可以直接使用
  • 减少重复代码

2. 职责清晰

  • Shared 负责通用逻辑
  • 各个服务负责特定配置
  • 易于理解和维护

3. 灵活性

  • 通过配置注入实现定制化
  • 支持多种使用方式
  • 易于扩展

4. 可测试性

  • 通用方法独立测试
  • 配置化便于 mock
  • 减少耦合

迁移指南

如果其他服务想要使用 shared 中的路由生成逻辑:

步骤 1准备配置

// 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加载视图数据

import { loadViewsFromStorage } from 'shared/utils/route'

// 从 localStorage 加载
const views = loadViewsFromStorage('loginDomain', 'userViews')

// 或从 API 加载
// const views = await api.getUserViews()

步骤 3生成并添加路由

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
  • 更新文档和类型声明