user.schema.mt.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. import { z } from '@hono/zod-openapi';
  2. import { DeleteStatus, DisabledStatus } from '@d8d/shared-types';
  3. import { RoleSchemaMt } from './role.schema.mt';
  4. // 多租户基础用户 schema(包含所有字段)
  5. export const UserSchemaMt = z.object({
  6. id: z.number().int().positive().openapi({ description: '用户ID' }),
  7. tenantId: z.number().int().positive().openapi({ description: '租户ID' }),
  8. username: z.string().min(3, '用户名至少3个字符').max(255, '用户名最多255个字符').openapi({
  9. example: 'admin',
  10. description: '用户名,3-255个字符'
  11. }),
  12. password: z.string().min(6, '密码至少6位').max(255, '密码最多255位').openapi({
  13. example: 'password123',
  14. description: '密码,最少6位'
  15. }),
  16. phone: z.string().max(255, '手机号最多255个字符').nullable().openapi({
  17. example: '13800138000',
  18. description: '手机号'
  19. }),
  20. email: z.email('请输入正确的邮箱格式').max(255, '邮箱最多255个字符').nullable().openapi({
  21. example: 'user@example.com',
  22. description: '邮箱'
  23. }),
  24. nickname: z.string().max(255, '昵称最多255个字符').nullable().openapi({
  25. example: '昵称',
  26. description: '用户昵称'
  27. }),
  28. name: z.string().max(255, '姓名最多255个字符').nullable().openapi({
  29. example: '张三',
  30. description: '真实姓名'
  31. }),
  32. avatarFileId: z.number().int().positive().nullable().openapi({
  33. example: 1,
  34. description: '头像文件ID'
  35. }),
  36. avatarFile: z.object({
  37. id: z.number().int().positive().openapi({ description: '文件ID' }),
  38. name: z.string().max(255).openapi({ description: '文件名', example: 'avatar.jpg' }),
  39. fullUrl: z.string().openapi({ description: '文件完整URL', example: 'https://example.com/avatar.jpg' }),
  40. type: z.string().nullable().openapi({ description: '文件类型', example: 'image/jpeg' }),
  41. size: z.number().nullable().openapi({ description: '文件大小(字节)', example: 102400 })
  42. }).nullable().optional().openapi({
  43. description: '头像文件信息'
  44. }),
  45. openid: z.string().max(255).nullable().optional().openapi({
  46. example: 'oABCDEFGH123456789',
  47. description: '微信小程序openid'
  48. }),
  49. unionid: z.string().max(255).nullable().optional().openapi({
  50. example: 'unionid123456789',
  51. description: '微信unionid'
  52. }),
  53. registrationSource: z.string().max(20).default('web').openapi({
  54. example: 'miniapp',
  55. description: '注册来源: web, miniapp'
  56. }),
  57. isDisabled: z.nativeEnum(DisabledStatus).default(DisabledStatus.ENABLED).openapi({
  58. example: DisabledStatus.ENABLED,
  59. description: '是否禁用(0:启用,1:禁用)'
  60. }),
  61. isDeleted: z.number().int().min(0).max(1).default(DeleteStatus.NOT_DELETED).openapi({
  62. example: DeleteStatus.NOT_DELETED,
  63. description: '是否删除(0:未删除,1:已删除)'
  64. }),
  65. roles: z.array(RoleSchemaMt).optional().openapi({
  66. example: [
  67. {
  68. id: 1,
  69. tenantId: 1,
  70. name: 'admin',
  71. description: '管理员',
  72. permissions: ['user:create'],
  73. createdAt: new Date(),
  74. updatedAt: new Date()
  75. }
  76. ],
  77. description: '用户角色列表'
  78. }),
  79. createdAt: z.coerce.date().openapi({ description: '创建时间' }),
  80. updatedAt: z.coerce.date().openapi({ description: '更新时间' })
  81. });
  82. // 多租户创建用户请求 schema
  83. export const CreateUserDtoMt = z.object({
  84. username: z.string().min(3, '用户名至少3个字符').max(255, '用户名最多255个字符').openapi({
  85. example: 'admin',
  86. description: '用户名,3-255个字符'
  87. }),
  88. password: z.string().min(6, '密码至少6位').max(255, '密码最多255位').openapi({
  89. example: 'password123',
  90. description: '密码,最少6位'
  91. }),
  92. phone: z.string().max(255, '手机号最多255个字符').nullable().optional().openapi({
  93. example: '13800138000',
  94. description: '手机号'
  95. }),
  96. email: z.email('请输入正确的邮箱格式').max(255, '邮箱最多255个字符').nullable().optional().openapi({
  97. example: 'user@example.com',
  98. description: '邮箱'
  99. }),
  100. nickname: z.string().max(255, '昵称最多255个字符').nullable().optional().openapi({
  101. example: '昵称',
  102. description: '用户昵称'
  103. }),
  104. name: z.string().max(255, '姓名最多255个字符').nullable().optional().openapi({
  105. example: '张三',
  106. description: '真实姓名'
  107. }),
  108. avatarFileId: z.number().int().positive().nullable().optional().openapi({
  109. example: 1,
  110. description: '头像文件ID'
  111. }),
  112. isDisabled: z.number().int().min(0, '状态值只能是0或1').max(1, '状态值只能是0或1').default(DisabledStatus.ENABLED).optional().openapi({
  113. example: DisabledStatus.ENABLED,
  114. description: '是否禁用(0:启用,1:禁用)'
  115. })
  116. });
  117. // 多租户更新用户请求 schema
  118. export const UpdateUserDtoMt = z.object({
  119. username: z.string().min(3, '用户名至少3个字符').max(255, '用户名最多255个字符').optional().openapi({
  120. example: 'admin',
  121. description: '用户名,3-255个字符'
  122. }),
  123. password: z.string().min(6, '密码至少6位').max(255, '密码最多255位').optional().openapi({
  124. example: 'password123',
  125. description: '密码,最少6位'
  126. }),
  127. phone: z.string().max(255, '手机号最多255个字符').nullable().optional().openapi({
  128. example: '13800138000',
  129. description: '手机号'
  130. }),
  131. email: z.email('请输入正确的邮箱格式').max(255, '邮箱最多255个字符').nullable().optional().openapi({
  132. example: 'user@example.com',
  133. description: '邮箱'
  134. }),
  135. nickname: z.string().max(255, '昵称最多255个字符').nullable().optional().openapi({
  136. example: '昵称',
  137. description: '用户昵称'
  138. }),
  139. name: z.string().max(255, '姓名最多255个字符').nullable().optional().openapi({
  140. example: '张三',
  141. description: '真实姓名'
  142. }),
  143. avatarFileId: z.number().int().positive().nullable().optional().openapi({
  144. example: 1,
  145. description: '头像文件ID'
  146. }),
  147. isDisabled: z.number().int().min(0, '状态值只能是0或1').max(1, '状态值只能是0或1').optional().openapi({
  148. example: DisabledStatus.ENABLED,
  149. description: '是否禁用(0:启用,1:禁用)'
  150. })
  151. });
  152. // 多租户用户列表响应 schema
  153. export const UserListResponseMt = z.object({
  154. data: z.array(UserSchemaMt.omit({ password: true })),
  155. pagination: z.object({
  156. total: z.number().openapi({
  157. example: 100,
  158. description: '总记录数'
  159. }),
  160. current: z.number().openapi({
  161. example: 1,
  162. description: '当前页码'
  163. }),
  164. pageSize: z.number().openapi({
  165. example: 10,
  166. description: '每页数量'
  167. })
  168. })
  169. });
  170. // 多租户单个用户查询响应 schema
  171. export const UserResponseSchemaMt = UserSchemaMt.omit({password:true})
  172. // 多租户类型导出
  173. export type UserMt = z.infer<typeof UserSchemaMt>;
  174. export type CreateUserRequestMt = z.infer<typeof CreateUserDtoMt>;
  175. export type UpdateUserRequestMt = z.infer<typeof UpdateUserDtoMt>;
  176. export type UserListResponseTypeMt = z.infer<typeof UserListResponseMt>;