2026-04-27 23:27:37 +08:00

202 lines
5.5 KiB
Go

package roomturnoverreward
import (
"context"
"errors"
"net/http"
"sort"
"strings"
"time"
"chatapp3-golang/internal/integration"
"chatapp3-golang/internal/model"
"gorm.io/gorm"
)
type roomTurnoverRewardRankingLevel struct {
Level int
TurnoverThreshold int64
RewardGold int64
Enabled bool
}
// CurrentRoomRanking 返回当前周期的房间流水排行榜,并根据当前配置计算预计命中的最高奖励档。
func (s *Service) CurrentRoomRanking(ctx context.Context, sysOrigin string, limit int) (*RoomTurnoverRewardCurrentRankResponse, error) {
if s.repo.Java == nil {
return nil, NewAppError(http.StatusServiceUnavailable, "java_gateway_unavailable", "java gateway is unavailable")
}
sysOrigin = s.normalizeSysOrigin(sysOrigin)
if limit <= 0 {
limit = 20
}
if limit > 100 {
limit = 100
}
levels, err := s.loadRankingLevels(ctx, sysOrigin)
if err != nil {
return nil, err
}
now := time.Now().In(s.location)
periodStart, periodEnd := s.currentCycleBounds(now)
dateNumber, err := s.currentDateNumber(now)
if err != nil {
return nil, err
}
sourceLimit := limit * 5
if sourceLimit < 100 {
sourceLimit = 100
}
if sourceLimit > 500 {
sourceLimit = 500
}
contributions, err := s.repo.Java.ListCurrentWeekRoomContribution(ctx, sourceLimit)
if err != nil {
return nil, err
}
roomIDs := uniqueRoomIDs(contributions)
roomProfiles, err := s.repo.Java.MapRoomProfiles(ctx, roomIDs)
if err != nil {
return nil, err
}
items := make([]RoomTurnoverRewardCurrentRankItem, 0, limit)
for _, contribution := range contributions {
roomID := int64(contribution.RoomID)
if roomID <= 0 {
continue
}
profile, ok := roomProfiles[roomID]
if !ok {
continue
}
if profileSysOrigin := strings.ToUpper(strings.TrimSpace(profile.SysOrigin)); profileSysOrigin != "" && profileSysOrigin != sysOrigin {
continue
}
turnoverAmount := int64(contribution.ContributionValue)
item := RoomTurnoverRewardCurrentRankItem{
RoomID: roomID,
RoomAccount: profile.RoomAccount,
RoomName: profile.RoomName,
RoomCover: profile.RoomCover,
OwnerUserID: int64(profile.UserID),
CountryCode: profile.CountryCode,
CountryName: profile.CountryName,
TurnoverAmount: turnoverAmount,
DateNumber: contribution.DateNumber,
}
if item.DateNumber == 0 {
item.DateNumber = dateNumber
}
if level, ok := pickHighestRankingLevel(levels, turnoverAmount); ok {
item.MatchedLevel = level.Level
item.TurnoverThreshold = level.TurnoverThreshold
item.ExpectedRewardGold = level.RewardGold
}
items = append(items, item)
}
sort.Slice(items, func(i, j int) bool {
if items[i].TurnoverAmount == items[j].TurnoverAmount {
return items[i].RoomID < items[j].RoomID
}
return items[i].TurnoverAmount > items[j].TurnoverAmount
})
if len(items) > limit {
items = items[:limit]
}
for index := range items {
items[index].Rank = index + 1
}
return &RoomTurnoverRewardCurrentRankResponse{
SysOrigin: sysOrigin,
Timezone: s.defaultTimezone(),
CycleKey: s.cycleKey(periodStart),
PeriodStartAt: formatDateTime(periodStart),
PeriodEndAt: formatDateTime(periodEnd),
DateNumber: dateNumber,
Records: items,
}, nil
}
func (s *Service) loadRankingLevels(ctx context.Context, sysOrigin string) ([]roomTurnoverRewardRankingLevel, error) {
var configRow model.RoomTurnoverRewardConfig
err := s.repo.DB.WithContext(ctx).
Where("sys_origin = ?", sysOrigin).
First(&configRow).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return defaultRankingLevels(), nil
}
if err != nil {
return nil, err
}
levels, err := s.loadLevels(ctx, configRow.ID)
if err != nil {
return nil, err
}
result := make([]roomTurnoverRewardRankingLevel, 0, len(levels))
for _, level := range levels {
result = append(result, roomTurnoverRewardRankingLevel{
Level: level.Level,
TurnoverThreshold: level.TurnoverThreshold,
RewardGold: level.RewardGold,
Enabled: level.Enabled,
})
}
return result, nil
}
func defaultRankingLevels() []roomTurnoverRewardRankingLevel {
defaults := defaultLevelPayloads()
result := make([]roomTurnoverRewardRankingLevel, 0, len(defaults))
for _, level := range defaults {
result = append(result, roomTurnoverRewardRankingLevel{
Level: level.Level,
TurnoverThreshold: level.TurnoverThreshold,
RewardGold: level.RewardGold,
Enabled: level.Enabled,
})
}
return result
}
func pickHighestRankingLevel(levels []roomTurnoverRewardRankingLevel, turnoverAmount int64) (roomTurnoverRewardRankingLevel, bool) {
if turnoverAmount <= 0 || len(levels) == 0 {
return roomTurnoverRewardRankingLevel{}, false
}
sort.Slice(levels, func(i, j int) bool {
return levels[i].TurnoverThreshold > levels[j].TurnoverThreshold
})
for _, level := range levels {
if !level.Enabled || level.TurnoverThreshold <= 0 || level.RewardGold <= 0 {
continue
}
if turnoverAmount >= level.TurnoverThreshold {
return level, true
}
}
return roomTurnoverRewardRankingLevel{}, false
}
func uniqueRoomIDs(contributions []integration.RoomContributionActivityCount) []int64 {
result := make([]int64, 0, len(contributions))
seen := make(map[int64]struct{}, len(contributions))
for _, item := range contributions {
roomID := int64(item.RoomID)
if roomID <= 0 {
continue
}
if _, exists := seen[roomID]; exists {
continue
}
seen[roomID] = struct{}{}
result = append(result, roomID)
}
return result
}