93 lines
3.1 KiB
Go

package welfare_activity
import (
"context"
"errors"
"fmt"
"time"
)
func (s *service) Join(ctx context.Context, activityID int64, userID int64) error {
if activityID <= 0 || userID <= 0 {
return errors.New("活动或用户无效")
}
var activity Activity
if err := s.repo.GetDbR().WithContext(ctx).Where("id = ? AND deleted_at IS NULL", activityID).First(&activity).Error; err != nil {
return err
}
now := time.Now()
if !isJoinWindowOpen(activity, now) {
if now.Before(activity.StartTime) {
return errors.New("活动未开始")
}
return errors.New("当前不在活动参与时间内")
}
var existing int64
if err := s.repo.GetDbW().WithContext(ctx).Model(&Participant{}).Where("activity_id = ? AND user_id = ?", activityID, userID).Count(&existing).Error; err != nil {
return err
}
if existing > 0 {
return errors.New("已参与该活动")
}
start, end, period := activityStatsRange(activity)
paid, err := s.sumPaidAmount(ctx, userID, start, end)
if err != nil {
return err
}
if paid < activity.ThresholdAmount {
return fmt.Errorf("未达到参与门槛,还差%d分", activity.ThresholdAmount-paid)
}
participant := &Participant{ActivityID: activityID, UserID: userID, PeriodKey: period, PaidAmountSnapshot: paid}
return s.repo.GetDbW().WithContext(ctx).Create(participant).Error
}
func (s *service) ListParticipants(ctx context.Context, activityID int64, page int, pageSize int) (*ParticipantResponse, error) {
if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 20
}
if pageSize > 100 {
pageSize = 100
}
var total int64
db := s.repo.GetDbR().WithContext(ctx).Table("welfare_activity_participants").Where("activity_id = ?", activityID)
if err := db.Count(&total).Error; err != nil {
return nil, err
}
var list []ParticipantAvatar
err := s.repo.GetDbR().WithContext(ctx).Table("welfare_activity_participants p").
Select("p.user_id, COALESCE(u.nickname, '') AS nickname, COALESCE(u.avatar, '') AS avatar").
Joins("LEFT JOIN users u ON u.id = p.user_id").
Where("p.activity_id = ?", activityID).
Order("p.id DESC").
Offset((page - 1) * pageSize).
Limit(pageSize).
Scan(&list).Error
return &ParticipantResponse{Page: page, PageSize: pageSize, Total: total, List: list}, err
}
func (s *service) sumPaidAmount(ctx context.Context, userID int64, start time.Time, end time.Time) (int64, error) {
var total int64
err := s.repo.GetDbR().WithContext(ctx).Table("orders").
Select("COALESCE(SUM(actual_amount), 0)").
Where("user_id = ? AND status = 2 AND actual_amount > 0", userID).
Where("COALESCE(NULLIF(paid_at, '1970-01-01 00:00:00'), created_at) >= ?", start).
Where("COALESCE(NULLIF(paid_at, '1970-01-01 00:00:00'), created_at) < ?", end).
Scan(&total).Error
return total, err
}
func activityStatsRange(activity Activity) (time.Time, time.Time, string) {
return activity.StartTime, exclusiveEndTime(activity.EndTime), activityPeriodKey(activity)
}
func exclusiveEndTime(end time.Time) time.Time {
return end.Add(time.Second)
}
func activityPeriodKey(activity Activity) string {
return fmt.Sprintf("%016x", uint64(activity.ID))
}