package handler import ( "errors" "net/http" "time" "github.com/gin-gonic/gin" membershipservice "wx_service/internal/membership/service" "wx_service/internal/middleware" "wx_service/internal/model" ) type RedeemCodeHandler struct { svc *membershipservice.RedeemCodeService } func NewRedeemCodeHandler(svc *membershipservice.RedeemCodeService) *RedeemCodeHandler { return &RedeemCodeHandler{svc: svc} } type generateRedeemCodesRequest struct { Count int `json:"count"` Plan string `json:"plan"` DurationDays int `json:"duration_days"` ExpiresAt *string `json:"expires_at"` MaxUses int `json:"max_uses"` } func (h *RedeemCodeHandler) Generate(c *gin.Context) { adminToken := c.GetHeader("X-Admin-Token") if err := h.svc.ValidateAdminToken(adminToken); err != nil { switch { case errors.Is(err, membershipservice.ErrAdminTokenRequired): c.JSON(http.StatusServiceUnavailable, model.Error(http.StatusServiceUnavailable, "未配置后台口令,请联系管理员")) return default: c.JSON(http.StatusUnauthorized, model.Error(http.StatusUnauthorized, "无权限")) return } } var req generateRedeemCodesRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "请求参数错误")) return } var expiresAt *time.Time if req.ExpiresAt != nil && *req.ExpiresAt != "" { parsed, err := time.ParseInLocation("2006-01-02 15:04:05", *req.ExpiresAt, time.Local) if err != nil { c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "expires_at 格式错误,应为 YYYY-MM-DD HH:MM:SS")) return } expiresAt = &parsed } codes, err := h.svc.Generate(c.Request.Context(), membershipservice.GenerateRedeemCodesRequest{ Count: req.Count, Plan: req.Plan, DurationDays: req.DurationDays, ExpiresAt: expiresAt, MaxUses: req.MaxUses, }) if err != nil { c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, err.Error())) return } c.JSON(http.StatusOK, model.Success(gin.H{ "count": len(codes), "codes": codes, })) } type redeemRequest struct { Code string `json:"code" binding:"required"` } func (h *RedeemCodeHandler) Redeem(c *gin.Context) { user := middleware.MustCurrentUser(c) var req redeemRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "请求参数错误")) return } res, err := h.svc.Redeem(c.Request.Context(), user, req.Code, c.ClientIP(), c.GetHeader("User-Agent")) if err != nil { switch { case errors.Is(err, membershipservice.ErrRedeemCodeInvalid): c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "兑换码无效")) return case errors.Is(err, membershipservice.ErrRedeemCodeExpired): c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "兑换码已过期")) return case errors.Is(err, membershipservice.ErrRedeemCodeUsedUp): c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "兑换码已被使用")) return case errors.Is(err, membershipservice.ErrRedeemCodeDisabled): c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "兑换码不可用")) return default: c.JSON(http.StatusInternalServerError, model.Error(http.StatusInternalServerError, "兑换失败,请稍后重试")) return } } c.JSON(http.StatusOK, model.Success(gin.H{ "plan": res.Plan, "starts_at": res.StartsAt, "ends_at": res.EndsAt, "extended": res.Extended, "code_suffix": res.CodeSuffix, })) }