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 createSystemCouponRequest struct { Name string `json:"name" binding:"required"` Status *int32 `json:"status"` CouponType *int32 `json:"coupon_type"` DiscountType *int32 `json:"discount_type"` DiscountValue *int64 `json:"discount_value"` MinAmount *int64 `json:"min_amount"` ValidDays *int `json:"valid_days"` TotalQuantity *int64 `json:"total_quantity"` } type createSystemCouponResponse struct { ID int64 `json:"id"` Message string `json:"message"` } func (h *handler) CreateSystemCoupon() core.HandlerFunc { return func(ctx core.Context) { req := new(createSystemCouponRequest) res := new(createSystemCouponResponse) 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 } now := time.Now() m := &model.SystemCoupons{ Name: req.Name, ScopeType: getInt32OrDefault(req.CouponType, 1), DiscountType: getInt32OrDefault(req.DiscountType, 1), DiscountValue: getInt64OrDefault(req.DiscountValue, 0), MinSpend: getInt64OrDefault(req.MinAmount, 0), Status: getInt32OrDefault(req.Status, 1), } if req.ValidDays != nil && *req.ValidDays > 0 { m.ValidStart = now m.ValidEnd = now.Add(time.Duration(*req.ValidDays) * 24 * time.Hour) } if err := h.writeDB.SystemCoupons.WithContext(ctx.RequestContext()).Create(m); err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error())) return } if req.TotalQuantity != nil { if _, err := h.writeDB.SystemCoupons.WithContext(ctx.RequestContext()).Where(h.writeDB.SystemCoupons.ID.Eq(m.ID)).Updates(map[string]any{"total_quantity": *req.TotalQuantity}); err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error())) return } } res.ID = m.ID res.Message = "操作成功" ctx.Payload(res) } } type modifySystemCouponRequest struct { Name *string `json:"name"` Status *int32 `json:"status"` CouponType *int32 `json:"coupon_type"` DiscountType *int32 `json:"discount_type"` DiscountValue *int64 `json:"discount_value"` MinAmount *int64 `json:"min_amount"` ValidDays *int `json:"valid_days"` TotalQuantity *int64 `json:"total_quantity"` } func (h *handler) ModifySystemCoupon() core.HandlerFunc { return func(ctx core.Context) { req := new(modifySystemCouponRequest) if err := ctx.ShouldBindJSON(req); err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err))) return } idStr := ctx.Param("coupon_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.CouponType != nil { set["scope_type"] = *req.CouponType } if req.DiscountType != nil { set["discount_type"] = *req.DiscountType } if req.DiscountValue != nil { set["discount_value"] = *req.DiscountValue } if req.MinAmount != nil { set["min_spend"] = *req.MinAmount } if req.ValidDays != nil && *req.ValidDays > 0 { now := time.Now() set["valid_start"] = now set["valid_end"] = now.Add(time.Duration(*req.ValidDays) * 24 * time.Hour) } if req.TotalQuantity != nil { set["total_quantity"] = *req.TotalQuantity } if len(set) == 0 { ctx.Payload(pcSimpleMessage{Message: "操作成功"}) return } if _, err := h.writeDB.SystemCoupons.WithContext(ctx.RequestContext()).Where(h.writeDB.SystemCoupons.ID.Eq(id)).Updates(set); err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error())) return } ctx.Payload(pcSimpleMessage{Message: "操作成功"}) } } func (h *handler) DeleteSystemCoupon() core.HandlerFunc { return func(ctx core.Context) { idStr := ctx.Param("coupon_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.SystemCoupons.WithContext(ctx.RequestContext()).Where(h.writeDB.SystemCoupons.ID.Eq(id)).Delete(); err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.CreateAdminError, err.Error())) return } ctx.Payload(pcSimpleMessage{Message: "操作成功"}) } } type listSystemCouponsRequest struct { Name string `form:"name"` Status *int32 `form:"status"` Page int `form:"page"` PageSize int `form:"page_size"` } type systemCouponItem struct { ID int64 `json:"id"` Name string `json:"name"` Status int32 `json:"status"` CouponType int32 `json:"coupon_type"` DiscountType int32 `json:"discount_type"` DiscountValue int64 `json:"discount_value"` MinAmount int64 `json:"min_amount"` MaxDiscount int64 `json:"max_discount"` ValidDays int `json:"valid_days"` TotalQuantity int64 `json:"total_quantity"` UsedQuantity int64 `json:"used_quantity"` CreatedAt string `json:"created_at"` } type listSystemCouponsResponse struct { Page int `json:"page"` PageSize int `json:"page_size"` Total int64 `json:"total"` List []systemCouponItem `json:"list"` } func (h *handler) ListSystemCoupons() core.HandlerFunc { return func(ctx core.Context) { req := new(listSystemCouponsRequest) res := new(listSystemCouponsResponse) if err := ctx.ShouldBindForm(req); err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err))) return } if req.Page <= 0 { req.Page = 1 } if req.PageSize <= 0 { req.PageSize = 20 } q := h.readDB.SystemCoupons.WithContext(ctx.RequestContext()).ReadDB() if req.Name != "" { q = q.Where(h.readDB.SystemCoupons.Name.Like("%" + req.Name + "%")) } if req.Status != nil { q = q.Where(h.readDB.SystemCoupons.Status.Eq(*req.Status)) } total, err := q.Count() if err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ServerError, err.Error())) return } type dbRow struct { ID int64 Name string Status int32 ScopeType int32 DiscountType int32 DiscountValue int64 MinSpend int64 ValidStart time.Time ValidEnd time.Time CreatedAt time.Time TotalQuantity int64 } var rows []dbRow if err := q.Order(h.readDB.SystemCoupons.ID.Desc()).Limit(req.PageSize).Offset((req.Page - 1) * req.PageSize).Scan(&rows); err != nil { ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ServerError, err.Error())) return } res.Page = req.Page res.PageSize = req.PageSize res.Total = total res.List = make([]systemCouponItem, len(rows)) for i, v := range rows { validDays := 0 if !v.ValidStart.IsZero() && !v.ValidEnd.IsZero() { diff := v.ValidEnd.Sub(v.ValidStart) validDays = int(diff.Hours() / 24) } // 统计已发放数量(用户持券数) usedCnt, _ := h.readDB.UserCoupons.WithContext(ctx.RequestContext()).Where(h.readDB.UserCoupons.CouponID.Eq(v.ID)).Count() res.List[i] = systemCouponItem{ ID: v.ID, Name: v.Name, Status: v.Status, CouponType: v.ScopeType, DiscountType: v.DiscountType, DiscountValue: v.DiscountValue, MinAmount: v.MinSpend, MaxDiscount: 0, ValidDays: validDays, TotalQuantity: v.TotalQuantity, UsedQuantity: usedCnt, CreatedAt: v.CreatedAt.Format("2006-01-02 15:04:05"), } } ctx.Payload(res) } } func getInt32OrDefault(v *int32, d int32) int32 { if v != nil { return *v } return d } func getInt64OrDefault(v *int64, d int64) int64 { if v != nil { return *v } return d }