user.entity.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  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 isFollowing(): boolean {
  49. return false;
  50. }
  51. get followerCount(): number {
  52. return this.followers?.length || 0;
  53. }
  54. get followingCount(): number {
  55. return this.following?.length || 0;
  56. }
  57. }
  58. export const UserSchema = z.object({
  59. id: z.number().int().positive().openapi({ description: '用户ID' }),
  60. username: z.string().min(3).max(255).openapi({
  61. example: 'admin',
  62. description: '用户名,3-255个字符'
  63. }),
  64. password: z.string().min(6).max(255).openapi({
  65. example: 'password123',
  66. description: '密码,最少6位'
  67. }),
  68. phone: z.string().max(255).nullable().openapi({
  69. example: '13800138000',
  70. description: '手机号'
  71. }),
  72. email: z.string().email().max(255).nullable().openapi({
  73. example: 'user@example.com',
  74. description: '邮箱'
  75. }),
  76. nickname: z.string().max(255).nullable().openapi({
  77. example: '昵称',
  78. description: '用户昵称'
  79. }),
  80. name: z.string().max(255).nullable().openapi({
  81. example: '张三',
  82. description: '真实姓名'
  83. }),
  84. avatar: z.string().max(255).nullable().openapi({
  85. example: 'https://example.com/avatar.jpg',
  86. description: '用户头像'
  87. }),
  88. bio: z.string().nullable().openapi({
  89. example: '热爱技术的开发者',
  90. description: '个人简介'
  91. }),
  92. location: z.string().max(255).nullable().openapi({
  93. example: '北京',
  94. description: '位置'
  95. }),
  96. website: z.string().url().nullable().openapi({
  97. example: 'https://example.com',
  98. description: '个人网站'
  99. }),
  100. isDisabled: z.number().int().min(0).max(1).default(DisabledStatus.ENABLED).openapi({
  101. example: DisabledStatus.ENABLED,
  102. description: '是否禁用(0:启用,1:禁用)'
  103. }),
  104. isDeleted: z.number().int().min(0).max(1).default(DeleteStatus.NOT_DELETED).openapi({
  105. example: DeleteStatus.NOT_DELETED,
  106. description: '是否删除(0:未删除,1:已删除)'
  107. }),
  108. roles: z.array(RoleSchema).optional().openapi({
  109. example: [
  110. { id: 1, name: 'admin',description:'管理员', permissions: ['user:create'] ,createdAt: new Date(), updatedAt: new Date() }
  111. ],
  112. description: '用户角色列表'
  113. }),
  114. followerCount: z.number().int().nonnegative().openapi({
  115. description: '关注者数量',
  116. example: 100
  117. }),
  118. followingCount: z.number().int().nonnegative().openapi({
  119. description: '关注的用户数量',
  120. example: 50
  121. }),
  122. isFollowing: z.boolean().openapi({
  123. description: '当前用户是否关注该用户',
  124. example: false
  125. }),
  126. createdAt: z.date().openapi({ description: '创建时间' }),
  127. updatedAt: z.date().openapi({ description: '更新时间' }),
  128. });