Prechádzať zdrojové kódy

fix(story-13.13): 修复订单统计API路由结构以兼容Hono RPC客户端

问题:
- 原路由路径 /company-orders-stats/:id 无法生成正确的RPC类型结构
- 前端期望使用 enterpriseOrderClient['company-orders'][':id']['stats']
- 但后端实际路径为扁平的 /company-orders-stats/:id

修改内容:
- 后端: 使用嵌套路由结构 /company-orders -> :id/stats
  - 创建嵌套的 OpenAPIHono 实例
  - 订单列表路由: GET /company-orders (path: '')
  - 订单统计路由: GET /company-orders/:id/stats (path: '/:id/stats')
- 前端: 更新API调用使用 enterpriseOrderClient['company-orders'][':id']['stats']
  - types.ts: 更新 OrderStatsResponse 类型定义
  - OrderList.tsx: 更新 useOrderStats hook 中的API调用路径

修复的文件:
- allin-packages/order-module/src/routes/order-custom.routes.ts
- mini-ui-packages/yongren-order-management-ui/src/api/types.ts
- mini-ui-packages/yongren-order-management-ui/src/pages/OrderList/OrderList.tsx

Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
yourname 2 dní pred
rodič
commit
ce4b68003c

+ 55 - 48
allin-packages/order-module/src/routes/order-custom.routes.ts

@@ -26,7 +26,6 @@ import {
   OrderStatsResponseSchema,
   AssetType
 } from '../schemas/order.schema';
-import { OrderStatus, WorkStatus } from '@d8d/allin-enums';
 // FileSchema导入已不再需要,使用简化的SimpleFileSchema
 
 // 简化的文件schema,用于订单资产查询
@@ -853,10 +852,11 @@ const getOrderByIdForEnterpriseRoute = createRoute({
 });
 
 // 企业订单统计路由(用于企业小程序订单卡片)
-// 路径格式: /company-orders-stats/:id
+// 路径格式: /:id/stats (在 /company-orders 嵌套路由下)
+// 完整路径: /company-orders/:id/stats
 const orderStatsRoute = createRoute({
   method: 'get',
-  path: '/company-orders-stats/:id',
+  path: '/:id/stats',
   middleware: [enterpriseAuthMiddleware],
   request: {
     params: z.object({
@@ -1396,8 +1396,14 @@ const enterpriseOrderCustomRoutes = new OpenAPIHono<AuthContext>()
       }, 500);
     }
   })
