143 lines
4.5 KiB
Go
143 lines
4.5 KiB
Go
package voiceroomrocket
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"chatapp3-golang/internal/integration"
|
|
"chatapp3-golang/internal/model"
|
|
)
|
|
|
|
// GetKingRanking 查询火箭王榜单。
|
|
func (s *Service) GetKingRanking(ctx context.Context, user AuthUser, roomID int64, level int, roundNo int, cursor int, limit int) (*KingResponse, error) {
|
|
if roomID <= 0 {
|
|
return nil, NewAppError(http.StatusBadRequest, "missing_room_id", "roomId is required")
|
|
}
|
|
if level <= 0 || level > defaultMaxLevel {
|
|
return nil, NewAppError(http.StatusBadRequest, "invalid_level", "level must be between 1 and 6")
|
|
}
|
|
cursor, limit = normalizePage(cursor, limit)
|
|
snapshot, err := s.loadConfig(ctx, user.SysOrigin)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
local := resolveLocation(snapshot.Timezone)
|
|
now := time.Now().In(local)
|
|
statusRow, err := s.loadOrInitStatus(ctx, nil, snapshot.SysOrigin, roomID, dayKey(now, local), now)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if roundNo <= 0 {
|
|
roundNo = statusRow.RoundNo
|
|
}
|
|
sourceRoundNo := roundNo
|
|
records, err := s.rankRecords(ctx, snapshot.SysOrigin, roomID, statusRow.DayKey, sourceRoundNo, level, cursor, limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(records) == 0 && roundNo == statusRow.RoundNo && level > statusRow.CurrentLevel && roundNo > 1 {
|
|
sourceRoundNo = roundNo - 1
|
|
records, err = s.rankRecords(ctx, snapshot.SysOrigin, roomID, statusRow.DayKey, sourceRoundNo, level, cursor, limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
resp := &KingResponse{
|
|
RoomID: roomID,
|
|
DayKey: statusRow.DayKey,
|
|
RoundNo: roundNo,
|
|
SourceRoundNo: sourceRoundNo,
|
|
Level: level,
|
|
Records: records,
|
|
}
|
|
if len(records) > 3 {
|
|
resp.Podium = append([]KingRecord(nil), records[:3]...)
|
|
} else {
|
|
resp.Podium = append([]KingRecord(nil), records...)
|
|
}
|
|
if len(records) == 0 {
|
|
resp.EmptyReason = "未达到火箭等级,没有火箭王"
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (s *Service) topKingRecords(ctx context.Context, sysOrigin string, roomID int64, day string, roundNo int, level int, limit int) ([]KingRecord, error) {
|
|
if limit <= 0 {
|
|
limit = 3
|
|
}
|
|
return s.rankRecords(ctx, sysOrigin, roomID, day, roundNo, level, 1, limit)
|
|
}
|
|
|
|
func (s *Service) rankRecords(ctx context.Context, sysOrigin string, roomID int64, day string, roundNo int, level int, cursor int, limit int) ([]KingRecord, error) {
|
|
cursor, limit = normalizePage(cursor, limit)
|
|
var rows []model.VoiceRoomRocketContribution
|
|
if err := s.repo.DB.WithContext(ctx).
|
|
Where("sys_origin = ? AND room_id = ? AND day_key = ? AND round_no = ? AND level = ?", sysOrigin, roomID, day, roundNo, level).
|
|
Order("score_energy DESC, last_contribute_time ASC, user_id ASC").
|
|
Offset((cursor - 1) * limit).
|
|
Limit(limit).
|
|
Find(&rows).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
profiles := s.mapUserProfiles(ctx, contributionUserIDs(rows))
|
|
records := make([]KingRecord, 0, len(rows))
|
|
baseRank := (cursor-1)*limit + 1
|
|
for index, row := range rows {
|
|
profile := profiles[row.UserID]
|
|
record := userProfileToKingRecord(row.UserID, baseRank+index, row.ScoreEnergy, profile)
|
|
if strings.TrimSpace(record.Account) == "" {
|
|
record.Account = strconv.FormatInt(row.UserID, 10)
|
|
}
|
|
if strings.TrimSpace(record.UserNickname) == "" {
|
|
record.UserNickname = record.Account
|
|
}
|
|
records = append(records, record)
|
|
}
|
|
return records, nil
|
|
}
|
|
|
|
func contributionUserIDs(rows []model.VoiceRoomRocketContribution) []int64 {
|
|
result := make([]int64, 0, len(rows))
|
|
seen := map[int64]struct{}{}
|
|
for _, row := range rows {
|
|
if row.UserID <= 0 {
|
|
continue
|
|
}
|
|
if _, ok := seen[row.UserID]; ok {
|
|
continue
|
|
}
|
|
seen[row.UserID] = struct{}{}
|
|
result = append(result, row.UserID)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (s *Service) mapUserProfiles(ctx context.Context, userIDs []int64) map[int64]integration.UserProfile {
|
|
result := make(map[int64]integration.UserProfile, len(userIDs))
|
|
if s.userProfiles == nil {
|
|
return result
|
|
}
|
|
for _, userID := range userIDs {
|
|
profile, err := s.userProfiles.GetUserProfile(ctx, userID)
|
|
if err == nil {
|
|
result[userID] = profile
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func rankRedisKey(sysOrigin string, roomID int64, day string, roundNo int, level int) string {
|
|
return "voice_room:rocket:rank:" + strings.ToUpper(strings.TrimSpace(sysOrigin)) +
|
|
":" + strconv.FormatInt(roomID, 10) +
|
|
":" + day +
|
|
":" + strconv.Itoa(roundNo) +
|
|
":" + strconv.Itoa(level)
|
|
}
|
|
|
|
func roomLockKey(sysOrigin string, roomID int64) string {
|
|
return "voice_room:rocket:lock:" + strings.ToUpper(strings.TrimSpace(sysOrigin)) + ":" + strconv.FormatInt(roomID, 10)
|
|
}
|