bindbox-game/internal/api/admin/item_cards_admin.go
邹方成 1ab39d2f5a
Some checks failed
Build docker and publish / linux (1.24.5) (push) Failing after 25s
refactor: 重构项目结构并重命名模块
feat(admin): 新增工会管理功能
feat(activity): 添加活动管理相关服务
feat(user): 实现用户道具卡和积分管理
feat(guild): 新增工会成员管理功能

fix: 修复数据库连接配置
fix: 修正jwtoken导入路径
fix: 解决端口冲突问题

style: 统一代码格式和注释风格
style: 更新项目常量命名

docs: 添加项目框架和开发规范文档
docs: 更新接口文档注释

chore: 移除无用代码和文件
chore: 更新Makefile和配置文件
chore: 清理日志文件

test: 添加道具卡测试脚本
2025-11-14 21:10:00 +08:00

378 lines
13 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"
"strconv"
"time"
"bindbox-game/internal/code"
"bindbox-game/internal/pkg/core"
"bindbox-game/internal/pkg/validation"
"bindbox-game/internal/repository/mysql/model"
)
type simpleMessageResponse struct {
Message string `json:"message"`
}
type createItemCardRequest struct {
Name string `json:"name" binding:"required"`
Status int32 `json:"status"`
CardType int32 `json:"card_type" binding:"required"`
ScopeType int32 `json:"scope_type" binding:"required"`
ActivityCategoryID int64 `json:"activity_category_id"`
ActivityID int64 `json:"activity_id"`
IssueID int64 `json:"issue_id"`
Price int64 `json:"price" binding:"required"`
ValidStartUnix *int64 `json:"valid_start_unix"`
ValidEndUnix *int64 `json:"valid_end_unix"`
EffectType int32 `json:"effect_type" binding:"required"`
RewardMultiplierX1000 int32 `json:"reward_multiplier_x1000"`
BoostRateX1000 int32 `json:"boost_rate_x1000"`
StackingStrategy int32 `json:"stacking_strategy"`
MaxEffectValueX1000 int32 `json:"max_effect_value_x1000"`
Remark string `json:"remark"`
}
type createItemCardResponse struct {
ID int64 `json:"id"`
Message string `json:"message"`
}
// CreateSystemItemCard 创建道具卡
// @Summary 创建道具卡
// @Description 管理员创建新的道具卡,支持设置类型、效果、有效期等属性
// @Tags 管理端.运营管理
// @Accept json
// @Produce json
// @Param RequestBody body createItemCardRequest true "创建道具卡请求参数"
// @Success 200 {object} createItemCardResponse
// @Failure 400 {object} code.Failure "参数错误"
// @Failure 401 {object} code.Failure "未授权"
// @Failure 403 {object} code.Failure "无权限,仅超管可操作"
// @Failure 500 {object} code.Failure "服务器内部错误"
// @Router /api/admin/system_item_cards [post]
func (h *handler) CreateSystemItemCard() core.HandlerFunc {
return func(ctx core.Context) {
req := new(createItemCardRequest)
res := new(createItemCardResponse)
if err := ctx.ShouldBindJSON(req); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
return
}
if ctx.SessionUserInfo().IsSuper != 1 {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, "禁止操作"))
return
}
item := &model.SystemItemCards{
Name: req.Name,
Status: func() int32 {
if req.Status == 0 {
return 1
}
return req.Status
}(),
CardType: req.CardType,
ScopeType: req.ScopeType,
ActivityCategoryID: req.ActivityCategoryID,
ActivityID: req.ActivityID,
IssueID: req.IssueID,
Price: req.Price,
EffectType: req.EffectType,
RewardMultiplierX1000: req.RewardMultiplierX1000,
BoostRateX1000: req.BoostRateX1000,
StackingStrategy: func() int32 {
if req.StackingStrategy == 0 {
return 1
}
return req.StackingStrategy
}(),
MaxEffectValueX1000: req.MaxEffectValueX1000,
Remark: req.Remark,
}
do := h.writeDB.SystemItemCards.WithContext(ctx.RequestContext())
if req.ValidStartUnix != nil {
item.ValidStart = time.Unix(*req.ValidStartUnix, 0)
}
if req.ValidEndUnix != nil {
item.ValidEnd = time.Unix(*req.ValidEndUnix, 0)
} else {
do = do.Omit(h.writeDB.SystemItemCards.ValidEnd)
}
if err := do.Create(item); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error()))
return
}
res.ID = item.ID
res.Message = "操作成功"
ctx.Payload(res)
}
}
type modifyItemCardRequest struct {
Name *string `json:"name"`
Status *int32 `json:"status"`
CardType *int32 `json:"card_type"`
ScopeType *int32 `json:"scope_type"`
ActivityCategoryID *int64 `json:"activity_category_id"`
ActivityID *int64 `json:"activity_id"`
IssueID *int64 `json:"issue_id"`
Price *int64 `json:"price"`
ValidStartUnix *int64 `json:"valid_start_unix"`
ValidEndUnix *int64 `json:"valid_end_unix"`
EffectType *int32 `json:"effect_type"`
RewardMultiplierX1000 *int32 `json:"reward_multiplier_x1000"`
BoostRateX1000 *int32 `json:"boost_rate_x1000"`
StackingStrategy *int32 `json:"stacking_strategy"`
MaxEffectValueX1000 *int32 `json:"max_effect_value_x1000"`
Remark *string `json:"remark"`
}
// ModifySystemItemCard 修改道具卡
// @Summary 修改道具卡
// @Description 管理员修改道具卡信息,支持修改名称、价格、有效期等属性
// @Tags 管理端.运营管理
// @Accept json
// @Produce json
// @Param item_card_id path integer true "道具卡ID"
// @Param RequestBody body modifyItemCardRequest true "修改道具卡请求参数"
// @Success 200 {object} simpleMessageResponse
// @Failure 400 {object} code.Failure "参数错误"
// @Failure 401 {object} code.Failure "未授权"
// @Failure 403 {object} code.Failure "无权限,仅超管可操作"
// @Failure 500 {object} code.Failure "服务器内部错误"
// @Router /api/admin/system_item_cards/{item_card_id} [put]
func (h *handler) ModifySystemItemCard() core.HandlerFunc {
return func(ctx core.Context) {
req := new(modifyItemCardRequest)
if err := ctx.ShouldBindJSON(req); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
return
}
idStr := ctx.Param("item_card_id")
id, _ := strconv.ParseInt(idStr, 10, 64)
if ctx.SessionUserInfo().IsSuper != 1 {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, "禁止操作"))
return
}
set := map[string]any{}
if req.Name != nil {
set["name"] = *req.Name
}
if req.Status != nil {
set["status"] = *req.Status
}
if req.CardType != nil {
set["card_type"] = *req.CardType
}
if req.ScopeType != nil {
set["scope_type"] = *req.ScopeType
}
if req.ActivityCategoryID != nil {
set["activity_category_id"] = *req.ActivityCategoryID
}
if req.ActivityID != nil {
set["activity_id"] = *req.ActivityID
}
if req.IssueID != nil {
set["issue_id"] = *req.IssueID
}
if req.Price != nil {
set["price"] = *req.Price
}
if req.EffectType != nil {
set["effect_type"] = *req.EffectType
}
if req.RewardMultiplierX1000 != nil {
set["reward_multiplier_x1000"] = *req.RewardMultiplierX1000
}
if req.BoostRateX1000 != nil {
set["boost_rate_x1000"] = *req.BoostRateX1000
}
if req.StackingStrategy != nil {
set["stacking_strategy"] = *req.StackingStrategy
}
if req.MaxEffectValueX1000 != nil {
set["max_effect_value_x1000"] = *req.MaxEffectValueX1000
}
if req.Remark != nil {
set["remark"] = *req.Remark
}
if req.ValidStartUnix != nil {
set["valid_start"] = time.Unix(*req.ValidStartUnix, 0)
}
if req.ValidEndUnix != nil {
set["valid_end"] = time.Unix(*req.ValidEndUnix, 0)
}
if len(set) == 0 {
ctx.Payload(simpleMessageResponse{Message: "操作成功"})
return
}
if _, err := h.writeDB.SystemItemCards.WithContext(ctx.RequestContext()).Where(h.writeDB.SystemItemCards.ID.Eq(id)).Updates(set); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error()))
return
}
ctx.Payload(simpleMessageResponse{Message: "操作成功"})
}
}
// DeleteSystemItemCard 删除道具卡
// @Summary 删除道具卡
// @Description 管理员删除指定的道具卡
// @Tags 管理端.运营管理
// @Accept json
// @Produce json
// @Param item_card_id path integer true "道具卡ID"
// @Success 200 {object} simpleMessageResponse
// @Failure 400 {object} code.Failure "参数错误"
// @Failure 401 {object} code.Failure "未授权"
// @Failure 403 {object} code.Failure "无权限,仅超管可操作"
// @Failure 500 {object} code.Failure "服务器内部错误"
// @Router /api/admin/system_item_cards/{item_card_id} [delete]
func (h *handler) DeleteSystemItemCard() core.HandlerFunc {
return func(ctx core.Context) {
idStr := ctx.Param("item_card_id")
id, _ := strconv.ParseInt(idStr, 10, 64)
if ctx.SessionUserInfo().IsSuper != 1 {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, "禁止操作"))
return
}
if _, err := h.writeDB.SystemItemCards.WithContext(ctx.RequestContext()).Where(h.writeDB.SystemItemCards.ID.Eq(id)).Delete(); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error()))
return
}
ctx.Payload(simpleMessageResponse{Message: "操作成功"})
}
}
type listItemCardsRequest struct {
Name string `form:"name"`
Status int32 `form:"status"`
CardType int32 `form:"card_type"`
ScopeType int32 `form:"scope_type"`
Page int `form:"page"`
PageSize int `form:"page_size"`
}
type itemCardListItem struct {
*model.SystemItemCards
}
type listItemCardsResponse struct {
Page int `json:"page"`
PageSize int `json:"page_size"`
Total int64 `json:"total"`
List []itemCardListItem `json:"list"`
}
// ListSystemItemCards 获取道具卡列表
// @Summary 获取道具卡列表
// @Description 管理员获取道具卡列表,支持按名称、状态、类型等条件筛选
// @Tags 管理端.运营管理
// @Accept json
// @Produce json
// @Param name query string false "道具卡名称"
// @Param status query integer false "状态1启用 2禁用"
// @Param card_type query integer false "道具卡类型1抽奖卡 2加成卡 3保底卡"
// @Param scope_type query integer false "适用范围1全局 2活动分类 3活动 4期次"
// @Param page query integer false "页码默认1"
// @Param page_size query integer false "每页条数默认10"
// @Success 200 {object} listItemCardsResponse
// @Failure 400 {object} code.Failure "参数错误"
// @Failure 401 {object} code.Failure "未授权"
// @Failure 500 {object} code.Failure "服务器内部错误"
// @Router /api/admin/system_item_cards [get]
func (h *handler) ListSystemItemCards() core.HandlerFunc {
return func(ctx core.Context) {
req := new(listItemCardsRequest)
res := new(listItemCardsResponse)
if err := ctx.ShouldBindForm(req); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
return
}
q := h.readDB.SystemItemCards.WithContext(ctx.RequestContext()).ReadDB()
if req.Name != "" {
q = q.Where(h.readDB.SystemItemCards.Name.Like("%" + req.Name + "%"))
}
if req.Status != 0 {
q = q.Where(h.readDB.SystemItemCards.Status.Eq(req.Status))
}
if req.CardType != 0 {
q = q.Where(h.readDB.SystemItemCards.CardType.Eq(req.CardType))
}
if req.ScopeType != 0 {
q = q.Where(h.readDB.SystemItemCards.ScopeType.Eq(req.ScopeType))
}
total, err := q.Count()
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ListActivitiesError, err.Error()))
return
}
if req.Page <= 0 {
req.Page = 1
}
if req.PageSize <= 0 {
req.PageSize = 20
}
if req.PageSize > 100 {
req.PageSize = 100
}
rows, err := q.Order(h.readDB.SystemItemCards.ID.Desc()).Offset((req.Page - 1) * req.PageSize).Limit(req.PageSize).Find()
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ListActivitiesError, err.Error()))
return
}
res.Page = req.Page
res.PageSize = req.PageSize
res.Total = total
res.List = make([]itemCardListItem, len(rows))
for i, r := range rows {
res.List[i] = itemCardListItem{SystemItemCards: r}
}
ctx.Payload(res)
}
}
type assignItemCardRequest struct {
CardID int64 `json:"card_id" binding:"required"`
Quantity int `json:"quantity"`
}
// AssignUserItemCard 给用户分配道具卡
// @Summary 给用户分配道具卡
// @Description 管理员给指定用户分配道具卡,可指定数量
// @Tags 管理端.运营管理
// @Accept json
// @Produce json
// @Param user_id path integer true "用户ID"
// @Param RequestBody body assignItemCardRequest true "分配道具卡请求参数"
// @Success 200 {object} simpleMessageResponse
// @Failure 400 {object} code.Failure "参数错误"
// @Failure 401 {object} code.Failure "未授权"
// @Failure 403 {object} code.Failure "无权限,仅超管可操作"
// @Failure 500 {object} code.Failure "服务器内部错误"
// @Router /api/admin/users/{user_id}/item_cards [post]
func (h *handler) AssignUserItemCard() core.HandlerFunc {
return func(ctx core.Context) {
req := new(assignItemCardRequest)
if err := ctx.ShouldBindJSON(req); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
return
}
userID, err := strconv.ParseInt(ctx.Param("user_id"), 10, 64)
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递用户ID"))
return
}
if ctx.SessionUserInfo().IsSuper != 1 {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, "禁止操作"))
return
}
if err := h.user.AddItemCard(ctx.RequestContext(), userID, req.CardID, req.Quantity); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error()))
return
}
ctx.Payload(simpleMessageResponse{Message: "操作成功"})
}
}