|
@@ -0,0 +1,117 @@
|
|
|
|
|
+import { z } from '@hono/zod-openapi';
|
|
|
|
|
+import { Gender, CertificationStatus, JobSeekingStatus } from './silver-user-profile.entity';
|
|
|
|
|
+
|
|
|
|
|
+// 基础响应 schema
|
|
|
|
|
+export const SilverTalentSchema = z.object({
|
|
|
|
|
+ id: z.number().int().positive().openapi({ description: '人才ID', example: 1 }),
|
|
|
|
|
+ userId: z.number().int().positive().openapi({ description: '用户ID', example: 123 }),
|
|
|
|
|
+ realName: z.string().min(1).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.enum(['MALE', 'FEMALE', 'OTHER']).openapi({ description: '性别', example: 'MALE' }),
|
|
|
|
|
+ phone: z.string().max(20).openapi({ description: '联系电话', example: '13800138000' }),
|
|
|
|
|
+ email: z.string().max(255).email().nullable().openapi({ description: '邮箱', example: 'example@email.com' }),
|
|
|
|
|
+ avatarUrl: z.string().max(500).url().nullable().openapi({ description: '头像URL', example: 'https://example.com/avatar.jpg' }),
|
|
|
|
|
+ personalIntro: z.string().max(1000).nullable().openapi({ description: '个人简介', example: '退休中学语文教师,擅长书法和传统文化教育' }),
|
|
|
|
|
+ personalSkills: z.string().max(2000).nullable().openapi({ description: '个人技能', example: '书法、国画、古典文学、诗词创作' }),
|
|
|
|
|
+ personalExperience: z.string().max(3000).nullable().openapi({ description: '个人经历', example: '从事教育工作40年,曾在重点中学任教...' }),
|
|
|
|
|
+ certificationStatus: z.enum(['UNCERTIFIED', 'PENDING', 'CERTIFIED', 'REJECTED']).openapi({ description: '认证状态', example: 'CERTIFIED' }),
|
|
|
|
|
+ certificationInfo: z.string().max(2000).nullable().openapi({ description: '认证信息', example: '高级教师职称证书、书法协会会员证' }),
|
|
|
|
|
+ jobSeekingStatus: z.enum(['NOT_SEEKING', 'ACTIVELY_SEEKING', 'OPEN_TO_OPPORTUNITIES']).openapi({ description: '求职状态', example: 'ACTIVELY_SEEKING' }),
|
|
|
|
|
+ jobSeekingRequirements: z.string().max(1000).nullable().openapi({ description: '求职需求', example: '希望寻找文化教育类兼职工作,时间灵活' }),
|
|
|
|
|
+
|
|
|
|
|
+ // 统计信息
|
|
|
|
|
+ totalPoints: z.number().int().min(0).default(0).openapi({ description: '总积分', example: 1250 }),
|
|
|
|
|
+ resumeCount: z.number().int().min(0).default(0).openapi({ description: '简历数量', example: 3 }),
|
|
|
|
|
+ applicationCount: z.number().int().min(0).default(0).openapi({ description: '申请次数', example: 15 }),
|
|
|
|
|
+ timeBankHours: z.number().min(0).default(0).openapi({ description: '时间银行小时数', example: 25.5 }),
|
|
|
|
|
+ knowledgeContributions: z.number().int().min(0).default(0).openapi({ description: '知识贡献数量', example: 8 }),
|
|
|
|
|
+
|
|
|
|
|
+ // 知识库统计
|
|
|
|
|
+ knowledgeShareCount: z.number().int().min(0).default(0).openapi({ description: '知识分享数', example: 5 }),
|
|
|
|
|
+ knowledgeDownloadCount: z.number().int().min(0).default(0).openapi({ description: '下载次数', example: 120 }),
|
|
|
|
|
+ knowledgeLikeCount: z.number().int().min(0).default(0).openapi({ description: '点赞次数', example: 45 }),
|
|
|
|
|
+ knowledgeReadCount: z.number().int().min(0).default(0).openapi({ description: '阅读次数', example: 356 }),
|
|
|
|
|
+ knowledgeFavoriteCount: z.number().int().min(0).default(0).openapi({ description: '收藏次数', example: 12 }),
|
|
|
|
|
+ knowledgeCommentCount: z.number().int().min(0).default(0).openapi({ description: '评论次数', example: 8 }),
|
|
|
|
|
+ knowledgeRanking: z.number().int().min(0).default(0).openapi({ description: '知识排名', example: 15 }),
|
|
|
|
|
+ knowledgeRankingScore: z.number().min(0).default(0).openapi({ description: '知识排名分数', example: 85.5 }),
|
|
|
|
|
+
|
|
|
|
|
+ // 时间信息
|
|
|
|
|
+ createdAt: z.date().openapi({ description: '创建时间', example: '2024-01-15T10:30:00Z' }),
|
|
|
|
|
+ updatedAt: z.date().openapi({ description: '更新时间', example: '2024-01-20T14:45:00Z' })
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 创建人才DTO
|
|
|
|
|
+export const CreateSilverTalentDto = z.object({
|
|
|
|
|
+ realName: z.string().min(1).max(50).openapi({ description: '真实姓名', example: '张老先生' }),
|
|
|
|
|
+ nickname: z.string().max(50).optional().openapi({ description: '昵称', example: '张老师' }),
|
|
|
|
|
+ organization: z.string().max(255).optional().openapi({ description: '所属机构' }),
|
|
|
|
|
+ age: z.number().int().min(50).max(100).openapi({ description: '年龄', example: 65 }),
|
|
|
|
|
+ gender: z.enum(['MALE', 'FEMALE', 'OTHER']).openapi({ description: '性别' }),
|
|
|
|
|
+ phone: z.string().max(20).openapi({ description: '联系电话' }),
|
|
|
|
|
+ email: z.string().max(255).email().optional().openapi({ description: '邮箱' }),
|
|
|
|
|
+ personalIntro: z.string().max(1000).optional().openapi({ description: '个人简介' }),
|
|
|
|
|
+ personalSkills: z.string().max(2000).optional().openapi({ description: '个人技能,以逗号分隔', example: '书法,国画,古典文学' }),
|
|
|
|
|
+ personalExperience: z.string().max(3000).optional().openapi({ description: '个人经历' }),
|
|
|
|
|
+ jobSeekingRequirements: z.string().max(1000).optional().openapi({ description: '求职需求' })
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 更新人才DTO
|
|
|
|
|
+export const UpdateSilverTalentDto = z.object({
|
|
|
|
|
+ realName: z.string().min(1).max(50).optional().openapi({ description: '真实姓名' }),
|
|
|
|
|
+ nickname: z.string().max(50).optional().openapi({ description: '昵称' }),
|
|
|
|
|
+ organization: z.string().max(255).optional().openapi({ description: '所属机构' }),
|
|
|
|
|
+ age: z.number().int().min(50).max(100).optional().openapi({ description: '年龄' }),
|
|
|
|
|
+ gender: z.enum(['MALE', 'FEMALE', 'OTHER']).optional().openapi({ description: '性别' }),
|
|
|
|
|
+ phone: z.string().max(20).optional().openapi({ description: '联系电话' }),
|
|
|
|
|
+ email: z.string().max(255).email().optional().openapi({ description: '邮箱' }),
|
|
|
|
|
+ personalIntro: z.string().max(1000).optional().openapi({ description: '个人简介' }),
|
|
|
|
|
+ personalSkills: z.string().max(2000).optional().openapi({ description: '个人技能' }),
|
|
|
|
|
+ personalExperience: z.string().max(3000).optional().openapi({ description: '个人经历' }),
|
|
|
|
|
+ jobSeekingStatus: z.enum(['NOT_SEEKING', 'ACTIVELY_SEEKING', 'OPEN_TO_OPPORTUNITIES']).optional().openapi({ description: '求职状态' }),
|
|
|
|
|
+ jobSeekingRequirements: z.string().max(1000).optional().openapi({ description: '求职需求' })
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 搜索参数DTO
|
|
|
|
|
+export const SearchSilverTalentDto = z.object({
|
|
|
|
|
+ keyword: z.string().optional().openapi({ description: '搜索关键词', example: '书法' }),
|
|
|
|
|
+ city: z.string().optional().openapi({ description: '城市筛选', example: '北京' }),
|
|
|
|
|
+ minAge: z.coerce.number().int().min(50).optional().openapi({ description: '最小年龄' }),
|
|
|
|
|
+ maxAge: z.coerce.number().int().max(100).optional().openapi({ description: '最大年龄' }),
|
|
|
|
|
+ skills: z.array(z.string()).optional().openapi({ description: '技能筛选', example: ['书法', '国画'] }),
|
|
|
|
|
+ certified: z.coerce.boolean().optional().openapi({ description: '仅认证用户', example: true }),
|
|
|
|
|
+ available: z.coerce.boolean().optional().openapi({ description: '仅可服务用户', example: true }),
|
|
|
|
|
+ sortBy: z.enum(['createdAt', 'rating', 'popularity', 'experience']).default('createdAt').openapi({ description: '排序字段' }),
|
|
|
|
|
+ sortOrder: z.enum(['asc', 'desc']).default('desc').openapi({ description: '排序方向' }),
|
|
|
|
|
+ page: z.coerce.number().int().min(1).default(1).openapi({ description: '页码', example: 1 }),
|
|
|
|
|
+ pageSize: z.coerce.number().int().min(1).max(50).default(20).openapi({ description: '每页数量', example: 20 })
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 列表响应DTO
|
|
|
|
|
+export const SilverTalentListResponse = z.object({
|
|
|
|
|
+ data: z.array(SilverTalentSchema).openapi({ description: '人才列表数据' }),
|
|
|
|
|
+ pagination: z.object({
|
|
|
|
|
+ total: z.number().openapi({ example: 100, description: '总记录数' }),
|
|
|
|
|
+ current: z.number().openapi({ example: 1, description: '当前页码' }),
|
|
|
|
|
+ pageSize: z.number().openapi({ example: 20, description: '每页数量' }),
|
|
|
|
|
+ totalPages: z.number().openapi({ example: 5, description: '总页数' })
|
|
|
|
|
+ })
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 技能标签DTO
|
|
|
|
|
+export const TalentSkillDto = z.object({
|
|
|
|
|
+ skillName: z.string().min(1).max(50).openapi({ description: '技能名称', example: '书法' }),
|
|
|
|
|
+ skillLevel: z.enum(['初级', '中级', '高级', '专家']).default('中级').openapi({ description: '技能等级' }),
|
|
|
|
|
+ yearsExperience: z.coerce.number().int().min(0).default(0).openapi({ description: '经验年数', example: 10 }),
|
|
|
|
|
+ certificationUrl: z.string().url().optional().openapi({ description: '认证链接' })
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 响应类型定义
|
|
|
|
|
+export type SilverTalent = z.infer<typeof SilverTalentSchema>;
|
|
|
|
|
+export type CreateSilverTalentRequest = z.infer<typeof CreateSilverTalentDto>;
|
|
|
|
|
+export type UpdateSilverTalentRequest = z.infer<typeof UpdateSilverTalentDto>;
|
|
|
|
|
+export type SearchSilverTalentParams = z.infer<typeof SearchSilverTalentDto>;
|
|
|
|
|
+export type SilverTalentListResponseType = z.infer<typeof SilverTalentListResponse>;
|
|
|
|
|
+export type TalentSkill = z.infer<typeof TalentSkillDto>;
|