Browse Source

♻️ refactor(users): 重构用户模块相关代码

- 移动UserSchema从user.entity到user.schema文件
- 引入CreateUserDto和UpdateUserDto替代直接使用UserSchema
- 添加avatarFile关联关系查询用户头像信息
- 使用parseWithAwait工具函数处理数据解析
- 优化错误处理代码格式

📝 docs(users): 更新用户API文档引用

- 调整用户相关API中的schema引用路径
- 统一使用user.schema中的类型定义
- 移除重复的UpdateUserSchema定义
- 修复导入路径错误问题
yourname 6 months ago
parent
commit
edf36c5633

+ 4 - 4
src/server/api/users/[id]/get.ts

@@ -5,7 +5,7 @@ import { authMiddleware } from '@/server/middleware/auth.middleware';
 import { ErrorSchema } from '@/server/utils/errorHandler';
 import { AppDataSource } from '@/server/data-source';
 import { AuthContext } from '@/server/types/context';
-import { UserSchema } from '@/server/modules/users/user.entity';
+import { UserSchema } from '@/server/modules/users/user.schema';
 
 const userService = new UserService(AppDataSource);
 
@@ -49,9 +49,9 @@ const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
     }
     return c.json(user, 200);
   } catch (error) {
-    return c.json({ 
-      code: 500, 
-      message: error instanceof Error ? error.message : '获取用户详情失败' 
+    return c.json({
+      code: 500,
+      message: error instanceof Error ? error.message : '获取用户详情失败'
     }, 500);
   }
 });

+ 5 - 11
src/server/api/users/[id]/put.ts

@@ -5,7 +5,7 @@ import { authMiddleware } from '@/server/middleware/auth.middleware';
 import { ErrorSchema } from '@/server/utils/errorHandler';
 import { AppDataSource } from '@/server/data-source';
 import { AuthContext } from '@/server/types/context';
-import { UserSchema } from '@/server/modules/users/user.entity';
+import { UserSchema, UpdateUserDto } from '@/server/modules/users/user.schema';
 
 const userService = new UserService(AppDataSource);
 
@@ -17,12 +17,6 @@ const UpdateParams = z.object({
   })
 });
 
