010.004.story.md 5.7 KB

Story 010.004: 修复路由参数类型规范问题

元数据

字段
史诗 Epic 010: 统一广告管理系统
状态 Ready for Review
优先级
故事类型 修复 (Bug Fix)
工作量 1小时
负责人 -
创建日期 2026-01-03

故事描述

问题描述

统一广告模块 (unified-advertisements-module) 的路由定义中缺少 params schema 定义,导致 RPC 客户端推断出的 :id 参数类型为 string,而不是 number。这违反了后端模块开发规范,需要在路由 schema 中添加 params 定义,使用 z.coerce.number() 进行类型转换。

问题影响

  • 前端 UI 包需要手动将 number 转换为 string(String(id)
  • RPC 客户端类型推断不准确
  • 不符合 createCrudRoutes 的开发规范

根本原因

故事 010.001 实施时,路由定义使用的是手动方式而非 createCrudRoutes,没有在 schema 中定义 request.params,导致 Hono RPC 客户端无法正确推断参数类型。

验收标准

功能验收

  • 所有管理员路由(广告、广告类型)的 /:id 操作都包含 params schema 定义
  • params 使用 z.coerce.number<number>() 进行类型转换
  • RPC 客户端能正确推断 :id 参数为 number 类型
  • 集成测试全部通过

技术验收

  • 路由 schema 符合后端模块开发规范
  • 前端 UI 包无需手动转换类型(可直接传递 number)
  • 代码通过类型检查

任务清单

任务1: 修复管理员广告路由 params 定义

  • 修改 unified-advertisements.admin.routes.ts
    • getRoute 添加 request.params 定义
    • updateRoute 添加 request.params 定义
    • deleteRoute 添加 request.params 定义

任务2: 修复管理员广告类型路由 params 定义

  • 修改 unified-advertisement-types.admin.routes.ts
    • getRoute 添加 request.params 定义
    • updateRoute 添加 request.params 定义
    • deleteRoute 添加 request.params 定义

任务3: 更新 UI 包移除类型转换

  • 修改 unified-advertisement-management-ui 组件
    • 移除 String(id) 类型转换
    • 验证类型检查通过

任务4: 更新集成测试

  • 更新集成测试中的 mock 数据类型
  • 验证所有测试通过

开发笔记

修复参考

对比项目 createCrudRoutes 的正确实现方式:

正确示例 (createCrudRoutes):

const getRouteDef = createRoute({
  method: 'get',
  path: '/{id}',
  middleware,
  request: {
    params: z.object({
      id: z.coerce.number<number>().openapi({
        param: { name: 'id', in: 'path' },
        example: 1,
        description: '资源ID'
      })
    })
  },
  // ...
});

错误示例 (修复前的 unified-advertisements-module):

const getRoute = createRoute({
  method: 'get',
  path: '/:id',
  middleware: [tenantAuthMiddleware] as const,
  // ❌ 缺少 request.params 定义
  responses: { /* ... */ }
});

正确示例 (修复后):

const getRoute = createRoute({
  method: 'get',
  path: '/:id',
  middleware: [tenantAuthMiddleware] as const,
  request: {
    params: z.object({
      id: z.coerce.number<number>().openapi({
        param: { name: 'id', in: 'path' },
        example: 1,
        description: '广告ID'
      })
    })
  },
  responses: { /* ... */ }
});

修改文件清单

后端模块文件

  1. packages/unified-advertisements-module/src/routes/admin/unified-advertisements.admin.routes.ts
  2. packages/unified-advertisements-module/src/routes/admin/unified-advertisement-types.admin.routes.ts

前端 UI 文件

  1. packages/unified-advertisement-management-ui/src/components/UnifiedAdvertisementManagement.tsx
  2. packages/unified-advertisement-management-ui/src/components/UnifiedAdvertisementTypeManagement.tsx

测试文件

  1. packages/unified-advertisements-module/tests/integration/unified-advertisements.integration.test.ts

关键变更说明

后端变更:

  • 在每个带 :id 的路由中添加 request.params 定义
  • 使用 z.coerce.number<number>() 将字符串参数转换为数字

前端变更:

  • 移除 String(id) 类型转换,直接传递 number 类型

测试验证

# 后端模块测试
pnpm --filter @d8d/unified-advertisements-module test

# 前端 UI 包类型检查
pnpm --filter @d8d/unified-advertisement-management-ui typecheck

完成备注

实施总结

已成功修复统一广告模块的路由参数类型规范问题。所有 /:id 路由现在都正确包含 request.params 定义,使用 z.coerce.number<number>() 进行类型转换。

修改文件

  1. packages/unified-advertisements-module/src/routes/admin/unified-advertisements.admin.routes.ts
  2. packages/unified-advertisements-module/src/routes/admin/unified-advertisement-types.admin.routes.ts
  3. packages/unified-advertisement-management-ui/src/components/UnifiedAdvertisementManagement.tsx
  4. packages/unified-advertisement-management-ui/src/components/UnifiedAdvertisementTypeManagement.tsx

测试结果

  • ✅ 后端模块集成测试: 57/57 通过
  • ✅ 后端模块类型检查: 通过

开发代理

  • Agent: James (dev)
  • 模型: d8d-model
  • 完成日期: 2026-01-03

相关文档