package firstrechargereward import ( "context" "strings" "chatapp3-golang/internal/model" ) // PageGrantRecords returns admin-facing first recharge reward grant records. func (s *Service) PageGrantRecords( ctx context.Context, sysOrigin string, status string, userID int64, cursor int, limit int, ) (*GrantRecordPageResponse, error) { sysOrigin = s.normalizeSysOrigin(sysOrigin) status = strings.ToUpper(strings.TrimSpace(status)) cursor, limit = NormalizePage(cursor, limit) query := s.db.WithContext(ctx).Model(&model.FirstRechargeRewardGrantRecord{}). Where("sys_origin = ?", sysOrigin) if status != "" { query = query.Where("status = ?", status) } if userID > 0 { query = query.Where("user_id = ?", userID) } var total int64 if err := query.Count(&total).Error; err != nil { return nil, err } var rows []model.FirstRechargeRewardGrantRecord if err := query. Order("create_time desc"). Offset((cursor - 1) * limit). Limit(limit). Find(&rows).Error; err != nil { return nil, err } rewardItems := s.loadRewardItemsForRecords(ctx, rows) views := make([]GrantRecordView, 0, len(rows)) for _, row := range rows { views = append(views, grantRecordViewFromModel(row, rewardItems[row.RewardGroupID])) } return &GrantRecordPageResponse{ Records: views, Total: total, Current: cursor, Size: limit, }, nil } func (s *Service) loadRewardItemsForRecords(ctx context.Context, rows []model.FirstRechargeRewardGrantRecord) map[int64][]RewardItem { levels := make([]levelSnapshot, 0, len(rows)) seen := make(map[int64]struct{}) for _, row := range rows { if row.RewardGroupID <= 0 { continue } if _, exists := seen[row.RewardGroupID]; exists { continue } seen[row.RewardGroupID] = struct{}{} levels = append(levels, levelSnapshot{ RewardGroupID: row.RewardGroupID, }) } return s.loadRewardItemsMap(ctx, levels) } func grantRecordViewFromModel(row model.FirstRechargeRewardGrantRecord, rewardItems []RewardItem) GrantRecordView { return GrantRecordView{ ID: row.ID, EventID: row.EventID, UserID: row.UserID, Account: row.Account, UserAvatar: row.UserAvatar, UserNickname: row.UserNickname, CountryCode: row.CountryCode, CountryName: row.CountryName, SysOrigin: row.SysOrigin, RechargeAmount: formatAmountCents(row.RechargeAmountCents), RechargeAmountCents: row.RechargeAmountCents, RechargeThreshold: formatAmountCents(row.RechargeThresholdCents), RechargeThresholdCents: row.RechargeThresholdCents, Level: row.Level, PayPlatform: row.PayPlatform, PaymentMethod: row.PaymentMethod, SourceOrderID: row.SourceOrderID, RewardGroupID: row.RewardGroupID, RewardGroupName: row.RewardGroupName, RewardItems: rewardItems, Status: row.Status, RewardGroupStatus: row.RewardGroupStatus, RetryCount: row.RetryCount, LastError: row.LastError, EventTime: formatDateTime(row.EventTime), SentAt: formatPtrDateTime(row.SentAt), CreateTime: formatDateTime(row.CreateTime), UpdateTime: formatDateTime(row.UpdateTime), } }