-const UpdateUserSchema = UserSchema.omit({ 
-  id: true,
-  createdAt: true,
-  updatedAt: true 
-}).partial();
-
 const routeDef = createRoute({
   method: 'put',
   path: '/{id}',
@@ -32,7 +26,7 @@ const routeDef = createRoute({
     body: {
       content: {
         'application/json': {
-          schema: UpdateUserSchema
+          schema: UpdateUserDto
         }
       }
     }
@@ -67,9 +61,9 @@ const app = new OpenAPIHono<AuthContext>().openapi(routeDef, async (c) => {
     }
     return c.json(user, 200);
   } catch (error) {
-    return c.json({ 
-      code: 500, 
-      message: error instanceof Error ? error.message : '更新用户失败' 
+    return c.json({
+      code: 500,
+      message: error instanceof Error ? error.message : '更新用户失败'
     }, 500);
   }
 });

+ 6 - 5
src/server/api/users/get.ts

@@ -5,7 +5,8 @@ import { authMiddleware } from '../../middleware/auth.middleware';
 import { ErrorSchema } from '../../utils/errorHandler';
 import { AppDataSource } from '../../data-source';
 import { AuthContext } from '../../types/context';
-import { UserSchema } from '../../modules/users/user.entity';
+import { UserSchema } from '../../modules/users/user.schema';
+import { parseWithAwait } from '@/server/utils/parseWithAwait';
 
 const userService = new UserService(AppDataSource);
 
@@ -87,7 +88,7 @@ const app = new OpenAPIHono<AuthContext>().openapi(listUsersRoute, async (c) =>
     });
     
     return c.json({
-      data: users,
+      data: await parseWithAwait(z.array(UserSchema), users),
       pagination: {
         total,
         current: page,
@@ -98,9 +99,9 @@ const app = new OpenAPIHono<AuthContext>().openapi(listUsersRoute, async (c) =>
     if (error instanceof z.ZodError) {
       return c.json({ code: 400, message: '参数错误' }, 400);
     }
-    return c.json({ 
-      code: 500, 
-      message: error instanceof Error ? error.message : '获取用户列表失败' 
+    return c.json({
+      code: 500,
+      message: error instanceof Error ? error.message : '获取用户列表失败'
     }, 500);
   }
 });

+ 2 - 16
src/server/api/users/post.ts

@@ -1,27 +1,13 @@
 import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
 import { UserService } from '../../modules/users/user.service';
-import { z } from '@hono/zod-openapi';
 import { authMiddleware } from '../../middleware/auth.middleware';
 import { ErrorSchema } from '../../utils/errorHandler';
 import { AppDataSource } from '../../data-source';
 import { AuthContext } from '../../types/context';
-import { UserSchema } from '@/server/modules/users/user.entity';
+import { UserSchema, CreateUserDto } from '@/server/modules/users/user.schema';
 
 const userService = new UserService(AppDataSource);
 
-
-const CreateUserSchema = UserSchema.omit({
-  id: true,
-  createdAt: true,
-  updatedAt: true,
-}).extend({
-  phone: UserSchema.shape.phone.optional(),
-  email: UserSchema.shape.email.optional(),
-  nickname: UserSchema.shape.nickname.optional(),
-  name: UserSchema.shape.name.optional(),
-  avatar: UserSchema.shape.avatar.optional(),
-})
-
 const createUserRoute = createRoute({
   method: 'post',
   path: '/',
@@ -30,7 +16,7 @@ const createUserRoute = createRoute({
     body: {
       content: {
         'application/json': {
-          schema: CreateUserSchema
+          schema: CreateUserDto
         }
       }
     }

+ 0 - 52
src/server/modules/users/user.entity.ts

@@ -66,55 +66,3 @@ export class UserEntity {
     Object.assign(this, partial);
   }
 }
-
-export const UserSchema = z.object({
-  id: z.number().int().positive().openapi({ description: '用户ID' }),
-  username: z.string().min(3).max(255).openapi({
-    example: 'admin',
-    description: '用户名,3-255个字符'
-  }),
-  password: z.string().min(6).max(255).openapi({
-    example: 'password123',
-    description: '密码,最少6位'
-  }),
-  phone: z.string().max(255).nullable().openapi({
-    example: '13800138000',
-    description: '手机号'
-  }),
-  email: z.string().email().max(255).nullable().openapi({
-    example: 'user@example.com',
-    description: '邮箱'
-  }),
-  nickname: z.string().max(255).nullable().openapi({
-    example: '昵称',
-    description: '用户昵称'
-  }),
-  name: z.string().max(255).nullable().openapi({
-    example: '张三',
-    description: '真实姓名'
-  }),
-  avatar: z.string().max(255).nullable().openapi({
-    example: 'https://example.com/avatar.jpg',
-    description: '用户头像'
-  }),
-  isDisabled: z.number().int().min(0).max(1).default(DisabledStatus.ENABLED).openapi({
-    example: DisabledStatus.ENABLED,
-    description: '是否禁用(0:启用,1:禁用)'
-  }),
-  isDeleted: z.number().int().min(0).max(1).default(DeleteStatus.NOT_DELETED).openapi({
-    example: DeleteStatus.NOT_DELETED,
-    description: '是否删除(0:未删除,1:已删除)'
-  }),
-  roles: z.array(RoleSchema).optional().openapi({
-    example: [
-      { id: 1, name: 'admin',description:'管理员', permissions: ['user:create'] ,createdAt: new Date(), updatedAt: new Date() }
-    ],
-    description: '用户角色列表'
-  }),
-  userType: z.enum([UserType.TEACHER, UserType.STUDENT]).default(UserType.STUDENT).openapi({
-    example: UserType.STUDENT,
-    description: '用户类型(teacher:老师,student:学生)'
-  }),
-  createdAt: z.date().openapi({ description: '创建时间' }),
-  updatedAt: z.date().openapi({ description: '更新时间' })
-});

+ 6 - 5
src/server/modules/users/user.service.ts

@@ -34,7 +34,7 @@ export class UserService {
     try {
       return await this.userRepository.findOne({ 
         where: { id },
-        relations: ['roles']
+        relations: ['roles', 'avatarFile']
       });
     } catch (error) {
       console.error('Error getting user:', error);
@@ -46,7 +46,7 @@ export class UserService {
     try {
       return await this.userRepository.findOne({
         where: { username },
-        relations: ['roles']
+        relations: ['roles', 'avatarFile']
       });
     } catch (error) {
       console.error('Error getting user:', error);
@@ -58,7 +58,7 @@ export class UserService {
     try {
       return await this.userRepository.findOne({
         where: { phone: phone },
-        relations: ['roles']
+        relations: ['roles', 'avatarFile']
       });
     } catch (error) {
       console.error('Error getting user by phone:', error);
@@ -100,6 +100,7 @@ export class UserService {
       const queryBuilder = this.userRepository
         .createQueryBuilder('user')
         .leftJoinAndSelect('user.roles', 'roles')
+        .leftJoinAndSelect('user.avatarFile', 'avatarFile')
         .skip(skip)
         .take(pageSize);
 
@@ -138,7 +139,7 @@ export class UserService {
   async getUsers(): Promise<User[]> {
     try {
       const users = await this.userRepository.find({
-        relations: ['roles']
+        relations: ['roles', 'avatarFile']
       });
       return users;
     } catch (error) {
@@ -156,7 +157,7 @@ export class UserService {
     try {
       return await this.userRepository.findOne({
         where: [{ username: account }, { email: account }],
-        relations: ['roles']
+        relations: ['roles', 'avatarFile']
       });
     } catch (error) {
       console.error('Error getting user by account:', error);