user.entity.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import { Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable, CreateDateColumn, UpdateDateColumn, OneToMany } from 'typeorm';
  2. import { Role, RoleSchema } from './role.entity';
  3. import { z } from '@hono/zod-openapi';
  4. import { DeleteStatus, DisabledStatus } from '@/share/types';
  5. import { FollowEntity } from '../follows/follow.entity';
  6. @Entity({ name: 'users' })
  7. export class UserEntity {
  8. @PrimaryGeneratedColumn({ unsigned: true, comment: '用户ID' })
  9. id!: number;
  10. @Column({ name: 'username', type: 'varchar', length: 255, unique: true, comment: '用户名' })
  11. username!: string;
  12. @Column({ name: 'password', type: 'varchar', length: 255, comment: '密码' })
  13. password!: string;
  14. @Column({ name: 'phone', type: 'varchar', length: 255, nullable: true, comment: '手机号' })
  15. phone!: string | null;
  16. @Column({ name: 'email', type: 'varchar', length: 255, nullable: true, comment: '邮箱' })
  17. email!: string | null;
  18. @Column({ name: 'nickname', type: 'varchar', length: 255, nullable: true, comment: '昵称' })
  19. nickname!: string | null;
  20. @Column({ name: 'name', type: 'varchar', length: 255, nullable: true, comment: '真实姓名' })
  21. name!: string | null;
  22. @Column({ name: 'avatar', type: 'varchar', length: 255, nullable: true, comment: '头像' })
  23. avatar!: string | null;
  24. @Column({ name: 'bio', type: 'text', nullable: true, comment: '个人简介' })
  25. bio!: string | null;
  26. @Column({ name: 'location', type: 'varchar', length: 255, nullable: true, comment: '位置' })
  27. location!: string | null;
  28. @Column({ name: 'website', type: 'varchar', length: 255, nullable: true, comment: '个人网站' })
  29. website!: string | null;
  30. @Column({ name: 'is_disabled', type: 'int', default: DisabledStatus.ENABLED, comment: '是否禁用(0:启用,1:禁用)' })
  31. isDisabled!: DisabledStatus;
  32. @Column({ name: 'is_deleted', type: 'int', default: DeleteStatus.NOT_DELETED, comment: '是否删除(0:未删除,1:已删除)' })
  33. isDeleted!: DeleteStatus;
  34. @ManyToMany(() => Role)
  35. @JoinTable()
  36. roles!: Role[];
  37. @OneToMany(() => FollowEntity, follow => follow.follower)
  38. following!: FollowEntity[];
  39. @OneToMany(() => FollowEntity, follow => follow.following)
  40. followers!: FollowEntity[];
  41. @CreateDateColumn({ name: 'created_at', type: 'timestamp' })
  42. createdAt!: Date;
  43. @UpdateDateColumn({ name: 'updated_at', type: 'timestamp' })
  44. updatedAt!: Date;
  45. constructor(partial?: Partial<UserEntity>) {
  46. Object.assign(this, partial);
  47. }
  48. get followerCount(): number {
  49. return this.followers?.length || 0;
  50. }
  51. get followingCount(): number {
  52. return this.following?.length || 0;
  53. }
  54. }
  55. export const UserSchema = z.object({
  56. id: z.number().int().positive().openapi({ description: '用户ID' }),
  57. username: z.string().min(3).max(255).openapi({
  58. example: 'admin',
  59. description: '用户名,3-255个字符'
  60. }),
  61. password: z.string().min(6).max(255).openapi({
  62. example: 'password123',
  63. description: '密码,最少6位'
  64. }),
  65. phone: z.string().max(255).nullable().openapi({
  66. example: '13800138000',
  67. description: '手机号'
  68. }),
  69. email: z.string().email().max(255).nullable().openapi({
  70. example: 'user@example.com',
  71. description: '邮箱'
  72. }),
  73. nickname: z.string().max(255).nullable().openapi({
  74. example: '昵称',
  75. description: '用户昵称'
  76. }),
  77. name: z.string().max(255).nullable().openapi({
  78. example: '张三',
  79. description: '真实姓名'
  80. }),
  81. avatar: z.string().max(255).nullable().openapi({
  82. example: 'https://example.com/avatar.jpg',
  83. description: '用户头像'
  84. }),
  85. bio: z.string().nullable().openapi({
  86. example: '热爱技术的开发者',
  87. description: '个人简介'
  88. }),
  89. location: z.string().max(255).nullable().openapi({
  90. example: '北京',
  91. description: '位置'
  92. }),
  93. website: z.string().url().nullable().openapi({
  94. example: 'https://example.com',
  95. description: '个人网站'
  96. }),
  97. isDisabled: z.number().int().min(0).max(1).default(DisabledStatus.ENABLED).openapi({
  98. example: DisabledStatus.ENABLED,
  99. description: '是否禁用(0:启用,1:禁用)'
  100. }),
  101. isDeleted: z.number().int().min(0).max(1).default(DeleteStatus.NOT_DELETED).openapi({
  102. example: DeleteStatus.NOT_DELETED,
  103. description: '是否删除(0:未删除,1:已删除)'
  104. }),
  105. roles: z.array(RoleSchema).optional().openapi({
  106. example: [
  107. { id: 1, name: 'admin',description:'管理员', permissions: ['user:create'] ,createdAt: new Date(), updatedAt: new Date() }
  108. ],
  109. description: '用户角色列表'
  110. }),
  111. followerCount: z.number().int().nonnegative().openapi({
  112. description: '关注者数量',
  113. example: 100
  114. }),
  115. followingCount: z.number().int().nonnegative().openapi({
  116. description: '关注的用户数量',
  117. example: 50
  118. }),
  119. createdAt: z.date().openapi({ description: '创建时间' }),
  120. updatedAt: z.date().openapi({ description: '更新时间' })
  121. });