Zuncle 3db52af4b6 feat(activity): 重构福利活动并支持统一奖池
对齐福利活动新库表结构,支持商品、道具卡和优惠券统一建奖、开奖与中奖记录。
同时新增福利活动测试命令行工具,便于模拟消费、参与活动并验证完整开奖链路。
2026-04-29 17:21:11 +08:00

70 lines
2.2 KiB
Go

package welfare_activity
import (
"context"
"time"
)
func (s *service) ListJoinableActivitiesForUser(ctx context.Context, userID int64) ([]JoinableActivityItem, error) {
now := time.Now()
var activities []Activity
if err := s.repo.GetDbR().WithContext(ctx).Where("deleted_at IS NULL AND status = ? AND start_time <= ? AND end_time > ? AND draw_time > ?", StatusActive, now, now, now).Order("draw_time ASC, id ASC").Find(&activities).Error; err != nil {
return nil, err
}
if len(activities) == 0 {
return []JoinableActivityItem{}, nil
}
paidByType := map[string]int64{}
periodByType := map[string]string{}
for _, activity := range activities {
if _, ok := paidByType[activity.Type]; ok {
continue
}
start, end, period := periodRange(activity.Type, now)
paid, err := s.sumPaidAmount(ctx, userID, start, end)
if err != nil {
return nil, err
}
paidByType[activity.Type] = paid
periodByType[activity.Type] = period
}
activityIDs := make([]int64, 0, len(activities))
for _, activity := range activities {
activityIDs = append(activityIDs, activity.ID)
}
var participants []Participant
if err := s.repo.GetDbR().WithContext(ctx).Where("user_id = ? AND activity_id IN ?", userID, activityIDs).Find(&participants).Error; err != nil {
return nil, err
}
joinedMap := map[int64]map[string]bool{}
for _, participant := range participants {
if _, ok := joinedMap[participant.ActivityID]; !ok {
joinedMap[participant.ActivityID] = map[string]bool{}
}
joinedMap[participant.ActivityID][participant.PeriodKey] = true
}
items := make([]JoinableActivityItem, 0, len(activities))
for _, activity := range activities {
currentPaid := paidByType[activity.Type]
periodKey := periodByType[activity.Type]
joined := joinedMap[activity.ID][periodKey]
canJoin := !joined && currentPaid >= activity.ThresholdAmount
items = append(items, JoinableActivityItem{
ActivityID: activity.ID,
Title: activity.Title,
Type: activity.Type,
ThresholdAmount: activity.ThresholdAmount,
CurrentPaid: currentPaid,
CanJoin: canJoin,
Joined: joined,
StartTime: activity.StartTime,
EndTime: activity.EndTime,
DrawTime: activity.DrawTime,
})
}
return items, nil
}