255 lines
7.9 KiB
Go

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 "发放中"
}
}