Просмотр исходного кода

✨ feat(silver-users): 重构用户头像存储方式为文件关联模型

- 将头像存储从URL字符串改为文件ID关联
- 新增avatarFileId字段关联File实体
- 添加avatarFile关系用于获取完整文件信息
- 更新API文档以反映新的头像文件结构
- 移除原有的avatarUrl字段

✨ feat(api): 添加用户头像文件关系查询支持

- 在银龄用户资料路由中添加relations配置,默认关联查询avatarFile
- 更新API schema以支持返回头像文件详细信息
- 调整DTO结构,使用avatarFileId替代原avatarUrl字段
yourname 7 месяцев назад
Родитель
Сommit
0977f56da2

+ 2 - 1
src/server/api/silver-users/profiles/index.ts

@@ -14,7 +14,8 @@ const silverUserProfileRoutes = createCrudRoutes({
     createdByField: 'createdBy',
     updatedByField: 'updatedBy',
     userIdField: 'userId'
-  }
+  },
+  relations: ['avatarFile']
 });
 
 export default silverUserProfileRoutes;

+ 24 - 4
src/server/modules/silver-users/silver-user-profile.entity.ts

@@ -1,5 +1,6 @@
 import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn } from 'typeorm';
 import { UserEntity } from '../users/user.entity';
+import { File } from '../files/file.entity';
 import { z } from '@hono/zod-openapi';
 
 export enum Gender {
@@ -55,8 +56,12 @@ export class SilverUserProfile {
   @Column({ name: 'email', type: 'varchar', length: 255, nullable: true })
   email!: string | null;
 
-  @Column({ name: 'avatar_url', type: 'text', nullable: true })
-  avatarUrl!: string | null;
+  @Column({ name: 'avatar_file_id', type: 'int', unsigned: true, nullable: true, comment: '头像文件ID' })
+  avatarFileId!: number | null;
+
+  @ManyToOne(() => File, { nullable: true })
+  @JoinColumn({ name: 'avatar_file_id', referencedColumnName: 'id' })
+  avatarFile!: File | null;
 
   @Column({ name: 'personal_intro', type: 'text', nullable: true })
   personalIntro!: string | null;
@@ -146,7 +151,19 @@ export const SilverUserProfileSchema = z.object({
   gender: z.number().int().min(1).max(3).openapi({ description: '性别:1-男,2-女,3-其他', example: 1 }),
   phone: z.string().max(20).openapi({ description: '联系电话', example: '13800138000' }),
   email: z.string().max(255).email().nullable().optional().openapi({ description: '电子邮箱', example: 'example@email.com' }),
-  avatarUrl: z.string().url().nullable().optional().openapi({ description: '头像URL', example: 'https://example.com/avatar.jpg' }),
+  avatarFileId: z.number().int().positive().nullable().optional().openapi({
+    example: 1,
+    description: '头像文件ID'
+  }),
+  avatarFile: z.object({
+    id: z.number().int().positive().openapi({ description: '文件ID' }),
+    name: z.string().max(255).openapi({ description: '文件名', example: 'avatar.jpg' }),
+    fullUrl: z.string().openapi({ description: '文件完整URL', example: 'https://example.com/avatar.jpg' }),
+    type: z.string().nullable().openapi({ description: '文件类型', example: 'image/jpeg' }),
+    size: z.number().nullable().openapi({ description: '文件大小(字节)', example: 102400 })
+  }).nullable().optional().openapi({
+    description: '头像文件信息'
+  }),
   personalIntro: z.string().nullable().optional().openapi({ description: '个人简介', example: '退休教师,热爱教育事业' }),
   personalSkills: z.string().nullable().optional().openapi({ description: '个人技能', example: '书法、绘画、音乐教学' }),
   personalExperience: z.string().nullable().optional().openapi({ description: '个人经历', example: '从事教育工作40年,经验丰富' }),
@@ -181,7 +198,10 @@ export const CreateSilverUserProfileDto = z.object({
   nickname: z.string().max(50).optional().openapi({ description: '昵称', example: '张大爷' }),
   organization: z.string().max(255).optional().openapi({ description: '所属组织/机构', example: '社区服务中心' }),
   email: z.string().max(255).email().optional().openapi({ description: '电子邮箱', example: 'example@email.com' }),
-  avatarUrl: z.string().url().optional().openapi({ description: '头像URL', example: 'https://example.com/avatar.jpg' }),
+  avatarFileId: z.number().int().positive().optional().openapi({
+    example: 1,
+    description: '头像文件ID'
+  }),
   personalIntro: z.string().optional().openapi({ description: '个人简介', example: '退休教师,热爱教育事业' }),
   personalSkills: z.string().optional().openapi({ description: '个人技能', example: '书法、绘画、音乐教学' }),
   personalExperience: z.string().optional().openapi({ description: '个人经历', example: '从事教育工作40年,经验丰富' }),