Files

288 lines
7.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 路由生成逻辑重构说明
## 重构目标
将 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<string, () => Promise<any>>
/** 视图组件加载器 */
viewLoader: (componentPath: string) => (() => Promise<any>) | null
/** 静态路由列表(可选) */
staticRoutes?: RouteRecordRaw[]
/** 404 组件(可选) */
notFoundComponent?: () => Promise<any>
}
```
### GenerateSimpleRoutesOptions
```typescript
interface GenerateSimpleRoutesOptions {
/** 是否作为根路由的子路由(路径去掉前导 / */
asRootChildren?: boolean
/** iframe 类型视图的占位组件 */
iframePlaceholder?: () => Promise<any>
/** 是否启用详细日志 */
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
- ✅ 更新文档和类型声明