topfans/backend/services/activityService/repository/activity_repository.go
2026-05-20 17:05:02 +08:00

324 lines
9.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package repository
import (
"errors"
"github.com/topfans/backend/pkg/database"
"github.com/topfans/backend/pkg/models"
"gorm.io/gorm"
)
// ActivityRepository Activity仓库接口
type ActivityRepository interface {
// CreateActivity 创建活动
CreateActivity(activity *models.Activity) error
// GetActivityByID 根据ID获取活动
GetActivityByID(id int64) (*models.Activity, error)
// GetActivitiesByStar 根据star_id获取活动列表
GetActivitiesByStar(starID int64, status string, page, pageSize int) ([]*models.Activity, int64, error)
// UpdateActivityProgress 更新活动进度
UpdateActivityProgress(id int64, progress int64) error
// GetActivityItems 获取活动道具列表
GetActivityItems(activityID int64) ([]*models.ActivityItem, error)
// GetActivityItemByType 根据类型获取道具
GetActivityItemByType(activityID int64, itemType string) (*models.ActivityItem, error)
// CreateContribution 创建贡献记录
CreateContribution(contribution *models.ActivityContribution) error
// GetUserStats 获取用户活动统计
GetUserStats(activityID, userID, starID int64) (*models.ActivityUserStats, error)
// UpdateUserStats 更新用户活动统计
UpdateUserStats(stats *models.ActivityUserStats) error
// GetRanking 获取排行榜
GetRanking(activityID, starID int64, page, pageSize int) ([]*models.ActivityUserStats, int64, error)
// GetUserRank 获取用户排名
GetUserRank(userID, activityID, starID int64) (int, error)
// GetLatestContributions 获取最新贡献记录(用于实时显示)
GetLatestContributions(activityID int64, sinceTimestamp int64, sinceID int64, limit int) ([]*models.ActivityContribution, error)
}
// activityRepository Activity仓库实现
type activityRepository struct {
db *gorm.DB
}
// NewActivityRepository 创建Activity仓库实例
func NewActivityRepository() ActivityRepository {
return &activityRepository{
db: database.GetDB(),
}
}
// CreateActivity 创建活动
func (r *activityRepository) CreateActivity(activity *models.Activity) error {
if activity == nil {
return errors.New("activity cannot be nil")
}
return r.db.Create(activity).Error
}
// GetActivityByID 根据ID获取活动
func (r *activityRepository) GetActivityByID(id int64) (*models.Activity, error) {
if id <= 0 {
return nil, errors.New("activity id must be greater than 0")
}
var activity models.Activity
if err := r.db.Preload("Items", "is_active = ?", true).First(&activity, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &activity, nil
}
// GetActivitiesByStar 根据star_id获取活动列表
func (r *activityRepository) GetActivitiesByStar(starID int64, status string, page, pageSize int) ([]*models.Activity, int64, error) {
if starID <= 0 {
return nil, 0, errors.New("star_id must be greater than 0")
}
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 10
}
query := r.db.Model(&models.Activity{}).Where("star_id = ?", starID)
if status != "" {
query = query.Where("status = ?", status)
}
var total int64
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
offset := (page - 1) * pageSize
var activities []*models.Activity
if err := query.Preload("Items", "is_active = ?", true).
Order("start_time DESC").
Offset(offset).
Limit(pageSize).
Find(&activities).Error; err != nil {
return nil, 0, err
}
return activities, total, nil
}
// UpdateActivityProgress 更新活动进度
func (r *activityRepository) UpdateActivityProgress(id int64, progress int64) error {
if id <= 0 {
return errors.New("activity id must be greater than 0")
}
return r.db.Model(&models.Activity{}).
Where("id = ?", id).
Update("current_progress", progress).Error
}
// GetActivityItems 获取活动道具列表
func (r *activityRepository) GetActivityItems(activityID int64) ([]*models.ActivityItem, error) {
if activityID <= 0 {
return nil, errors.New("activity_id must be greater than 0")
}
var items []*models.ActivityItem
if err := r.db.Where("activity_id = ? AND is_active = ?", activityID, true).
Order("sort_order ASC").
Find(&items).Error; err != nil {
return nil, err
}
return items, nil
}
// GetActivityItemByType 根据类型获取道具
func (r *activityRepository) GetActivityItemByType(activityID int64, itemType string) (*models.ActivityItem, error) {
if activityID <= 0 {
return nil, errors.New("activity_id must be greater than 0")
}
if itemType == "" {
return nil, errors.New("item_type cannot be empty")
}
var item models.ActivityItem
if err := r.db.Where("activity_id = ? AND item_type = ? AND is_active = ?", activityID, itemType, true).
First(&item).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &item, nil
}
// CreateContribution 创建贡献记录
func (r *activityRepository) CreateContribution(contribution *models.ActivityContribution) error {
if contribution == nil {
return errors.New("contribution cannot be nil")
}
return r.db.Create(contribution).Error
}
// GetUserStats 获取用户活动统计
func (r *activityRepository) GetUserStats(activityID, userID, starID int64) (*models.ActivityUserStats, error) {
if activityID <= 0 || userID <= 0 || starID <= 0 {
return nil, errors.New("activity_id, user_id, star_id must be greater than 0")
}
var stats models.ActivityUserStats
if err := r.db.Where("activity_id = ? AND user_id = ? AND star_id = ?", activityID, userID, starID).
First(&stats).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &stats, nil
}
// UpdateUserStats 更新用户活动统计
func (r *activityRepository) UpdateUserStats(stats *models.ActivityUserStats) error {
if stats == nil {
return errors.New("stats cannot be nil")
}
// 使用 upsert 逻辑
var existing models.ActivityUserStats
err := r.db.Where("activity_id = ? AND user_id = ? AND star_id = ?",
stats.ActivityID, stats.UserID, stats.StarID).First(&existing).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
// 不存在,创建新记录
return r.db.Create(stats).Error
}
return err
}
// 存在,更新记录
return r.db.Model(&existing).
Updates(map[string]interface{}{
"total_contribution": stats.TotalContribution,
"total_crystal_spent": stats.TotalCrystalSpent,
"total_items": stats.TotalItems,
"last_contribute_at": stats.LastContributeAt,
"updated_at": stats.UpdatedAt,
}).Error
}
// GetRanking 获取排行榜
func (r *activityRepository) GetRanking(activityID, starID int64, page, pageSize int) ([]*models.ActivityUserStats, int64, error) {
if activityID <= 0 {
return nil, 0, errors.New("activity_id must be greater than 0")
}
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 10
}
query := r.db.Model(&models.ActivityUserStats{}).Where("activity_id = ?", activityID)
// 添加 star_id 过滤
if starID > 0 {
query = query.Where("star_id = ?", starID)
}
var total int64
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
offset := (page - 1) * pageSize
var stats []*models.ActivityUserStats
if err := query.Order("total_contribution DESC").
Offset(offset).
Limit(pageSize).
Find(&stats).Error; err != nil {
return nil, 0, err
}
return stats, total, nil
}
// GetUserRank 获取用户排名
func (r *activityRepository) GetUserRank(userID, activityID, starID int64) (int, error) {
if userID <= 0 || activityID <= 0 || starID <= 0 {
return 0, errors.New("user_id, activity_id, star_id must be greater than 0")
}
// 获取用户的贡献值
var userStats models.ActivityUserStats
if err := r.db.Where("activity_id = ? AND user_id = ? AND star_id = ?", activityID, userID, starID).
First(&userStats).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return 0, nil // 用户没有贡献记录
}
return 0, err
}
// 计算排名:统计贡献值大于当前用户的数量
var count int64
if err := r.db.Model(&models.ActivityUserStats{}).
Where("activity_id = ? AND star_id = ? AND total_contribution > ?", activityID, starID, userStats.TotalContribution).
Count(&count).Error; err != nil {
return 0, err
}
return int(count) + 1, nil
}
// GetLatestContributions 获取最新贡献记录(用于实时显示)
func (r *activityRepository) GetLatestContributions(activityID int64, sinceTimestamp int64, sinceID int64, limit int) ([]*models.ActivityContribution, error) {
if activityID <= 0 {
return nil, errors.New("activity_id must be greater than 0")
}
if limit <= 0 {
limit = 5
}
if limit > 20 {
limit = 20 // 最多返回20条
}
query := r.db.Model(&models.ActivityContribution{}).
Where("activity_id = ?", activityID).
Order("created_at DESC, id DESC")
// 如果有 sinceTimestamp 和 sinceID进行分页查询
// 用于增量获取:获取 created_at > sinceTimestamp 或者 (created_at == sinceTimestamp AND id > sinceID) 的记录
if sinceTimestamp > 0 {
query = query.Where("created_at > ? OR (created_at = ? AND id > ?)", sinceTimestamp, sinceTimestamp, sinceID)
}
var contributions []*models.ActivityContribution
if err := query.Limit(limit).Find(&contributions).Error; err != nil {
return nil, err
}
return contributions, nil
}