package postgres import ( "context" "errors" "fmt" "time" "photography-backend/internal/model/entity" "photography-backend/internal/repository/interfaces" "go.uber.org/zap" "gorm.io/gorm" ) // userRepositoryImpl 用户仓储实现 type userRepositoryImpl struct { db *gorm.DB logger *zap.Logger } // NewUserRepository 创建用户仓储实现 func NewUserRepository(db *gorm.DB, logger *zap.Logger) interfaces.UserRepository { return &userRepositoryImpl{ db: db, logger: logger, } } // Create 创建用户 func (r *userRepositoryImpl) Create(ctx context.Context, user *entity.User) error { return r.db.WithContext(ctx).Create(user).Error } // GetByID 根据ID获取用户 func (r *userRepositoryImpl) GetByID(ctx context.Context, id uint) (*entity.User, error) { var user entity.User err := r.db.WithContext(ctx).First(&user, id).Error if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, errors.New("user not found") } return nil, err } return &user, nil } // GetByEmail 根据邮箱获取用户 func (r *userRepositoryImpl) GetByEmail(ctx context.Context, email string) (*entity.User, error) { var user entity.User err := r.db.WithContext(ctx).Where("email = ?", email).First(&user).Error if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, errors.New("user not found") } return nil, err } return &user, nil } // GetByUsername 根据用户名获取用户 func (r *userRepositoryImpl) GetByUsername(ctx context.Context, username string) (*entity.User, error) { var user entity.User err := r.db.WithContext(ctx).Where("username = ?", username).First(&user).Error if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, errors.New("user not found") } return nil, err } return &user, nil } // GetByEmailOrUsername 根据邮箱或用户名获取用户 func (r *userRepositoryImpl) GetByEmailOrUsername(ctx context.Context, emailOrUsername string) (*entity.User, error) { var user entity.User err := r.db.WithContext(ctx). Where("email = ? OR username = ?", emailOrUsername, emailOrUsername). First(&user).Error if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, errors.New("user not found") } return nil, err } return &user, nil } // Update 更新用户 func (r *userRepositoryImpl) Update(ctx context.Context, user *entity.User) error { return r.db.WithContext(ctx).Save(user).Error } // Delete 删除用户 func (r *userRepositoryImpl) Delete(ctx context.Context, id uint) error { return r.db.WithContext(ctx).Delete(&entity.User{}, id).Error } // List 获取用户列表 func (r *userRepositoryImpl) List(ctx context.Context, params *entity.UserListParams) ([]*entity.User, int64, error) { var users []*entity.User var total int64 query := r.db.WithContext(ctx).Model(&entity.User{}) // 应用过滤条件 if params.Role != nil { query = query.Where("role = ?", *params.Role) } if params.Status != nil { query = query.Where("status = ?", *params.Status) } if params.Search != "" { query = query.Where("username ILIKE ? OR email ILIKE ? OR first_name ILIKE ? OR last_name ILIKE ?", "%"+params.Search+"%", "%"+params.Search+"%", "%"+params.Search+"%", "%"+params.Search+"%") } if params.CreatedFrom != nil { query = query.Where("created_at >= ?", *params.CreatedFrom) } if params.CreatedTo != nil { query = query.Where("created_at <= ?", *params.CreatedTo) } if params.LastLoginFrom != nil { query = query.Where("last_login_at >= ?", *params.LastLoginFrom) } if params.LastLoginTo != nil { query = query.Where("last_login_at <= ?", *params.LastLoginTo) } // 获取总数 if err := query.Count(&total).Error; err != nil { return nil, 0, err } // 应用排序 orderBy := "created_at DESC" if params.Sort != "" { order := "ASC" if params.Order == "desc" { order = "DESC" } orderBy = fmt.Sprintf("%s %s", params.Sort, order) } query = query.Order(orderBy) // 应用分页 if params.Page > 0 && params.Limit > 0 { offset := (params.Page - 1) * params.Limit query = query.Offset(offset).Limit(params.Limit) } // 查询数据 if err := query.Find(&users).Error; err != nil { return nil, 0, err } return users, total, nil } // ListByRole 根据角色获取用户列表 func (r *userRepositoryImpl) ListByRole(ctx context.Context, role entity.UserRole, params *entity.UserListParams) ([]*entity.User, int64, error) { if params == nil { params = &entity.UserListParams{} } params.Role = &role return r.List(ctx, params) } // ListByStatus 根据状态获取用户列表 func (r *userRepositoryImpl) ListByStatus(ctx context.Context, status entity.UserStatus, params *entity.UserListParams) ([]*entity.User, int64, error) { if params == nil { params = &entity.UserListParams{} } params.Status = &status return r.List(ctx, params) } // SearchUsers 搜索用户 func (r *userRepositoryImpl) SearchUsers(ctx context.Context, keyword string, params *entity.UserListParams) ([]*entity.User, int64, error) { if params == nil { params = &entity.UserListParams{} } params.Search = keyword return r.List(ctx, params) } // Count 统计用户总数 func (r *userRepositoryImpl) Count(ctx context.Context) (int64, error) { var count int64 err := r.db.WithContext(ctx).Model(&entity.User{}).Count(&count).Error return count, err } // CountByRole 根据角色统计用户数 func (r *userRepositoryImpl) CountByRole(ctx context.Context, role entity.UserRole) (int64, error) { var count int64 err := r.db.WithContext(ctx).Model(&entity.User{}). Where("role = ?", role).Count(&count).Error return count, err } // CountByStatus 根据状态统计用户数 func (r *userRepositoryImpl) CountByStatus(ctx context.Context, status entity.UserStatus) (int64, error) { var count int64 err := r.db.WithContext(ctx).Model(&entity.User{}). Where("status = ?", status).Count(&count).Error return count, err } // CountActiveUsers 统计活跃用户数 func (r *userRepositoryImpl) CountActiveUsers(ctx context.Context) (int64, error) { return r.CountByStatus(ctx, entity.UserStatusActive) } // UpdateStatus 更新用户状态 func (r *userRepositoryImpl) UpdateStatus(ctx context.Context, id uint, status entity.UserStatus) error { return r.db.WithContext(ctx).Model(&entity.User{}). Where("id = ?", id). Update("status", status).Error } // UpdateLastLogin 更新最后登录时间 func (r *userRepositoryImpl) UpdateLastLogin(ctx context.Context, id uint) error { now := time.Now() return r.db.WithContext(ctx).Model(&entity.User{}). Where("id = ?", id). Update("last_login_at", now).Error } // UpdatePassword 更新密码 func (r *userRepositoryImpl) UpdatePassword(ctx context.Context, id uint, hashedPassword string) error { return r.db.WithContext(ctx).Model(&entity.User{}). Where("id = ?", id). Update("password", hashedPassword).Error } // SoftDelete 软删除用户 func (r *userRepositoryImpl) SoftDelete(ctx context.Context, id uint) error { return r.db.WithContext(ctx).Delete(&entity.User{}, id).Error } // Restore 恢复软删除用户 func (r *userRepositoryImpl) Restore(ctx context.Context, id uint) error { return r.db.WithContext(ctx).Unscoped().Model(&entity.User{}). Where("id = ?", id). Update("deleted_at", nil).Error } // BatchUpdateStatus 批量更新用户状态 func (r *userRepositoryImpl) BatchUpdateStatus(ctx context.Context, ids []uint, status entity.UserStatus) error { if len(ids) == 0 { return nil } return r.db.WithContext(ctx).Model(&entity.User{}). Where("id IN ?", ids). Update("status", status).Error } // BatchDelete 批量删除用户 func (r *userRepositoryImpl) BatchDelete(ctx context.Context, ids []uint) error { if len(ids) == 0 { return nil } return r.db.WithContext(ctx).Delete(&entity.User{}, ids).Error } // ValidateEmailUnique 验证邮箱唯一性 func (r *userRepositoryImpl) ValidateEmailUnique(ctx context.Context, email string, excludeID uint) error { var count int64 query := r.db.WithContext(ctx).Model(&entity.User{}).Where("email = ?", email) if excludeID > 0 { query = query.Where("id != ?", excludeID) } if err := query.Count(&count).Error; err != nil { return err } if count > 0 { return errors.New("email already exists") } return nil } // ValidateUsernameUnique 验证用户名唯一性 func (r *userRepositoryImpl) ValidateUsernameUnique(ctx context.Context, username string, excludeID uint) error { var count int64 query := r.db.WithContext(ctx).Model(&entity.User{}).Where("username = ?", username) if excludeID > 0 { query = query.Where("id != ?", excludeID) } if err := query.Count(&count).Error; err != nil { return err } if count > 0 { return errors.New("username already exists") } return nil } // GetUserPhotos 获取用户照片 func (r *userRepositoryImpl) GetUserPhotos(ctx context.Context, userID uint, params *entity.PhotoListParams) ([]*entity.Photo, int64, error) { var photos []*entity.Photo var total int64 query := r.db.WithContext(ctx).Model(&entity.Photo{}).Where("user_id = ?", userID) // 应用过滤条件 if params != nil { if params.Status != nil { query = query.Where("status = ?", *params.Status) } if params.CategoryID != nil { query = query.Joins("JOIN photo_categories ON photos.id = photo_categories.photo_id"). Where("photo_categories.category_id = ?", *params.CategoryID) } if params.TagID != nil { query = query.Joins("JOIN photo_tags ON photos.id = photo_tags.photo_id"). Where("photo_tags.tag_id = ?", *params.TagID) } if params.DateFrom != nil { query = query.Where("taken_at >= ?", *params.DateFrom) } if params.DateTo != nil { query = query.Where("taken_at <= ?", *params.DateTo) } if params.Search != "" { query = query.Where("title ILIKE ? OR description ILIKE ?", "%"+params.Search+"%", "%"+params.Search+"%") } } // 获取总数 if err := query.Count(&total).Error; err != nil { return nil, 0, err } // 应用排序和分页 if params != nil { orderBy := "created_at DESC" if params.Sort != "" { order := "ASC" if params.Order == "desc" { order = "DESC" } orderBy = fmt.Sprintf("%s %s", params.Sort, order) } query = query.Order(orderBy) if params.Page > 0 && params.Limit > 0 { offset := (params.Page - 1) * params.Limit query = query.Offset(offset).Limit(params.Limit) } } // 预加载关联数据 query = query.Preload("Categories").Preload("Tags") // 查询数据 if err := query.Find(&photos).Error; err != nil { return nil, 0, err } return photos, total, nil } // GetUserStats 获取用户统计信息 func (r *userRepositoryImpl) GetUserStats(ctx context.Context, userID uint) (*entity.UserStats, error) { var stats entity.UserStats // 照片统计 var photoCount int64 if err := r.db.WithContext(ctx).Model(&entity.Photo{}). Where("user_id = ?", userID).Count(&photoCount).Error; err != nil { return nil, err } stats.PhotoCount = photoCount // 按状态统计照片 for _, status := range []entity.PhotoStatus{ entity.PhotoStatusActive, entity.PhotoStatusDraft, entity.PhotoStatusArchived, } { var count int64 if err := r.db.WithContext(ctx).Model(&entity.Photo{}). Where("user_id = ? AND status = ?", userID, status). Count(&count).Error; err != nil { return nil, err } switch status { case entity.PhotoStatusActive: stats.PublishedPhotos = count case entity.PhotoStatusDraft: stats.DraftPhotos = count case entity.PhotoStatusArchived: stats.ArchivedPhotos = count } } // 总浏览数 var totalViews int64 if err := r.db.WithContext(ctx).Model(&entity.Photo{}). Where("user_id = ?", userID). Select("COALESCE(SUM(view_count), 0)").Row().Scan(&totalViews); err != nil { return nil, err } stats.TotalViews = totalViews // 总下载数 var totalDownloads int64 if err := r.db.WithContext(ctx).Model(&entity.Photo{}). Where("user_id = ?", userID). Select("COALESCE(SUM(download_count), 0)").Row().Scan(&totalDownloads); err != nil { return nil, err } stats.TotalDownloads = totalDownloads // 存储空间使用 var storageUsed int64 if err := r.db.WithContext(ctx).Model(&entity.Photo{}). Where("user_id = ?", userID). Select("COALESCE(SUM(file_size), 0)").Row().Scan(&storageUsed); err != nil { return nil, err } stats.StorageUsed = storageUsed // 本月新增照片 now := time.Now() startOfMonth := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) endOfMonth := startOfMonth.AddDate(0, 1, 0).Add(-time.Nanosecond) var monthlyPhotos int64 if err := r.db.WithContext(ctx).Model(&entity.Photo{}). Where("user_id = ? AND created_at >= ? AND created_at <= ?", userID, startOfMonth, endOfMonth). Count(&monthlyPhotos).Error; err != nil { return nil, err } stats.MonthlyPhotos = monthlyPhotos return &stats, nil } // GetAllStats 获取全部用户统计信息 func (r *userRepositoryImpl) GetAllStats(ctx context.Context) (*entity.UserGlobalStats, error) { var stats entity.UserGlobalStats // 总用户数 if total, err := r.Count(ctx); err != nil { return nil, err } else { stats.Total = total } // 活跃用户数 if active, err := r.CountActiveUsers(ctx); err != nil { return nil, err } else { stats.Active = active } // 按角色统计 for _, role := range []entity.UserRole{ entity.UserRoleAdmin, entity.UserRoleEditor, entity.UserRoleUser, } { if count, err := r.CountByRole(ctx, role); err != nil { return nil, err } else { switch role { case entity.UserRoleAdmin: stats.Admins = count case entity.UserRoleEditor: stats.Editors = count case entity.UserRoleUser: stats.Users = count } } } // 本月新注册用户 now := time.Now() startOfMonth := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) endOfMonth := startOfMonth.AddDate(0, 1, 0).Add(-time.Nanosecond) var monthlyUsers int64 if err := r.db.WithContext(ctx).Model(&entity.User{}). Where("created_at >= ? AND created_at <= ?", startOfMonth, endOfMonth). Count(&monthlyUsers).Error; err != nil { return nil, err } stats.MonthlyRegistrations = monthlyUsers return &stats, nil }