bindbox-game/internal/api/admin/batch_draw.go
邹方成 8141a47690
Some checks failed
Build docker and publish / linux (1.24.5) (push) Failing after 39s
feat(称号系统): 新增称号管理功能与抽奖效果集成
- 新增系统称号模板与效果配置表及相关CRUD接口
- 实现用户称号分配与抽奖效果应用逻辑
- 优化抽奖接口支持用户ID参数以应用称号效果
- 新增称号管理前端页面与分配功能
- 修复Windows时区错误与JSON字段初始化问题
- 移除无用管理接口代码并更新文档说明
2025-11-16 11:37:40 +08:00

159 lines
4.6 KiB
Go

package admin
import (
"encoding/hex"
"encoding/json"
"net/http"
"strconv"
"bindbox-game/internal/code"
"bindbox-game/internal/pkg/core"
"bindbox-game/internal/pkg/validation"
"bindbox-game/internal/repository/mysql/model"
)
type batchDrawRequest struct {
UserIDs []int64 `json:"user_ids" binding:"required,min=1,max=1000,dive,min=1"`
}
type batchDrawResponse struct {
Draws []drawResultItem `json:"draws"`
}
type drawResultItem struct {
UserID int64 `json:"user_id"`
DrawID int64 `json:"draw_id"`
RewardID int64 `json:"reward_id"`
RewardName string `json:"reward_name"`
IsWinner bool `json:"is_winner"`
Receipt interface{} `json:"receipt"`
}
func (h *handler) BatchDrawForUsers() core.HandlerFunc {
return func(ctx core.Context) {
activityIDStr := ctx.Param("activity_id")
if activityIDStr == "" {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递活动ID"))
return
}
issueIDStr := ctx.Param("issue_id")
if issueIDStr == "" {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递期ID"))
return
}
if _, err := strconv.ParseInt(issueIDStr, 10, 64); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
return
}
issueID, _ := strconv.ParseInt(issueIDStr, 10, 64)
_, _ = strconv.ParseInt(activityIDStr, 10, 64)
var req batchDrawRequest
if err := ctx.ShouldBindJSON(&req); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
return
}
rewards, err := h.activity.ListIssueRewards(ctx.RequestContext(), issueID)
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ExecuteDrawError, err.Error()))
return
}
rewardMap := make(map[int64]string, len(rewards))
for _, r := range rewards {
rewardMap[r.ID] = r.Name
}
// 开始事务处理
tx := h.writeDB.Begin()
if tx.Error != nil {
ctx.AbortWithError(core.Error(http.StatusInternalServerError, code.ExecuteDrawError, "启动事务失败"))
return
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
panic(r)
}
}()
draws := make([]drawResultItem, 0, len(req.UserIDs))
for _, uid := range req.UserIDs {
// 执行抽奖(应用头衔效果)
rec, err := h.activity.ExecuteDrawWithEffects(ctx.RequestContext(), issueID, uid)
if err != nil {
tx.Rollback()
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ExecuteDrawError, err.Error()))
return
}
// 创建抽奖日志
isWinner := int32(0)
if rec.SelectedItemId > 0 {
isWinner = 1
}
drawLog := &model.ActivityDrawLogs{
UserID: uid,
IssueID: issueID,
RewardID: rec.SelectedItemId,
IsWinner: isWinner,
Level: 1, // 默认等级
}
if err := tx.ActivityDrawLogs.Create(drawLog); err != nil {
tx.Rollback()
ctx.AbortWithError(core.Error(http.StatusInternalServerError, code.ExecuteDrawError, "创建抽奖日志失败"))
return
}
// 保存抽奖收据
itemsSnapshot, _ := json.Marshal(rec.Items)
receipt := &model.ActivityDrawReceipts{
DrawLogID: drawLog.ID,
AlgoVersion: rec.AlgoVersion,
RoundID: rec.RoundId,
DrawID: rec.DrawId,
ClientID: rec.ClientId,
Timestamp: rec.Timestamp,
ServerSeedHash: hex.EncodeToString(rec.ServerSeedHash),
ServerSubSeed: hex.EncodeToString(rec.ServerSubSeed),
ClientSeed: hex.EncodeToString(rec.ClientSeed),
Nonce: int64(rec.Nonce),
ItemsRoot: hex.EncodeToString(rec.ItemsRoot),
WeightsTotal: int64(rec.WeightsTotal),
SelectedIndex: int32(rec.SelectedIndex),
RandProof: hex.EncodeToString(rec.RandProof),
Signature: "", // 可以后续添加签名
ItemsSnapshot: string(itemsSnapshot),
}
if err := tx.ActivityDrawReceipts.Create(receipt); err != nil {
tx.Rollback()
ctx.AbortWithError(core.Error(http.StatusInternalServerError, code.ExecuteDrawError, "保存抽奖收据失败"))
return
}
name := ""
if rec.SelectedItemId > 0 {
name = rewardMap[rec.SelectedItemId]
}
draws = append(draws, drawResultItem{
UserID: uid,
DrawID: rec.DrawId,
RewardID: rec.SelectedItemId,
RewardName: name,
IsWinner: rec.SelectedItemId > 0,
Receipt: rec,
})
}
// 提交事务
if err := tx.Commit(); err != nil {
tx.Rollback()
ctx.AbortWithError(core.Error(http.StatusInternalServerError, code.ExecuteDrawError, "提交事务失败"))
return
}
ctx.Payload(&batchDrawResponse{Draws: draws})
}
}