-  // 企业订单列表路由(独立路由)
-  .openapi(companyOrdersRoute, async (c) => {
+  // 企业订单路由(嵌套结构:/company-orders 和 /company-orders/:id/stats)
+  .route('/company-orders',
+    new OpenAPIHono<AuthContext>()
+      // GET /company-orders - 企业订单列表
+      .openapi(createRoute({
+        ...companyOrdersRoute,
+        path: ''
+      }), async (c) => {
     try {
       const query = c.req.valid('query');
       const user = c.get('user');
@@ -1435,49 +1441,50 @@ const enterpriseOrderCustomRoutes = new OpenAPIHono<AuthContext>()
       }, 500);
     }
   })
-  // 企业订单统计路由(独立路由,路径为 /company-orders-stats/:id)
-  .openapi(orderStatsRoute, async (c) => {
-    try {
-      const { id: orderId } = c.req.valid('param');
-      const query = c.req.valid('query');
-      const user = c.get('user');
-      const orderService = new OrderService(AppDataSource);
-
-      // 企业ID强制从认证token获取
-      const companyId = user?.companyId;
-      if (!companyId) {
-        return c.json({ code: 403, message: '无企业权限' }, 403);
-      }
-
-      // 获取当前年月(如果未提供)
-      const now = new Date();
-      const year = query.year ?? now.getFullYear();
-      const month = query.month ?? now.getMonth() + 1;
-
-      const result = await orderService.getOrderStats(orderId, companyId, year, month);
-
-      // 使用 parseWithAwait 验证和转换数据
-      const validatedResult = await parseWithAwait(OrderStatsResponseSchema, result);
-      return c.json(validatedResult, 200);
-    } catch (error) {
-      if (error instanceof z.ZodError) {
-        return c.json({
-          code: 400,
-          message: '参数错误',
-          errors: error.issues
-        }, 400);
-      }
-
-      if (error instanceof Error && error.message.includes('订单不存在')) {
-        return c.json({ code: 404, message: error.message }, 404);
-      }
-
-      return c.json({
-        code: 500,
-        message: error instanceof Error ? error.message : '获取订单统计失败'
-      }, 500);
-    }
-  })
+      // GET /company-orders/:id/stats - 企业订单统计
+      .openapi(orderStatsRoute, async (c) => {
+        try {
+          const { id: orderId } = c.req.valid('param');
+          const query = c.req.valid('query');
+          const user = c.get('user');
+          const orderService = new OrderService(AppDataSource);
+
+          // 企业ID强制从认证token获取
+          const companyId = user?.companyId;
+          if (!companyId) {
+            return c.json({ code: 403, message: '无企业权限' }, 403);
+          }
+
+          // 获取当前年月(如果未提供)
+          const now = new Date();
+          const year = query.year ?? now.getFullYear();
+          const month = query.month ?? now.getMonth() + 1;
+
+          const result = await orderService.getOrderStats(orderId, companyId, year, month);
+
+          // 使用 parseWithAwait 验证和转换数据
+          const validatedResult = await parseWithAwait(OrderStatsResponseSchema, result);
+          return c.json(validatedResult, 200);
+        } catch (error) {
+          if (error instanceof z.ZodError) {
+            return c.json({
+              code: 400,
+              message: '参数错误',
+              errors: error.issues
+            }, 400);
+          }
+
+          if (error instanceof Error && error.message.includes('订单不存在')) {
+            return c.json({ code: 404, message: error.message }, 404);
+          }
+
+          return c.json({
+            code: 500,
+            message: error instanceof Error ? error.message : '获取订单统计失败'
+          }, 500);
+        }
+      })
+    )
   // 企业专用订单详情查询
   .openapi(getOrderByIdForEnterpriseRoute, async (c) => {
     try {

+ 2 - 1
mini-ui-packages/yongren-order-management-ui/src/api/types.ts

@@ -19,7 +19,8 @@ export type OrderData = InferResponseType<typeof enterpriseOrderClient['company-
 // 企业专用扩展API
 export type CheckinStatisticsResponse = InferResponseType<typeof enterpriseOrderClient['checkin-statistics']['$get'], 200>;
 export type VideoStatisticsResponse = InferResponseType<typeof enterpriseOrderClient['video-statistics']['$get'], 200>;
-export type OrderStatsResponse = InferResponseType<typeof enterpriseOrderClient['company-orders-stats'][':id']['$get'], 200>;
+// 订单统计API路径: /company-orders/:id/stats -> client key: 'company-orders' -> ':id' -> 'stats'
+export type OrderStatsResponse = InferResponseType<typeof enterpriseOrderClient['company-orders'][':id']['stats']['$get'], 200>;
 export type CompanyVideosResponse = InferResponseType<typeof enterpriseOrderClient['company-videos']['$get'], 200>;
 export type BatchDownloadRequest = InferRequestType<typeof enterpriseOrderClient['batch-download']['$post']>['json'];
 export type UpdateVideoStatusRequest = InferRequestType<typeof enterpriseOrderClient.videos[':id']['status']['$put']>['json'];

+ 2 - 2
mini-ui-packages/yongren-order-management-ui/src/pages/OrderList/OrderList.tsx

@@ -23,8 +23,8 @@ const useOrderStats = (orderId: number | undefined) => {
         return null
       }
       console.debug('[useOrderStats] 正在调用统计 API,orderId:', orderId)
-      // 路径: /company-orders/{id}/stats -> client key: 'company-orders-stats' with param ':id'
-      const response = await enterpriseOrderClient['company-orders-stats'][':id'].$get({
+      // 路径: /company-orders/:id/stats -> client key: 'company-orders' -> ':id' -> 'stats'
+      const response = await enterpriseOrderClient['company-orders'][':id']['stats'].$get({
         param: { id: orderId },
         query: {}
       })