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 }