bindbox-game/internal/api/admin/users_batch_admin.go
邹方成 87ad4177b1
Some checks failed
Build docker and publish / linux (1.24.5) (push) Failing after 39s
feat(工作台): 实现管理端工作台接口并优化数据展示
feat(抽奖动态): 修复抽奖动态未渲染问题并优化文案展示
fix(用户概览): 修复用户概览无数据显示问题
feat(新用户列表): 在新用户列表显示称号明细
refactor(待办事项): 移除代办模块并全宽展示实时动态
feat(批量操作): 限制为单用户操作并在批量时提醒
fix(称号分配): 防重复分配称号的改造计划
perf(接口性能): 优化新用户和抽奖动态接口性能
feat(订单漏斗): 优化订单转化漏斗指标计算
docs(测试计划): 完善盲盒运营API核查与闭环测试计划
2025-11-16 14:00:29 +08:00

144 lines
5.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package admin
import (
"net/http"
"bindbox-game/internal/code"
"bindbox-game/internal/pkg/core"
"bindbox-game/internal/pkg/validation"
usersvc "bindbox-game/internal/service/user"
)
type batchPointsRequest struct {
Users []int64 `json:"users" binding:"required"`
Amount int64 `json:"amount" binding:"min=1"`
Reason string `json:"reason"`
IdempotencyKey string `json:"idempotency_key"`
}
type batchCouponsRequest struct {
Users []int64 `json:"users" binding:"required"`
CouponID int64 `json:"coupon_id" binding:"required"`
QuantityPerUser int `json:"quantity_per_user"`
IdempotencyKey string `json:"idempotency_key"`
}
type batchRewardsRequest struct {
Users []int64 `json:"users" binding:"required"`
ProductID int64 `json:"product_id" binding:"required"`
Quantity int `json:"quantity" binding:"min=1"`
ActivityID *int64 `json:"activity_id"`
RewardID *int64 `json:"reward_id"`
AddressID *int64 `json:"address_id"`
Remark string `json:"remark"`
IdempotencyKey string `json:"idempotency_key"`
}
type batchItemResult struct {
UserID int64 `json:"user_id"`
Status string `json:"status"`
Message string `json:"message"`
}
type batchResponse struct {
Success int `json:"success"`
Failed int `json:"failed"`
Details []batchItemResult `json:"details"`
}
func (h *handler) BatchAddUserPoints() core.HandlerFunc {
return func(ctx core.Context) {
if ctx.SessionUserInfo().IsSuper != 1 {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, "禁止操作"))
return
}
req := new(batchPointsRequest)
if err := ctx.ShouldBindJSON(req); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
return
}
if len(req.Users) != 1 {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "当前仅支持单用户操作请仅选择1位用户"))
return
}
res := &batchResponse{Details: make([]batchItemResult, 0, len(req.Users))}
for _, uid := range req.Users {
if err := h.user.AddPoints(ctx.RequestContext(), uid, req.Amount, "manual", req.Reason, nil, nil); err != nil {
res.Failed++
res.Details = append(res.Details, batchItemResult{UserID: uid, Status: "failed", Message: err.Error()})
} else {
res.Success++
res.Details = append(res.Details, batchItemResult{UserID: uid, Status: "success"})
}
}
ctx.Payload(res)
}
}
func (h *handler) BatchAddUserCoupons() core.HandlerFunc {
return func(ctx core.Context) {
if ctx.SessionUserInfo().IsSuper != 1 {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, "禁止操作"))
return
}
req := new(batchCouponsRequest)
if err := ctx.ShouldBindJSON(req); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
return
}
if len(req.Users) != 1 {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "当前仅支持单用户操作请仅选择1位用户"))
return
}
if req.QuantityPerUser <= 0 { req.QuantityPerUser = 1 }
if req.QuantityPerUser > 5 { req.QuantityPerUser = 5 }
res := &batchResponse{Details: make([]batchItemResult, 0, len(req.Users))}
for _, uid := range req.Users {
ok := true
for i := 0; i < req.QuantityPerUser; i++ {
if err := h.user.AddCoupon(ctx.RequestContext(), uid, req.CouponID); err != nil { ok = false }
}
if ok {
res.Success++
res.Details = append(res.Details, batchItemResult{UserID: uid, Status: "success"})
} else {
res.Failed++
res.Details = append(res.Details, batchItemResult{UserID: uid, Status: "failed"})
}
}
ctx.Payload(res)
}
}
func (h *handler) BatchGrantUserRewards() core.HandlerFunc {
return func(ctx core.Context) {
if ctx.SessionUserInfo().IsSuper != 1 {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, "禁止操作"))
return
}
req := new(batchRewardsRequest)
if err := ctx.ShouldBindJSON(req); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
return
}
if len(req.Users) != 1 {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "当前仅支持单用户操作请仅选择1位用户"))
return
}
if req.Quantity <= 0 { req.Quantity = 1 }
if req.Quantity > 10 { req.Quantity = 10 }
res := &batchResponse{Details: make([]batchItemResult, 0, len(req.Users))}
r := usersvc.GrantRewardRequest{ProductID: req.ProductID, Quantity: req.Quantity, ActivityID: req.ActivityID, RewardID: req.RewardID, AddressID: req.AddressID, Remark: req.Remark}
for _, uid := range req.Users {
_, err := h.user.GrantReward(ctx.RequestContext(), uid, r)
if err != nil {
res.Failed++
res.Details = append(res.Details, batchItemResult{UserID: uid, Status: "failed", Message: err.Error()})
} else {
res.Success++
res.Details = append(res.Details, batchItemResult{UserID: uid, Status: "success"})
}
}
ctx.Payload(res)
}
}