Forráskód Böngészése

✨ feat(solution-designs): 增强方案设计接口的数据验证

- 引入parseWithAwait工具处理异步字段验证
- 在get、post、put和列表接口中添加数据验证逻辑
- 确保返回数据符合SolutionDesignSchema规范

♻️ refactor(users): 优化用户类型定义

- 将userType字段从string类型改为'basic' | 'premium'联合类型
- 增强类型安全性和代码提示

♻️ refactor(error-handling): 优化错误响应类型定义

- 为错误响应状态码添加明确的类型约束
- 提高代码类型安全性和可维护性
yourname 2 hónapja
szülő
commit
b8d818d400

+ 6 - 2
src/server/api/solution-designs/[id]/get.ts

@@ -6,6 +6,7 @@ import { AppDataSource } from '@/server/data-source';
 import { SolutionDesignService } from '@/server/modules/solution-designs/solution-design.service';
 import { AuthContext } from '@/server/types/context';
 import { authMiddleware } from '@/server/middleware/auth.middleware';
+import { parseWithAwait } from '@/server/utils/parseWithAwait';
 
 // 路径参数Schema
 const GetParams = z.object({
@@ -62,12 +63,15 @@ const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
       return c.json({ code: 403, message: '无权访问此方案设计' }, 403);
     }
 
-    return c.json(result, 200);
+    // 使用parseWithAwait处理Promise字段
+    const validatedResult = await parseWithAwait(SolutionDesignSchema, result);
+
+    return c.json(validatedResult, 200);
 
   } catch (error) {
     console.error('获取方案设计详情失败:', error);
     const { code = 500, message = '获取详情失败' } = error as Error & { code?: number };
-    return c.json({ code, message }, code);
+    return c.json({ code, message }, code as 400 | 500 | 200 | 404 | 403);
   }
 });
 

+ 6 - 2
src/server/api/solution-designs/[id]/put.ts

@@ -7,6 +7,7 @@ import { AppDataSource } from '@/server/data-source';
 import { SolutionDesignService } from '@/server/modules/solution-designs/solution-design.service';
 import { AuthContext } from '@/server/types/context';
 import { authMiddleware } from '@/server/middleware/auth.middleware';
+import { parseWithAwait } from '@/server/utils/parseWithAwait';
 
 // 路径参数Schema
 const UpdateParams = z.object({
@@ -71,12 +72,15 @@ const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
 
     const result = await service.update(Number(id), data);
 
-    return c.json(result, 200);
+    // 使用parseWithAwait处理Promise字段
+    const validatedResult = await parseWithAwait(SolutionDesignSchema, result);
+
+    return c.json(validatedResult, 200);
 
   } catch (error) {
     console.error('更新方案设计失败:', error);
     const { code = 500, message = '更新方案设计失败' } = error as Error & { code?: number };
-    return c.json({ code, message }, code);
+    return c.json({ code, message }, code as 400 | 500 | 200 | 404 | 403);
   }
 });
 

+ 8 - 2
src/server/api/solution-designs/get.ts

@@ -6,6 +6,7 @@ import { AppDataSource } from '@/server/data-source';
 import { SolutionDesignService } from '@/server/modules/solution-designs/solution-design.service';
 import { AuthContext } from '@/server/types/context';
 import { authMiddleware } from '@/server/middleware/auth.middleware';
+import { parseWithAwait } from '@/server/utils/parseWithAwait';
 
 // 查询参数Schema
 const ListQuery = z.object({
@@ -71,8 +72,13 @@ const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
       query.status
     );
 
+    // 使用parseWithAwait处理Promise字段
+    const validatedData = await Promise.all(
+      data.map(item => parseWithAwait(SolutionDesignSchema, item))
+    );
+
     return c.json({
-      data,
+      data: validatedData,
       pagination: {
         total,
         current: query.page,
@@ -83,7 +89,7 @@ const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
   } catch (error) {
     console.error('获取方案设计列表失败:', error);
     const { code = 500, message = '获取列表失败' } = error as Error & { code?: number };
-    return c.json({ code, message }, code);
+    return c.json({ code, message }, code as 400 | 500 | 200);
   }
 });
 

+ 6 - 2
src/server/api/solution-designs/post.ts

@@ -6,6 +6,7 @@ import { AppDataSource } from '@/server/data-source';
 import { SolutionDesignService } from '@/server/modules/solution-designs/solution-design.service';
 import { AuthContext } from '@/server/types/context';
 import { authMiddleware } from '@/server/middleware/auth.middleware';
+import { parseWithAwait } from '@/server/utils/parseWithAwait';
 
 // 路由定义
 const routeDef = createRoute({
@@ -44,12 +45,15 @@ const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
     const service = new SolutionDesignService(AppDataSource);
     const result = await service.createSolutionDesign(data, user.id, data.originalFileId);
 
-    return c.json(result, 200);
+    // 使用parseWithAwait处理Promise字段
+    const validatedResult = await parseWithAwait(SolutionDesignSchema, result);
+
+    return c.json(validatedResult, 200);
 
   } catch (error) {
     console.error('创建方案设计失败:', error);
     const { code = 500, message = '创建方案设计失败' } = error as Error & { code?: number };
-    return c.json({ code, message }, code);
+    return c.json({ code, message }, code as 400 | 500 | 200);
   }
 });
 

+ 2 - 1
src/server/modules/membership/membership-plan.service.ts

@@ -1,6 +1,7 @@
 import { GenericCrudService } from '@/server/utils/generic-crud.service';
 import { DataSource } from 'typeorm';
 import { MembershipPlan } from './membership-plan.entity';
+import { MembershipType } from './membership-plan.schema';
 
 export class MembershipPlanService extends GenericCrudService<MembershipPlan> {
   constructor(dataSource: DataSource) {
@@ -18,7 +19,7 @@ export class MembershipPlanService extends GenericCrudService<MembershipPlan> {
   /**
    * 根据类型获取套餐
    */
-  async getPlanByType(type: string): Promise<MembershipPlan | null> {
+  async getPlanByType(type: MembershipType): Promise<MembershipPlan | null> {
     const plans = await this.repository.findOne({
       where: { type, isActive: 1 },
       order: { sortOrder: 'ASC' }

+ 1 - 1
src/server/modules/users/user.entity.ts

@@ -40,7 +40,7 @@ export class UserEntity {
   isDeleted!: DeleteStatus;
 
   @Column({ name: 'user_type', type: 'varchar', length: 20, default: 'basic', comment: '用户类型: basic, premium' })
-  userType!: string;
+  userType!: 'basic' | 'premium';
 
   @Column({ name: 'remaining_count', type: 'int', default: 5, comment: '剩余文档处理次数' })
   remainingCount!: number;