package pointsmall import ( "errors" "net/http" "strconv" "hfb_sys/backend/internal/middleware" "hfb_sys/backend/pkg/response" "github.com/gin-gonic/gin" ) type Handler struct { service *Service } func NewHandler(service *Service) *Handler { return &Handler{service: service} } func (h *Handler) Summary(c *gin.Context) { userID, ok := currentUserID(c) if !ok { response.Unauthorized(c, "缺少用户上下文") return } item, err := h.service.Summary(c.Request.Context(), userID) if err != nil { writeError(c, err) return } response.OK(c, item) } func (h *Handler) Ledger(c *gin.Context) { userID, ok := currentUserID(c) if !ok { response.Unauthorized(c, "缺少用户上下文") return } items, err := h.service.Ledger(c.Request.Context(), userID, parseLimit(c.Query("limit"))) if err != nil { writeError(c, err) return } response.OK(c, items) } func (h *Handler) Products(c *gin.Context) { items, err := h.service.ListProducts(c.Request.Context(), false) if err != nil { writeError(c, err) return } response.OK(c, items) } func (h *Handler) AdminProducts(c *gin.Context) { items, err := h.service.ListProducts(c.Request.Context(), true) if err != nil { writeError(c, err) return } response.OK(c, items) } func (h *Handler) CreateProduct(c *gin.Context) { var req ProductRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "积分商品参数不正确") return } item, err := h.service.CreateProduct(c.Request.Context(), req) if err != nil { writeError(c, err) return } response.OK(c, item) } func (h *Handler) UpdateProduct(c *gin.Context) { id, _ := strconv.ParseUint(c.Param("id"), 10, 64) if id == 0 { response.BadRequest(c, "商品 ID 不正确") return } var req ProductRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "积分商品参数不正确") return } item, err := h.service.UpdateProduct(c.Request.Context(), id, req) if err != nil { writeError(c, err) return } response.OK(c, item) } func (h *Handler) Redeem(c *gin.Context) { userID, ok := currentUserID(c) if !ok { response.Unauthorized(c, "缺少用户上下文") return } productID, _ := strconv.ParseUint(c.Param("id"), 10, 64) var req RedeemRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "请填写联系人、正确的手机号和兑换数量") return } item, err := h.service.Redeem(c.Request.Context(), userID, productID, req) if err != nil { writeError(c, err) return } response.OK(c, item) } func (h *Handler) MyRedemptions(c *gin.Context) { userID, ok := currentUserID(c) if !ok { response.Unauthorized(c, "缺少用户上下文") return } items, err := h.service.ListRedemptions(c.Request.Context(), userID, false) if err != nil { writeError(c, err) return } response.OK(c, items) } func (h *Handler) AdminRedemptions(c *gin.Context) { items, err := h.service.ListRedemptions(c.Request.Context(), 0, true) if err != nil { writeError(c, err) return } response.OK(c, items) } func (h *Handler) CompleteRedemption(c *gin.Context) { adminID, ok := currentAdminID(c) if !ok { response.Unauthorized(c, "缺少管理员上下文") return } id, _ := strconv.ParseUint(c.Param("id"), 10, 64) var req CompleteRedemptionRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "处理备注不正确") return } item, err := h.service.CompleteRedemption(c.Request.Context(), adminID, id, req.Remark) if err != nil { writeError(c, err) return } response.OK(c, item) } func currentUserID(c *gin.Context) (uint64, bool) { value, ok := c.Get(middleware.ContextUserID) if !ok { return 0, false } id, ok := value.(uint64) return id, ok } func currentAdminID(c *gin.Context) (uint64, bool) { value, ok := c.Get(middleware.ContextAdminID) if !ok { return 0, false } id, ok := value.(uint64) return id, ok } func parseLimit(value string) int { limit, err := strconv.Atoi(value) if err != nil { return 100 } return limit } func writeError(c *gin.Context, err error) { response.RecordError(c, err) switch { case errors.Is(err, ErrInvalidInput): response.BadRequest(c, "积分商城参数不正确") case errors.Is(err, ErrProductUnavailable): response.Error(c, http.StatusConflict, "points_product_unavailable", "商品已下架或库存不足") case errors.Is(err, ErrInsufficientPoints): response.Error(c, http.StatusConflict, "insufficient_points", "可用积分不足") case errors.Is(err, ErrRedeemLimitExceeded): response.Error(c, http.StatusConflict, "points_redeem_limit", "已超过该商品限兑数量") case errors.Is(err, ErrRedemptionNotPending): response.Error(c, http.StatusConflict, "points_redemption_processed", "该兑换记录已处理") case IsNotFound(err): response.Error(c, http.StatusNotFound, "not_found", "积分商城数据不存在") default: response.Error(c, http.StatusInternalServerError, "internal_error", "积分商城服务暂时不可用") } }