Kaynağa Gözat

♻️ refactor(silver-users): 分离DTO与实体定义并优化数据结构

- 将SilverUserProfileSchema、CreateSilverUserProfileDto和UpdateSilverUserProfileDto从entity文件迁移到dto文件
- 移除entity文件中的zod验证相关代码,保持实体类的纯粹性
- 调整SilverUserProfileDto中的字段定义,移除userId和certificationStatus等字段
- 添加avatarFileId字段替代原有的avatarUrl,支持文件管理功能
- 在service和api文件中更新相关引用路径,确保依赖正确
- 移动Gender、CertificationStatus和JobSeekingStatus枚举到dto文件统一管理
yourname 7 ay önce
ebeveyn
işleme
2b0521d1ff

+ 1 - 1
src/server/api/silver-talents-admin/index.ts

@@ -4,7 +4,7 @@ import {
   SilverUserProfileSchema,
   CreateSilverUserProfileDto,
   UpdateSilverUserProfileDto
-} from '@/server/modules/silver-users/silver-user-profile.entity';
+} from '@/server/modules/silver-users/silver-user-profile.dto';
 import { authMiddleware } from '@/server/middleware/auth.middleware';
 import { OpenAPIHono } from '@hono/zod-openapi';
 import statsRoute from './stats';

+ 2 - 1
src/server/modules/silver-users/silver-talent-admin.service.ts

@@ -1,5 +1,6 @@
 import { DataSource, Repository } from 'typeorm';
-import { SilverUserProfile, CertificationStatus, JobSeekingStatus } from './silver-user-profile.entity';
+import { SilverUserProfile } from './silver-user-profile.entity';
+import { CertificationStatus, JobSeekingStatus } from './silver-user-profile.dto';
 import { CreateSilverTalentRequest, UpdateSilverTalentRequest } from './silver-talent.dto';
 import debug from 'debug';
 

+ 79 - 129
src/server/modules/silver-users/silver-user-profile.dto.ts

@@ -20,138 +20,88 @@ export enum JobSeekingStatus {
 }
 
 export const CreateSilverUserProfileDto = z.object({
-  userId: z.coerce.number().int().positive().openapi({
-    description: '关联用户ID',
-    example: 1
-  }),
-  realName: z.string().max(50).openapi({
-    description: '真实姓名',
-    example: '张三'
-  }),
-  nickname: z.string().max(50).optional().openapi({
-    description: '网名/昵称',
-    example: '银龄达人'
-  }),
-  organization: z.string().max(255).optional().openapi({
-    description: '所属机构/单位',
-    example: '北京市老年协会'
-  }),
-  age: z.coerce.number().int().min(50).max(100).openapi({
-    description: '年龄',
-    example: 65
-  }),
-  gender: z.coerce.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().optional().openapi({
-    description: '邮箱地址',
-    example: 'user@example.com'
-  }),
-  avatarUrl: z.string().max(500).url().optional().openapi({
-    description: '头像URL',
-    example: 'https://example.com/avatar.jpg'
-  }),
-  personalIntro: z.string().optional().openapi({
-    description: '个人简介',
-    example: '具有30年教育经验的退休教师,擅长老年教育和培训'
-  }),
-  personalSkills: z.string().optional().openapi({
-    description: '个人技能',
-    example: '钢琴,书法,英语,老年心理辅导'
-  }),
-  personalExperience: z.string().optional().openapi({
-    description: '个人履历',
-    example: '1985-2015 北京市第一中学教师,2015-至今 社区志愿者'
-  }),
-  jobSeekingRequirements: z.string().optional().openapi({
-    description: '求职需求',
-    example: '寻求教育咨询或培训类兼职工作,时间灵活'
-  })
+  realName: z.string().max(50).openapi({ description: '真实姓名', example: '张三' }),
+  age: z.coerce.number().int().min(1).max(120).openapi({ description: '年龄', example: 65 }),
+  gender: z.coerce.number().int().min(1).max(3).openapi({ description: '性别:1-男,2-女,3-其他', example: 1 }),
+  phone: z.string().max(20).openapi({ description: '联系电话', example: '13800138000' }),
+  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' }),
+  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年,经验丰富' }),
+  certificationInfo: z.string().optional().openapi({ description: '认证信息', example: '教师资格证、工作经验证明' }),
+  jobSeekingRequirements: z.string().optional().openapi({ description: '求职需求', example: '希望找兼职教师工作,每周工作3天' })
 });
 
