202 lines
5.5 KiB
Go
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
|
|
}
|