bindbox-game/internal/api/admin/welfare_activities_admin.go
Zuncle 6127dc1a35 fix(activity): 允许后台编辑未开始的福利活动
中文说明:新增后台专用福利活动详情查询,后台编辑未开始活动时不再复用前台的未开始拦截逻辑,避免后台打开编辑弹窗提示“活动未开始”。
2026-05-03 23:03:52 +08:00

312 lines
10 KiB
Go

package admin
import (
"net/http"
"strconv"
"time"
"bindbox-game/internal/code"
"bindbox-game/internal/pkg/core"
"bindbox-game/internal/pkg/validation"
welfaresvc "bindbox-game/internal/service/welfare_activity"
)
type saveWelfareActivityRequest struct {
Title string `json:"title" binding:"required"`
Type string `json:"type" binding:"required"`
ThresholdAmount int64 `json:"threshold_amount"`
StartTime string `json:"start_time" binding:"required"`
EndTime string `json:"end_time" binding:"required"`
DrawTime string `json:"draw_time" binding:"required"`
Status string `json:"status"`
Description string `json:"description"`
CoverImage string `json:"cover_image"`
Prizes []welfaresvc.PrizeInput `json:"prizes"`
}
func (h *handler) CreateWelfareActivity() core.HandlerFunc {
return func(ctx core.Context) {
req := new(saveWelfareActivityRequest)
if err := ctx.ShouldBindJSON(req); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
return
}
input, err := req.toInput()
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, err.Error()))
return
}
item, err := h.welfare.CreateActivity(ctx.RequestContext(), input)
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateActivityError, err.Error()))
return
}
ctx.Payload(map[string]interface{}{"id": item.ID, "message": "操作成功"})
}
}
func (h *handler) UpdateWelfareActivity() core.HandlerFunc {
return func(ctx core.Context) {
id, err := strconv.ParseInt(ctx.Param("id"), 10, 64)
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "活动ID无效"))
return
}
req := new(saveWelfareActivityRequest)
if err := ctx.ShouldBindJSON(req); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
return
}
input, err := req.toInput()
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, err.Error()))
return
}
if err := h.welfare.UpdateActivity(ctx.RequestContext(), id, input); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ModifyActivityError, err.Error()))
return
}
ctx.Payload(simpleMessageResponse{Message: "操作成功"})
}
}
type listAdminWelfareActivitiesRequest struct {
Title string `form:"title"`
Type string `form:"type"`
Status string `form:"status"`
Page int `form:"page"`
PageSize int `form:"page_size"`
}
type listAdminWelfareWinnersRequest struct {
Page int `form:"page"`
PageSize int `form:"page_size"`
}
type welfareCostSummaryRequest struct {
StartTime string `form:"start_time"`
EndTime string `form:"end_time"`
}
func (h *handler) ListWelfareActivities() core.HandlerFunc {
return func(ctx core.Context) {
req := new(listAdminWelfareActivitiesRequest)
if err := ctx.ShouldBindForm(req); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, err.Error()))
return
}
res, err := h.welfare.ListActivities(ctx.RequestContext(), welfaresvc.ListActivitiesRequest{Type: req.Type, Status: req.Status, Title: req.Title, Page: req.Page, PageSize: req.PageSize})
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ListActivitiesError, err.Error()))
return
}
ctx.Payload(res)
}
}
func (h *handler) GetWelfareActivity() core.HandlerFunc {
return func(ctx core.Context) {
id, err := strconv.ParseInt(ctx.Param("id"), 10, 64)
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "活动ID无效"))
return
}
res, err := h.welfare.GetActivityAdmin(ctx.RequestContext(), id)
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.GetActivityError, err.Error()))
return
}
ctx.Payload(res)
}
}
func (h *handler) DeleteWelfareActivity() core.HandlerFunc {
return func(ctx core.Context) {
id, err := strconv.ParseInt(ctx.Param("id"), 10, 64)
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "活动ID无效"))
return
}
if err := h.welfare.DeleteActivity(ctx.RequestContext(), id); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.DeleteActivityError, err.Error()))
return
}
ctx.Payload(simpleMessageResponse{Message: "操作成功"})
}
}
type copyWelfareActivityRequest struct {
Title string `json:"title"`
Type string `json:"type" binding:"required"`
ThresholdAmount int64 `json:"threshold_amount"`
StartTime string `json:"start_time" binding:"required"`
EndTime string `json:"end_time" binding:"required"`
DrawTime string `json:"draw_time" binding:"required"`
Status string `json:"status"`
}
func (h *handler) CopyWelfareActivity() core.HandlerFunc {
return func(ctx core.Context) {
id, err := strconv.ParseInt(ctx.Param("id"), 10, 64)
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "活动ID无效"))
return
}
req := new(copyWelfareActivityRequest)
if err := ctx.ShouldBindJSON(req); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
return
}
start, err := parseRequiredTime(req.StartTime)
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, err.Error()))
return
}
end, err := parseRequiredTime(req.EndTime)
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, err.Error()))
return
}
draw, err := parseRequiredTime(req.DrawTime)
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, err.Error()))
return
}
newID, err := h.welfare.CopyActivity(ctx.RequestContext(), id, welfaresvc.SaveActivityRequest{
Title: req.Title,
Type: req.Type,
ThresholdAmount: req.ThresholdAmount,
StartTime: start,
EndTime: end,
DrawTime: draw,
Status: req.Status,
})
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateActivityError, err.Error()))
return
}
ctx.Payload(map[string]interface{}{"new_activity_id": newID, "status": "success"})
}
}
func (h *handler) ListWelfareParticipants() core.HandlerFunc {
return func(ctx core.Context) {
id, _ := strconv.ParseInt(ctx.Param("id"), 10, 64)
res, err := h.welfare.ListParticipants(ctx.RequestContext(), id, 1, 100)
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ListActivitiesError, err.Error()))
return
}
ctx.Payload(res)
}
}
func (h *handler) ListWelfareWinners() core.HandlerFunc {
return func(ctx core.Context) {
id, _ := strconv.ParseInt(ctx.Param("id"), 10, 64)
req := new(listAdminWelfareWinnersRequest)
if err := ctx.ShouldBindForm(req); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, err.Error()))
return
}
res, err := h.welfare.ListWinners(ctx.RequestContext(), id, req.Page, req.PageSize)
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ListActivitiesError, err.Error()))
return
}
ctx.Payload(res)
}
}
func (h *handler) DrawWelfareActivity() core.HandlerFunc {
return func(ctx core.Context) {
id, _ := strconv.ParseInt(ctx.Param("id"), 10, 64)
if err := h.welfare.Draw(ctx.RequestContext(), id); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ModifyActivityError, err.Error()))
return
}
ctx.Payload(simpleMessageResponse{Message: "操作成功"})
}
}
func (h *handler) GetWelfareCost() core.HandlerFunc {
return func(ctx core.Context) {
id, _ := strconv.ParseInt(ctx.Param("id"), 10, 64)
res, err := h.welfare.GetCost(ctx.RequestContext(), id)
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ListActivitiesError, err.Error()))
return
}
ctx.Payload(res)
}
}
func (h *handler) GetWelfareCostSummary() core.HandlerFunc {
return func(ctx core.Context) {
req := new(welfareCostSummaryRequest)
if err := ctx.ShouldBindForm(req); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, err.Error()))
return
}
start, _ := parseOptionalTime(req.StartTime)
end, _ := parseOptionalTime(req.EndTime)
res, err := h.welfare.GetCostSummary(ctx.RequestContext(), start, end)
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ListActivitiesError, err.Error()))
return
}
ctx.Payload(res)
}
}
func (r *saveWelfareActivityRequest) toInput() (welfaresvc.SaveActivityRequest, error) {
start, err := parseRequiredTime(r.StartTime)
if err != nil {
return welfaresvc.SaveActivityRequest{}, err
}
end, err := parseRequiredTime(r.EndTime)
if err != nil {
return welfaresvc.SaveActivityRequest{}, err
}
if sameDay(start, end) && end.Hour() == 0 && end.Minute() == 0 && end.Second() == 0 {
end = time.Date(end.Year(), end.Month(), end.Day(), 23, 59, 59, 0, end.Location())
}
draw, err := parseRequiredTime(r.DrawTime)
if err != nil {
return welfaresvc.SaveActivityRequest{}, err
}
prizes := make([]welfaresvc.PrizeInput, 0, len(r.Prizes))
for _, prize := range r.Prizes {
if prize.RewardType == "" && prize.ProductID > 0 {
prize.RewardType = welfaresvc.RewardTypeProduct
prize.RewardRefID = prize.ProductID
}
prizes = append(prizes, prize)
}
return welfaresvc.SaveActivityRequest{Title: r.Title, Type: r.Type, ThresholdAmount: r.ThresholdAmount, StartTime: start, EndTime: end, DrawTime: draw, Status: r.Status, Description: r.Description, CoverImage: r.CoverImage, Prizes: prizes}, nil
}
func parseRequiredTime(v string) (time.Time, error) {
if t, err := time.Parse(time.RFC3339, v); err == nil {
return t, nil
}
return time.ParseInLocation("2006-01-02 15:04:05", v, time.Local)
}
func parseOptionalTime(v string) (*time.Time, error) {
if v == "" {
return nil, nil
}
t, err := parseRequiredTime(v)
if err != nil {
return nil, err
}
return &t, nil
}
func sameDay(a, b time.Time) bool {
y1, m1, d1 := a.Date()
y2, m2, d2 := b.Date()
return y1 == y2 && m1 == m2 && d1 == d2
}