Files
tyapi-server/internal/domains/user/entities/user.go

406 lines
10 KiB
Go
Raw Normal View History

package entities
import (
2025-07-11 21:05:58 +08:00
"fmt"
"regexp"
"time"
2025-07-13 16:36:20 +08:00
"github.com/google/uuid"
2025-07-11 21:05:58 +08:00
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
2025-07-20 20:53:26 +08:00
// UserType 用户类型枚举
type UserType string
const (
UserTypeNormal UserType = "user" // 普通用户
UserTypeAdmin UserType = "admin" // 管理员
)
// User 用户实体
2025-07-11 21:05:58 +08:00
// 系统用户的核心信息,提供基础的账户管理功能
// 支持手机号登录密码加密存储实现Entity接口便于统一管理
type User struct {
2025-07-11 21:05:58 +08:00
// 基础标识
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:"登录密码(加密存储,不返回前端)"`
2025-07-20 20:53:26 +08:00
// 用户类型和基本信息
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格式存储)"`
2025-07-11 21:05:58 +08:00
// 时间戳字段
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:"软删除时间"`
2025-07-13 16:36:20 +08:00
// 关联关系
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
}
2025-07-11 21:05:58 +08:00
// 实现 Entity 接口 - 提供统一的实体管理接口
// GetID 获取实体唯一标识
func (u *User) GetID() string {
return u.ID
}
2025-07-11 21:05:58 +08:00
// GetCreatedAt 获取创建时间
func (u *User) GetCreatedAt() time.Time {
return u.CreatedAt
}
2025-07-11 21:05:58 +08:00
// GetUpdatedAt 获取更新时间
func (u *User) GetUpdatedAt() time.Time {
return u.UpdatedAt
}
2025-07-11 21:05:58 +08:00
// Validate 验证用户信息
// 检查用户必填字段是否完整,确保数据的有效性
func (u *User) Validate() error {
2025-07-02 16:17:59 +08:00
if u.Phone == "" {
return NewValidationError("手机号不能为空")
}
if u.Password == "" {
2025-07-02 16:17:59 +08:00
return NewValidationError("密码不能为空")
}
2025-07-11 21:05:58 +08:00
// 验证手机号格式
if !u.IsValidPhone() {
return NewValidationError("手机号格式无效")
}
// 验证密码强度
if err := u.validatePasswordStrength(u.Password); err != nil {
return err
}
return nil
}
// ================ 业务方法 ================
2025-07-20 20:53:26 +08:00
// 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
}
2025-07-11 21:05:58 +08:00
// 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
}
2025-07-15 13:21:34 +08:00
// 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
}
2025-07-11 21:05:58 +08:00
// CanLogin 检查用户是否可以登录
func (u *User) CanLogin() bool {
// 检查用户是否被删除
if !u.DeletedAt.Time.IsZero() {
return false
}
// 检查必要字段是否存在
if u.Phone == "" || u.Password == "" {
return false
}
2025-07-20 20:53:26 +08:00
// 如果是管理员,检查是否激活
if u.IsAdmin() && !u.Active {
return false
}
2025-07-11 21:05:58 +08:00
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:]
}
2025-07-20 20:53:26 +08:00
// ================ 私有方法 ================
2025-07-11 21:05:58 +08:00
// 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 {
2025-07-20 20:53:26 +08:00
if len(password) < 6 {
return NewValidationError("密码长度不能少于6位")
2025-07-11 21:05:58 +08:00
}
2025-07-20 20:53:26 +08:00
if len(password) > 20 {
return NewValidationError("密码长度不能超过20位")
2025-07-11 21:05:58 +08:00
}
return nil
}
2025-07-20 20:53:26 +08:00
// IsValidPhoneFormat 验证手机号格式
2025-07-11 21:05:58 +08:00
func IsValidPhoneFormat(phone string) bool {
pattern := `^1[3-9]\d{9}$`
matched, _ := regexp.MatchString(pattern, phone)
return matched
}
2025-07-20 20:53:26 +08:00
// NewUser 创建新用户
2025-07-11 21:05:58 +08:00
func NewUser(phone, password string) (*User, error) {
user := &User{
2025-07-20 20:53:26 +08:00
Phone: phone,
UserType: string(UserTypeNormal), // 默认为普通用户
Active: true,
2025-07-11 21:05:58 +08:00
}
2025-07-20 20:53:26 +08:00
if err := user.SetPassword(password); err != nil {
2025-07-11 21:05:58 +08:00
return nil, err
}
2025-07-20 20:53:26 +08:00
return user, nil
}
// NewAdminUser 创建新管理员用户
func NewAdminUser(phone, password, username string) (*User, error) {
user := &User{
Phone: phone,
Username: username,
UserType: string(UserTypeAdmin),
Active: true,
}
2025-07-11 21:05:58 +08:00
if err := user.SetPassword(password); err != nil {
return nil, err
}
return user, nil
}
2025-07-20 20:53:26 +08:00
// TableName 指定数据库表名
func (User) TableName() string {
return "users"
}
2025-07-20 20:53:26 +08:00
// ================ 错误处理 ================
type ValidationError struct {
Message string
}
func (e *ValidationError) Error() string {
return e.Message
}
func NewValidationError(message string) *ValidationError {
return &ValidationError{Message: message}
}
2025-07-11 21:05:58 +08:00
func IsValidationError(err error) bool {
2025-07-20 20:53:26 +08:00
_, ok := err.(*ValidationError)
return ok
2025-07-11 21:05:58 +08:00
}
2025-07-13 16:36:20 +08:00
2025-07-20 20:53:26 +08:00
// ================ 缓存相关 ================
2025-07-13 16:36:20 +08:00
type UserCache struct {
// 基础标识
ID string `json:"id" comment:"用户唯一标识"`
Phone string `json:"phone" comment:"手机号码(登录账号)"`
Password string `json:"password" comment:"登录密码(加密存储)"`
2025-07-20 20:53:26 +08:00
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格式存储)"`
2025-07-13 16:36:20 +08:00
// 时间戳字段
CreatedAt time.Time `json:"created_at" comment:"创建时间"`
UpdatedAt time.Time `json:"updated_at" comment:"更新时间"`
DeletedAt gorm.DeletedAt `json:"deleted_at" comment:"软删除时间"`
}
2025-07-20 20:53:26 +08:00
// ToCache 转换为缓存结构
2025-07-13 16:36:20 +08:00
func (u *User) ToCache() *UserCache {
return &UserCache{
ID: u.ID,
Phone: u.Phone,
Password: u.Password,
2025-07-20 20:53:26 +08:00
UserType: u.UserType,
Username: u.Username,
2025-07-13 16:36:20 +08:00
CreatedAt: u.CreatedAt,
UpdatedAt: u.UpdatedAt,
DeletedAt: u.DeletedAt,
2025-07-20 20:53:26 +08:00
// 补充所有字段
// 管理员特有字段
Active: u.Active,
LastLoginAt: u.LastLoginAt,
LoginCount: u.LoginCount,
Permissions: u.Permissions,
2025-07-13 16:36:20 +08:00
}
}
2025-07-20 20:53:26 +08:00
// FromCache 从缓存结构恢复
2025-07-13 16:36:20 +08:00
func (u *User) FromCache(cache *UserCache) {
u.ID = cache.ID
u.Phone = cache.Phone
u.Password = cache.Password
2025-07-20 20:53:26 +08:00
u.UserType = cache.UserType
u.Username = cache.Username
2025-07-13 16:36:20 +08:00
u.CreatedAt = cache.CreatedAt
u.UpdatedAt = cache.UpdatedAt
u.DeletedAt = cache.DeletedAt
2025-07-20 20:53:26 +08:00
u.Active = cache.Active
u.LastLoginAt = cache.LastLoginAt
u.LoginCount = cache.LoginCount
u.Permissions = cache.Permissions
2025-07-13 16:36:20 +08:00
}