2
0

chat-message.schema.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import { z } from '@hono/zod-openapi';
  2. import { UserSchema } from '@/server/modules/users/user.schema';
  3. // 基础消息Schema
  4. export const ChatMessageSchema = z.object({
  5. id: z.number().int().positive().openapi({
  6. example: 1,
  7. description: '消息ID'
  8. }),
  9. classId: z.string().openapi({
  10. example: 'class_123456',
  11. description: '课堂ID'
  12. }),
  13. type: z.enum(['text', 'image', 'system']).openapi({
  14. example: 'text',
  15. description: '消息类型'
  16. }),
  17. content: z.string().openapi({
  18. example: '这是一条文本消息',
  19. description: '消息内容'
  20. }),
  21. senderId: z.number().int().positive().nullable().openapi({
  22. example: 1,
  23. description: '发送者ID'
  24. }),
  25. sender: UserSchema.omit({ password: true }).nullable().optional().openapi({
  26. description: '发送者用户信息'
  27. }),
  28. senderName: z.string().nullable().openapi({
  29. example: '张三',
  30. description: '发送者名称'
  31. }),
  32. timestamp: z.coerce.number<number>().int().positive().openapi({
  33. example: 1704067200000,
  34. description: '消息时间戳'
  35. }),
  36. fileId: z.number().int().positive().nullable().openapi({
  37. example: 1,
  38. description: '关联文件ID(用于图片消息)'
  39. }),
  40. file: z.object({
  41. id: z.number().int().positive().openapi({ description: '文件ID' }),
  42. name: z.string().max(255).openapi({ description: '文件名', example: 'example.jpg' }),
  43. fullUrl: z.string().openapi({ description: '文件完整URL', example: 'https://example.com/file.jpg' }),
  44. type: z.string().nullable().openapi({ description: '文件类型', example: 'image/jpeg' }),
  45. size: z.number().nullable().openapi({ description: '文件大小(字节)', example: 102400 })
  46. }).nullable().optional().openapi({
  47. description: '{描述}文件信息'
  48. }),
  49. createdBy: z.number().int().positive().nullable().openapi({
  50. example: 1,
  51. description: '创建用户ID'
  52. }),
  53. updatedBy: z.number().int().positive().nullable().openapi({
  54. example: 1,
  55. description: '更新用户ID'
  56. }),
  57. createdAt: z.coerce.date().openapi({
  58. example: '2024-01-01T12:00:00Z',
  59. description: '创建时间'
  60. }),
  61. updatedAt: z.coerce.date().openapi({
  62. example: '2024-01-01T12:00:00Z',
  63. description: '更新时间'
  64. })
  65. });
  66. // 创建消息DTO
  67. export const CreateChatMessageDto = z.object({
  68. classId: z.string().min(1, '课堂ID不能为空').openapi({
  69. example: 'class_123456',
  70. description: '课堂ID'
  71. }),
  72. type: z.enum(['text', 'image', 'system']).openapi({
  73. example: 'text',
  74. description: '消息类型'
  75. }),
  76. content: z.string().min(1, '消息内容不能为空').openapi({
  77. example: '这是一条文本消息',
  78. description: '消息内容'
  79. }),
  80. senderId: z.coerce.number().int().positive().nullable().optional().openapi({
  81. example: 1,
  82. description: '发送者ID'
  83. }),
  84. senderName: z.string().nullable().optional().openapi({
  85. example: '张三',
  86. description: '发送者名称'
  87. }),
  88. timestamp: z.coerce.number().int().positive().openapi({
  89. example: 1704067200000,
  90. description: '消息时间戳(毫秒)'
  91. }),
  92. fileId: z.coerce.number().int().positive().nullable().optional().openapi({
  93. example: 1,
  94. description: '关联文件ID(用于图片消息)'
  95. })
  96. });
  97. // 更新消息DTO
  98. export const UpdateChatMessageDto = z.object({
  99. classId: z.string().min(1, '课堂ID不能为空').optional().openapi({
  100. example: 'class_123456',
  101. description: '课堂ID'
  102. }),
  103. type: z.enum(['text', 'image', 'system']).optional().openapi({
  104. example: 'text',
  105. description: '消息类型'
  106. }),
  107. content: z.string().min(1, '消息内容不能为空').optional().openapi({
  108. example: '这是一条文本消息',
  109. description: '消息内容'
  110. }),
  111. senderId: z.coerce.number().int().positive().nullable().optional().openapi({
  112. example: 1,
  113. description: '发送者ID'
  114. }),
  115. senderName: z.string().nullable().optional().openapi({
  116. example: '张三',
  117. description: '发送者名称'
  118. }),
  119. timestamp: z.coerce.number().int().positive().optional().openapi({
  120. example: 1704067200000,
  121. description: '消息时间戳'
  122. }),
  123. fileId: z.coerce.number().int().positive().nullable().optional().openapi({
  124. example: 1,
  125. description: '关联文件ID(用于图片消息)'
  126. })
  127. });
  128. // 消息列表响应Schema
  129. export const ChatMessageListResponse = z.object({
  130. data: z.array(ChatMessageSchema),
  131. pagination: z.object({
  132. total: z.number().openapi({
  133. example: 100,
  134. description: '总记录数'
  135. }),
  136. current: z.number().openapi({
  137. example: 1,
  138. description: '当前页码'
  139. }),
  140. pageSize: z.number().openapi({
  141. example: 10,
  142. description: '每页数量'
  143. })
  144. })
  145. });
  146. // 历史消息查询参数
  147. export const HistoryQuerySchema = z.object({
  148. classId: z.string().min(1, '课堂ID不能为空').openapi({
  149. example: 'class_123456',
  150. description: '课堂ID'
  151. }),
  152. page: z.coerce.number().int().positive().default(1).openapi({
  153. example: 1,
  154. description: '页码'
  155. }),
  156. pageSize: z.coerce.number().int().positive().default(50).openapi({
  157. example: 50,
  158. description: '每页数量'
  159. })
  160. });