package entities import ( "fmt" "regexp" "time" "github.com/google/uuid" "golang.org/x/crypto/bcrypt" "gorm.io/gorm" ) // UserType 用户类型枚举 type UserType string const ( UserTypeNormal UserType = "user" // 普通用户 UserTypeAdmin UserType = "admin" // 管理员 ) // User 用户实体 // 系统用户的核心信息,提供基础的账户管理功能 // 支持手机号登录,密码加密存储,实现Entity接口便于统一管理 type User struct { // 基础标识 ID string `gorm:"primaryKey;type:varchar(36)" json:"id" comment:"用户唯一标识"` Phone string `gorm:"uniqueIndex;type:varchar(20);not null" json:"phone" comment:"手机号码(登录账号)"` Password string `gorm:"type:varchar(255);not null" json:"-" comment:"登录密码(加密存储,不返回前端)"` // 用户类型和基本信息 UserType string `gorm:"type:varchar(20);not null;default:'user'" json:"user_type" comment:"用户类型(user/admin)"` Username string `gorm:"type:varchar(100)" json:"username" comment:"用户名(管理员专用)"` // 管理员特有字段 Active bool `gorm:"default:true" json:"is_active" comment:"账户是否激活"` LastLoginAt *time.Time `json:"last_login_at" comment:"最后登录时间"` LoginCount int `gorm:"default:0" json:"login_count" comment:"登录次数统计"` Permissions string `gorm:"type:text" json:"permissions" comment:"权限列表(JSON格式存储)"` // 时间戳字段 CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at" comment:"创建时间"` UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at" comment:"更新时间"` DeletedAt gorm.DeletedAt `gorm:"index" json:"-" comment:"软删除时间"` // 关联关系 EnterpriseInfo *EnterpriseInfo `gorm:"foreignKey:UserID" json:"enterprise_info,omitempty" comment:"企业信息(认证后获得)"` } // BeforeCreate GORM钩子:创建前自动生成UUID func (u *User) BeforeCreate(tx *gorm.DB) error { if u.ID == "" { u.ID = uuid.New().String() } return nil } // 实现 Entity 接口 - 提供统一的实体管理接口 // GetID 获取实体唯一标识 func (u *User) GetID() string { return u.ID } // GetCreatedAt 获取创建时间 func (u *User) GetCreatedAt() time.Time { return u.CreatedAt } // GetUpdatedAt 获取更新时间 func (u *User) GetUpdatedAt() time.Time { return u.UpdatedAt } // Validate 验证用户信息 // 检查用户必填字段是否完整,确保数据的有效性 func (u *User) Validate() error { if u.Phone == "" { return NewValidationError("手机号不能为空") } if u.Password == "" { return NewValidationError("密码不能为空") } // 验证手机号格式 if !u.IsValidPhone() { return NewValidationError("手机号格式无效") } // 验证密码强度 if err := u.validatePasswordStrength(u.Password); err != nil { return err } return nil } // ================ 业务方法 ================ // IsAdmin 检查是否为管理员 func (u *User) IsAdmin() bool { return u.UserType == string(UserTypeAdmin) } // IsNormalUser 检查是否为普通用户 func (u *User) IsNormalUser() bool { return u.UserType == string(UserTypeNormal) } // SetUserType 设置用户类型 func (u *User) SetUserType(userType UserType) { u.UserType = string(userType) } // UpdateLastLoginAt 更新最后登录时间 func (u *User) UpdateLastLoginAt() { now := time.Now() u.LastLoginAt = &now } // IncrementLoginCount 增加登录次数 func (u *User) IncrementLoginCount() { u.LoginCount++ } // Activate 激活用户账户 func (u *User) Activate() { u.Active = true } // Deactivate 停用用户账户 func (u *User) Deactivate() { u.Active = false } // ChangePassword 修改密码 // 验证旧密码,检查新密码强度,更新密码 func (u *User) ChangePassword(oldPassword, newPassword, confirmPassword string) error { // 1. 验证确认密码 if newPassword != confirmPassword { return NewValidationError("新密码和确认新密码不匹配") } // 2. 验证旧密码 if !u.CheckPassword(oldPassword) { return NewValidationError("当前密码错误") } // 3. 验证新密码强度 if err := u.validatePasswordStrength(newPassword); err != nil { return err } // 4. 检查新密码不能与旧密码相同 if u.CheckPassword(newPassword) { return NewValidationError("新密码不能与当前密码相同") } // 5. 更新密码 hashedPassword, err := u.hashPassword(newPassword) if err != nil { return fmt.Errorf("密码加密失败: %w", err) } u.Password = hashedPassword return nil } // CheckPassword 验证密码是否正确 func (u *User) CheckPassword(password string) bool { err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password)) return err == nil } // SetPassword 设置密码(用于注册或重置密码) func (u *User) SetPassword(password string) error { // 验证密码强度 if err := u.validatePasswordStrength(password); err != nil { return err } // 加密密码 hashedPassword, err := u.hashPassword(password) if err != nil { return fmt.Errorf("密码加密失败: %w", err) } u.Password = hashedPassword return nil } // ResetPassword 重置密码(忘记密码时使用) func (u *User) ResetPassword(newPassword, confirmPassword string) error { // 1. 验证确认密码 if newPassword != confirmPassword { return NewValidationError("新密码和确认新密码不匹配") } // 2. 验证新密码强度 if err := u.validatePasswordStrength(newPassword); err != nil { return err } // 3. 更新密码 hashedPassword, err := u.hashPassword(newPassword) if err != nil { return fmt.Errorf("密码加密失败: %w", err) } u.Password = hashedPassword return nil } // CanLogin 检查用户是否可以登录 func (u *User) CanLogin() bool { // 检查用户是否被删除 if !u.DeletedAt.Time.IsZero() { return false } // 检查必要字段是否存在 if u.Phone == "" || u.Password == "" { return false } // 如果是管理员,检查是否激活 if u.IsAdmin() && !u.Active { return false } return true } // IsActive 检查用户是否处于活跃状态 func (u *User) IsActive() bool { return u.DeletedAt.Time.IsZero() } // IsDeleted 检查用户是否已被删除 func (u *User) IsDeleted() bool { return !u.DeletedAt.Time.IsZero() } // ================ 手机号相关方法 ================ // IsValidPhone 验证手机号格式 func (u *User) IsValidPhone() bool { return IsValidPhoneFormat(u.Phone) } // SetPhone 设置手机号 func (u *User) SetPhone(phone string) error { if !IsValidPhoneFormat(phone) { return NewValidationError("手机号格式无效") } u.Phone = phone return nil } // GetMaskedPhone 获取脱敏的手机号 func (u *User) GetMaskedPhone() string { if len(u.Phone) < 7 { return u.Phone } return u.Phone[:3] + "****" + u.Phone[len(u.Phone)-4:] } // ================ 私有方法 ================ // hashPassword 加密密码 func (u *User) hashPassword(password string) (string, error) { hashedBytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { return "", err } return string(hashedBytes), nil } // validatePasswordStrength 验证密码强度 func (u *User) validatePasswordStrength(password string) error { if len(password) < 6 { return NewValidationError("密码长度不能少于6位") } if len(password) > 20 { return NewValidationError("密码长度不能超过20位") } return nil } // IsValidPhoneFormat 验证手机号格式 func IsValidPhoneFormat(phone string) bool { pattern := `^1[3-9]\d{9}$` matched, _ := regexp.MatchString(pattern, phone) return matched } // NewUser 创建新用户 func NewUser(phone, password string) (*User, error) { user := &User{ Phone: phone, UserType: string(UserTypeNormal), // 默认为普通用户 Active: true, } if err := user.SetPassword(password); err != nil { return nil, err } return user, nil } // NewAdminUser 创建新管理员用户 func NewAdminUser(phone, password, username string) (*User, error) { user := &User{ Phone: phone, Username: username, UserType: string(UserTypeAdmin), Active: true, } if err := user.SetPassword(password); err != nil { return nil, err } return user, nil } // TableName 指定数据库表名 func (User) TableName() string { return "users" } // ================ 错误处理 ================ type ValidationError struct { Message string } func (e *ValidationError) Error() string { return e.Message } func NewValidationError(message string) *ValidationError { return &ValidationError{Message: message} } func IsValidationError(err error) bool { _, ok := err.(*ValidationError) return ok } // ================ 缓存相关 ================ type UserCache struct { // 基础标识 ID string `json:"id" comment:"用户唯一标识"` Phone string `json:"phone" comment:"手机号码(登录账号)"` Password string `json:"password" comment:"登录密码(加密存储)"` UserType string `json:"user_type" comment:"用户类型"` Username string `json:"username" comment:"用户名"` Active bool `gorm:"default:true" json:"is_active" comment:"账户是否激活"` LastLoginAt *time.Time `json:"last_login_at" comment:"最后登录时间"` LoginCount int `gorm:"default:0" json:"login_count" comment:"登录次数统计"` Permissions string `gorm:"type:text" json:"permissions" comment:"权限列表(JSON格式存储)"` // 时间戳字段 CreatedAt time.Time `json:"created_at" comment:"创建时间"` UpdatedAt time.Time `json:"updated_at" comment:"更新时间"` DeletedAt gorm.DeletedAt `json:"deleted_at" comment:"软删除时间"` } // ToCache 转换为缓存结构 func (u *User) ToCache() *UserCache { return &UserCache{ ID: u.ID, Phone: u.Phone, Password: u.Password, UserType: u.UserType, Username: u.Username, CreatedAt: u.CreatedAt, UpdatedAt: u.UpdatedAt, DeletedAt: u.DeletedAt, // 补充所有字段 // 管理员特有字段 Active: u.Active, LastLoginAt: u.LastLoginAt, LoginCount: u.LoginCount, Permissions: u.Permissions, } } // FromCache 从缓存结构恢复 func (u *User) FromCache(cache *UserCache) { u.ID = cache.ID u.Phone = cache.Phone u.Password = cache.Password u.UserType = cache.UserType u.Username = cache.Username u.CreatedAt = cache.CreatedAt u.UpdatedAt = cache.UpdatedAt u.DeletedAt = cache.DeletedAt u.Active = cache.Active u.LastLoginAt = cache.LastLoginAt u.LoginCount = cache.LoginCount u.Permissions = cache.Permissions }