package registerreward import ( "context" "net/http" "strings" "chatapp3-golang/internal/model" "gorm.io/gorm" ) // registerRewardDailyRecordRow 是后台分页查询时使用的中间结果,补齐了用户展示资料。 type registerRewardDailyRecordRow struct { model.ResidentRegisterRewardLog Account string `gorm:"column:account"` // 用户账号 UserAvatar string `gorm:"column:user_avatar"` // 用户头像 UserNickname string `gorm:"column:user_nickname"` // 用户昵称 CountryCode string `gorm:"column:country_code"` // 国家编码 CountryName string `gorm:"column:country_name"` // 国家名称 } // PageDailyRecords 分页返回指定日期的注册奖励领取记录,供后台查看当日限额使用情况。 func (s *RegisterRewardService) PageDailyRecords( ctx context.Context, sysOrigin string, claimDate string, cursor int, limit int, ) (*RegisterRewardDailyRecordPageResponse, error) { normalizedSysOrigin := strings.ToUpper(strings.TrimSpace(sysOrigin)) if normalizedSysOrigin == "" { return nil, NewAppError(http.StatusBadRequest, "bad_request", "sysOrigin is required") } resolvedClaimDate := normalizeRegisterRewardClaimDate(claimDate) page, size := normalizeRegisterRewardPage(cursor, limit) configRow, err := s.loadRegisterRewardConfig(ctx, normalizedSysOrigin) if err != nil { return nil, err } dailyLimit := int64(0) if configRow != nil { dailyLimit = configRow.DailyLimit } var total int64 if err := s.newDailyRecordBaseQuery(ctx, normalizedSysOrigin, resolvedClaimDate). Count(&total).Error; err != nil { return nil, err } occupiedCount, err := s.countDailyRecordsByGrantMode( ctx, normalizedSysOrigin, resolvedClaimDate, registerRewardGrantModeIssueReward, "", ) if err != nil { return nil, err } issuedCount, err := s.countDailyRecordsByGrantMode( ctx, normalizedSysOrigin, resolvedClaimDate, registerRewardGrantModeIssueReward, registerRewardStatusSuccess, ) if err != nil { return nil, err } successCount, err := s.countDailyRecordsByStatus( ctx, normalizedSysOrigin, resolvedClaimDate, registerRewardStatusSuccess, ) if err != nil { return nil, err } records := make([]RegisterRewardDailyRecordView, 0) if total > 0 { var rows []registerRewardDailyRecordRow if err := s.newDailyRecordBaseQuery(ctx, normalizedSysOrigin, resolvedClaimDate). Select("log.*, user.account, user.user_avatar, user.user_nickname, user.country_code, user.country_name"). Joins("LEFT JOIN user_base_info AS user ON user.id = log.user_id"). Order("log.create_time desc"). Order("log.id desc"). Offset((page - 1) * size). Limit(size). Find(&rows).Error; err != nil { return nil, err } records = make([]RegisterRewardDailyRecordView, 0, len(rows)) for _, row := range rows { records = append(records, toRegisterRewardDailyRecordView(row)) } } resp := &RegisterRewardDailyRecordPageResponse{ Date: resolvedClaimDate, LimitEnabled: dailyLimit > 0, DailyLimit: dailyLimit, OccupiedCount: occupiedCount, IssuedCount: issuedCount, SuccessCount: successCount, RemainingCount: resolveRegisterRewardRemainingCount( dailyLimit, occupiedCount, ), Records: records, Total: total, } return resp, nil } // newDailyRecordBaseQuery 创建后台领取记录分页的基础查询。 func (s *RegisterRewardService) newDailyRecordBaseQuery( ctx context.Context, sysOrigin string, claimDate string, ) *gorm.DB { return s.repo.DB.WithContext(ctx). Table("resident_register_reward_log AS log"). Where("log.sys_origin = ? AND log.claim_date = ?", sysOrigin, claimDate) } // countDailyRecordsByGrantMode 统计某天某系统在指定发奖模式下的记录数。 func (s *RegisterRewardService) countDailyRecordsByGrantMode( ctx context.Context, sysOrigin string, claimDate string, grantMode string, status string, ) (int64, error) { query := s.newDailyRecordBaseQuery(ctx, sysOrigin, claimDate). Where("log.grant_mode = ?", grantMode) if strings.TrimSpace(status) != "" { query = query.Where("log.status = ?", strings.ToUpper(strings.TrimSpace(status))) } var total int64 if err := query.Count(&total).Error; err != nil { return 0, err } return total, nil } // countDailyRecordsByStatus 统计某天某系统在指定处理状态下的记录数。 func (s *RegisterRewardService) countDailyRecordsByStatus( ctx context.Context, sysOrigin string, claimDate string, status string, ) (int64, error) { var total int64 if err := s.newDailyRecordBaseQuery(ctx, sysOrigin, claimDate). Where("log.status = ?", strings.ToUpper(strings.TrimSpace(status))). Count(&total).Error; err != nil { return 0, err } return total, nil } // toRegisterRewardDailyRecordView 把数据库行转换成后台页面直接可用的结构。 func toRegisterRewardDailyRecordView(row registerRewardDailyRecordRow) RegisterRewardDailyRecordView { claimResult := deriveRegisterRewardClaimResult(row.Status, row.GrantMode) return RegisterRewardDailyRecordView{ ID: row.ID, SysOrigin: row.SysOrigin, UserID: row.UserID, Account: row.Account, UserAvatar: row.UserAvatar, UserNickname: row.UserNickname, CountryCode: row.CountryCode, CountryName: row.CountryName, ClaimDate: row.ClaimDate, GrantMode: row.GrantMode, ClaimResult: claimResult, ClaimResultText: formatRegisterRewardClaimResultText(claimResult), GoldAmount: row.GoldAmount, RewardGroupID: row.RewardGroupID, Status: strings.ToUpper(strings.TrimSpace(row.Status)), ErrorMessage: strings.TrimSpace(row.ErrorMessage), CreateTime: formatRegisterRewardTime(row.CreateTime), UpdateTime: formatRegisterRewardTime(row.UpdateTime), } } // normalizeRegisterRewardPage 规范分页参数,避免非法页码或 pageSize。 func normalizeRegisterRewardPage(cursor int, limit int) (int, int) { if cursor <= 0 { cursor = 1 } if limit <= 0 { limit = 20 } if limit > 100 { limit = 100 } return cursor, limit } // resolveRegisterRewardRemainingCount 计算当前日期还剩余多少可发名额。 func resolveRegisterRewardRemainingCount(dailyLimit int64, occupiedCount int64) int64 { if dailyLimit <= 0 { return 0 } if occupiedCount >= dailyLimit { return 0 } return dailyLimit - occupiedCount } // deriveRegisterRewardClaimResult 统一归并后台页面展示的领取结果。 func deriveRegisterRewardClaimResult(status string, grantMode string) string { normalizedStatus := strings.ToUpper(strings.TrimSpace(status)) normalizedGrantMode := strings.ToUpper(strings.TrimSpace(grantMode)) switch { case normalizedGrantMode == registerRewardGrantModeQuotaExhausted && normalizedStatus == registerRewardStatusSuccess: return registerRewardClaimResultQuotaExhausted case normalizedGrantMode == registerRewardGrantModeIssueReward && normalizedStatus == registerRewardStatusSuccess: return registerRewardClaimResultRewarded case normalizedGrantMode == registerRewardGrantModeIssueReward && normalizedStatus == registerRewardStatusFailed: return registerRewardClaimResultFailed case normalizedGrantMode == registerRewardGrantModeIssueReward && normalizedStatus == registerRewardStatusPending: return registerRewardClaimResultPending case normalizedStatus == registerRewardStatusSkipped: return registerRewardClaimResultSkipped default: return registerRewardClaimResultPending } } // formatRegisterRewardClaimResultText 返回后台页面展示用的中文领取结果文案。 func formatRegisterRewardClaimResultText(claimResult string) string { switch strings.ToUpper(strings.TrimSpace(claimResult)) { case registerRewardClaimResultRewarded: return "已发放" case registerRewardClaimResultQuotaExhausted: return "名额已满,视为领取成功" case registerRewardClaimResultFailed: return "发奖失败,待补发" case registerRewardClaimResultSkipped: return "已跳过" default: return "发放中" } }