-export const UpdateSilverUserProfileDto = CreateSilverUserProfileDto.partial().extend({
-  certificationStatus: z.coerce.number().int().min(0).max(3).optional().openapi({
-    description: '认证状态 0:未认证 1:待认证 2:已认证 3:认证失败',
-    example: 2
-  }),
-  certificationInfo: z.string().optional().openapi({
-    description: '认证信息',
-    example: '教师资格证,心理咨询师证'
-  }),
-  jobSeekingStatus: z.coerce.number().int().min(0).max(2).optional().openapi({
-    description: '求职状态 0:不求职 1:积极求职 2:观望中',
-    example: 1
-  })
+export const UpdateSilverUserProfileDto = z.object({
+  realName: z.string().max(50).optional().openapi({ description: '真实姓名', example: '张三' }),
+  age: z.coerce.number().int().min(1).max(120).optional().openapi({ description: '年龄', example: 65 }),
+  gender: z.coerce.number().int().min(1).max(3).optional().openapi({ description: '性别:1-男,2-女,3-其他', example: 1 }),
+  phone: z.string().max(20).optional().openapi({ description: '联系电话', example: '13800138000' }),
+  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' }),
+  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年,经验丰富' }),
+  certificationInfo: z.string().optional().openapi({ description: '认证信息', example: '教师资格证、工作经验证明' }),
+  jobSeekingRequirements: z.string().optional().openapi({ description: '求职需求', example: '希望找兼职教师工作,每周工作3天' })
 });
 
 export const SilverUserProfileSchema = z.object({
-  id: z.number().int().positive().openapi({
-    description: '用户档案ID',
-    example: 1
-  }),
-  userId: z.number().int().positive().openapi({
-    description: '关联用户ID',
-    example: 1
-  }),
-  realName: z.string().max(50).openapi({
-    description: '真实姓名',
-    example: '张三'
-  }),
-  nickname: z.string().max(50).nullable().openapi({
-    description: '网名/昵称',
-    example: '银龄达人'
-  }),
-  organization: z.string().max(255).nullable().openapi({
-    description: '所属机构/单位',
-    example: '北京市老年协会'
-  }),
-  age: z.number().int().min(50).max(100).openapi({
-    description: '年龄',
-    example: 65
-  }),
-  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().openapi({
-    description: '邮箱地址',
-    example: 'user@example.com'
-  }),
-  avatarUrl: z.string().max(500).url().nullable().openapi({
-    description: '头像URL',
-    example: 'https://example.com/avatar.jpg'
-  }),
-  personalIntro: z.string().nullable().openapi({
-    description: '个人简介',
-    example: '具有30年教育经验的退休教师,擅长老年教育和培训'
-  }),
-  personalSkills: z.string().nullable().openapi({
-    description: '个人技能',
-    example: '钢琴,书法,英语,老年心理辅导'
-  }),
-  personalExperience: z.string().nullable().openapi({
-    description: '个人履历',
-    example: '1985-2015 北京市第一中学教师,2015-至今 社区志愿者'
-  }),
-  certificationStatus: z.number().int().min(0).max(3).openapi({
-    description: '认证状态 0:未认证 1:待认证 2:已认证 3:认证失败',
-    example: 2
-  }),
-  certificationInfo: z.string().nullable().openapi({
-    description: '认证信息',
-    example: '教师资格证,心理咨询师证'
-  }),
-  jobSeekingStatus: z.number().int().min(0).max(2).openapi({
-    description: '求职状态 0:不求职 1:积极求职 2:观望中',
-    example: 1
-  })
+  id: z.number().int().positive().openapi({ description: '用户资料ID', example: 1 }),
+  userId: z.number().int().positive().openapi({ description: '关联用户ID', example: 1 }),
+  realName: z.string().max(50).openapi({ description: '真实姓名', example: '张三' }),
+  nickname: z.string().max(50).nullable().optional().openapi({ description: '昵称', example: '张大爷' }),
+  organization: z.string().max(255).nullable().optional().openapi({ description: '所属组织/机构', example: '社区服务中心' }),
+  age: z.number().int().min(1).max(120).openapi({ description: '年龄', example: 65 }),
+  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' }),
+  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年,经验丰富' }),
+  certificationStatus: z.number().int().min(0).max(3).openapi({ description: '认证状态:0-未认证,1-认证中,2-已认证,3-已拒绝', example: 0 }),
+  certificationInfo: z.string().nullable().optional().openapi({ description: '认证信息', example: '教师资格证、工作经验证明' }),
+  jobSeekingStatus: z.number().int().min(0).max(2).openapi({ description: '求职状态:0-未求职,1-积极求职,2-观望机会', example: 0 }),
+  jobSeekingRequirements: z.string().nullable().optional().openapi({ description: '求职需求', example: '希望找兼职教师工作,每周工作3天' }),
+  totalPoints: z.number().int().min(0).openapi({ description: '总积分', example: 100 }),
+  resumeCount: z.number().int().min(0).openapi({ description: '简历数量', example: 1 }),
+  applicationCount: z.number().int().min(0).openapi({ description: '投递数量', example: 5 }),
+  timeBankHours: z.coerce.number().openapi({ description: '时间银行小时数', example: 10.5 }),
+  knowledgeContributions: z.number().int().min(0).openapi({ description: '知识贡献数', example: 3 }),
+  knowledgeShareCount: z.number().int().min(0).openapi({ description: '知识分享数', example: 3 }),
+  knowledgeDownloadCount: z.number().int().min(0).openapi({ description: '知识下载数', example: 15 }),
+  knowledgeLikeCount: z.number().int().min(0).openapi({ description: '知识点赞数', example: 25 }),
+  knowledgeReadCount: z.number().int().min(0).openapi({ description: '知识阅读数', example: 100 }),
+  knowledgeFavoriteCount: z.number().int().min(0).openapi({ description: '知识收藏数', example: 8 }),
+  knowledgeCommentCount: z.number().int().min(0).openapi({ description: '知识评论数', example: 5 }),
+  knowledgeRanking: z.number().int().min(0).openapi({ description: '知识排名', example: 1 }),
+  knowledgeRankingScore: z.coerce.number().openapi({ description: '知识排名分数', example: 95.5 }),
+  createdAt: z.date().openapi({ description: '创建时间', example: '2024-01-01T00:00:00Z' }),
+  updatedAt: z.date().openapi({ description: '更新时间', example: '2024-01-01T00:00:00Z' }),
+  createdBy: z.number().int().positive().nullable().optional().openapi({ description: '创建人ID', example: 1 }),
+  updatedBy: z.number().int().positive().nullable().optional().openapi({ description: '更新人ID', example: 1 })
 });

+ 2 - 109
src/server/modules/silver-users/silver-user-profile.entity.ts

@@ -1,26 +1,7 @@
 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 {
-  MALE = 1,
-  FEMALE = 2,
-  OTHER = 3
-}
-
-export enum CertificationStatus {
-  UNCERTIFIED = 0,
-  PENDING = 1,
-  CERTIFIED = 2,
-  REJECTED = 3
-}
-
-export enum JobSeekingStatus {
-  NOT_SEEKING = 0,
-  ACTIVELY_SEEKING = 1,
-  OPEN_TO_OPPORTUNITIES = 2
-}
+import { CertificationStatus, Gender, JobSeekingStatus } from './silver-user-profile.dto';
 
 @Entity('silver_user_profiles')
 export class SilverUserProfile {
@@ -138,92 +119,4 @@ export class SilverUserProfile {
 
   @Column({ name: 'updated_by', type: 'int', nullable: true })
   updatedBy!: number | null;
-}
-
-// Zod Schemas for API
-export const SilverUserProfileSchema = z.object({
-  id: z.number().int().positive().openapi({ description: '用户资料ID', example: 1 }),
-  userId: z.number().int().positive().openapi({ description: '关联用户ID', example: 1 }),
-  realName: z.string().max(50).openapi({ description: '真实姓名', example: '张三' }),
-  nickname: z.string().max(50).nullable().optional().openapi({ description: '昵称', example: '张大爷' }),
-  organization: z.string().max(255).nullable().optional().openapi({ description: '所属组织/机构', example: '社区服务中心' }),
-  age: z.number().int().min(1).max(120).openapi({ description: '年龄', example: 65 }),
-  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' }),
-  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年,经验丰富' }),
-  certificationStatus: z.number().int().min(0).max(3).openapi({ description: '认证状态:0-未认证,1-认证中,2-已认证,3-已拒绝', example: 0 }),
-  certificationInfo: z.string().nullable().optional().openapi({ description: '认证信息', example: '教师资格证、工作经验证明' }),
-  jobSeekingStatus: z.number().int().min(0).max(2).openapi({ description: '求职状态:0-未求职,1-积极求职,2-观望机会', example: 0 }),
-  jobSeekingRequirements: z.string().nullable().optional().openapi({ description: '求职需求', example: '希望找兼职教师工作,每周工作3天' }),
-  totalPoints: z.number().int().min(0).openapi({ description: '总积分', example: 100 }),
-  resumeCount: z.number().int().min(0).openapi({ description: '简历数量', example: 1 }),
-  applicationCount: z.number().int().min(0).openapi({ description: '投递数量', example: 5 }),
-  timeBankHours: z.coerce.number().openapi({ description: '时间银行小时数', example: 10.5 }),
-  knowledgeContributions: z.number().int().min(0).openapi({ description: '知识贡献数', example: 3 }),
-  knowledgeShareCount: z.number().int().min(0).openapi({ description: '知识分享数', example: 3 }),
-  knowledgeDownloadCount: z.number().int().min(0).openapi({ description: '知识下载数', example: 15 }),
-  knowledgeLikeCount: z.number().int().min(0).openapi({ description: '知识点赞数', example: 25 }),
-  knowledgeReadCount: z.number().int().min(0).openapi({ description: '知识阅读数', example: 100 }),
-  knowledgeFavoriteCount: z.number().int().min(0).openapi({ description: '知识收藏数', example: 8 }),
-  knowledgeCommentCount: z.number().int().min(0).openapi({ description: '知识评论数', example: 5 }),
-  knowledgeRanking: z.number().int().min(0).openapi({ description: '知识排名', example: 1 }),
-  knowledgeRankingScore: z.coerce.number().openapi({ description: '知识排名分数', example: 95.5 }),
-  createdAt: z.date().openapi({ description: '创建时间', example: '2024-01-01T00:00:00Z' }),
-  updatedAt: z.date().openapi({ description: '更新时间', example: '2024-01-01T00:00:00Z' }),
-  createdBy: z.number().int().positive().nullable().optional().openapi({ description: '创建人ID', example: 1 }),
-  updatedBy: z.number().int().positive().nullable().optional().openapi({ description: '更新人ID', example: 1 })
-});
-
-export const CreateSilverUserProfileDto = z.object({
-  realName: z.string().max(50).openapi({ description: '真实姓名', example: '张三' }),
-  age: z.coerce.number().int().min(1).max(120).openapi({ description: '年龄', example: 65 }),
-  gender: z.coerce.number().int().min(1).max(3).openapi({ description: '性别:1-男,2-女,3-其他', example: 1 }),
-  phone: z.string().max(20).openapi({ description: '联系电话', example: '13800138000' }),
-  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' }),
-  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年,经验丰富' }),
-  certificationInfo: z.string().optional().openapi({ description: '认证信息', example: '教师资格证、工作经验证明' }),
-  jobSeekingRequirements: z.string().optional().openapi({ description: '求职需求', example: '希望找兼职教师工作,每周工作3天' })
-});
-
-export const UpdateSilverUserProfileDto = z.object({
-  realName: z.string().max(50).optional().openapi({ description: '真实姓名', example: '张三' }),
-  age: z.coerce.number().int().min(1).max(120).optional().openapi({ description: '年龄', example: 65 }),
-  gender: z.coerce.number().int().min(1).max(3).optional().openapi({ description: '性别:1-男,2-女,3-其他', example: 1 }),
-  phone: z.string().max(20).optional().openapi({ description: '联系电话', example: '13800138000' }),
-  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' }),
-  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年,经验丰富' }),
-  certificationInfo: z.string().optional().openapi({ description: '认证信息', example: '教师资格证、工作经验证明' }),
-  jobSeekingRequirements: z.string().optional().openapi({ description: '求职需求', example: '希望找兼职教师工作,每周工作3天' })
-});
+}