package distribution import ( "errors" "net/http" "strconv" "strings" "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) ListSites(c *gin.Context) { items, err := h.service.ListSites(c.Request.Context()) if err != nil { writeError(c, err) return } response.OK(c, gin.H{"items": items}) } func (h *Handler) GetSite(c *gin.Context) { id, ok := parseID(c) if !ok { return } item, err := h.service.FindSite(c.Request.Context(), id) if err != nil { writeError(c, err) return } response.OK(c, item) } func (h *Handler) CreateSite(c *gin.Context) { var req CreateSiteRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "分销网站参数不正确") return } item, err := h.service.CreateSite(c.Request.Context(), req) if err != nil { writeError(c, err) return } response.Created(c, item) } func (h *Handler) UpdateSite(c *gin.Context) { id, ok := parseID(c) if !ok { return } var req UpdateSiteRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "分销网站参数不正确") return } item, err := h.service.UpdateSite(c.Request.Context(), id, req) if err != nil { writeError(c, err) return } response.OK(c, item) } func (h *Handler) ListRules(c *gin.Context) { var siteID *uint64 if raw := strings.TrimSpace(c.Query("site_id")); raw != "" { id, err := strconv.ParseUint(raw, 10, 64) if err != nil || id == 0 { response.BadRequest(c, "site_id 不正确") return } siteID = &id } items, err := h.service.ListRules(c.Request.Context(), siteID, c.Query("mode")) if err != nil { writeError(c, err) return } response.OK(c, gin.H{"items": items}) } func (h *Handler) CreateRule(c *gin.Context) { adminID, ok := currentAdminID(c) if !ok { response.Unauthorized(c, "缺少管理员上下文") return } var req CreateRuleRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "分销规则参数不正确") return } item, err := h.service.CreateRule(c.Request.Context(), adminID, req) if err != nil { writeError(c, err) return } response.Created(c, item) } func (h *Handler) UpdateRuleStatus(c *gin.Context) { id, ok := parseID(c) if !ok { return } var req UpdateRuleStatusRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "规则状态不正确") return } item, err := h.service.UpdateRuleStatus(c.Request.Context(), id, req.Status) if err != nil { writeError(c, err) return } response.OK(c, item) } func (h *Handler) ListOrders(c *gin.Context) { siteID := parseQueryUint(c, "site_id") if siteID < 0 { return } page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) size, _ := strconv.Atoi(c.DefaultQuery("page_size", "20")) result, err := h.service.ListOrders(c.Request.Context(), DistributionOrderListQuery{SiteID: uint64(siteID), Kind: c.Query("kind"), Status: c.Query("status"), Page: page, Size: size}) if err != nil { writeError(c, err) return } response.OK(c, result) } func (h *Handler) FindOrder(c *gin.Context) { id, ok := parseID(c) if !ok { return } item, err := h.service.FindOrder(c.Request.Context(), id) if err != nil { writeError(c, err) return } response.OK(c, item) } func (h *Handler) CreateFinancialSnapshot(c *gin.Context) { id, ok := parseID(c) if !ok { return } var req CreateFinancialSnapshotRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "分销财务快照参数不正确") return } item, err := h.service.CreateFinancialSnapshot(c.Request.Context(), id, req) if err != nil { writeError(c, err) return } response.Created(c, item) } func (h *Handler) ListAccountDisplays(c *gin.Context) { siteID := parseQueryUint(c, "site_id") if siteID <= 0 { if siteID == 0 { response.BadRequest(c, "site_id 不正确") } return } items, err := h.service.ListAccountDisplays(c.Request.Context(), uint64(siteID), c.Query("status")) if err != nil { writeError(c, err) return } response.OK(c, gin.H{"items": items}) } func (h *Handler) UpdateAccountDisplay(c *gin.Context) { id, ok := parseID(c) if !ok { return } var req UpdateAccountDisplayRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "账号展示状态不正确") return } item, err := h.service.UpdateAccountDisplay(c.Request.Context(), id, req.DisplayStatus) if err != nil { writeError(c, err) return } response.OK(c, item) } func (h *Handler) ListPaymentChannels(c *gin.Context) { siteID := parseQueryUint(c, "site_id") if siteID <= 0 { response.BadRequest(c, "site_id 不正确") return } items, err := h.service.ListPaymentChannels(c.Request.Context(), uint64(siteID)) if err != nil { writeError(c, err) return } response.OK(c, gin.H{"items": items}) } func (h *Handler) BindPaymentChannel(c *gin.Context) { siteID := parseQueryUint(c, "site_id") if siteID <= 0 { response.BadRequest(c, "site_id 不正确") return } var req BindPaymentChannelRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "支付通道参数不正确") return } item, err := h.service.BindPaymentChannel(c.Request.Context(), uint64(siteID), req) if err != nil { writeError(c, err) return } response.Created(c, item) } func (h *Handler) UnbindPaymentChannel(c *gin.Context) { id, ok := parseID(c) if !ok { return } if err := h.service.UnbindPaymentChannel(c.Request.Context(), id); err != nil { writeError(c, err) return } response.OK(c, gin.H{"deleted": true}) } func (h *Handler) ListSettlementBatches(c *gin.Context) { siteID := parseQueryUint(c, "site_id") if siteID <= 0 { response.BadRequest(c, "site_id 不正确") return } items, err := h.service.ListSettlementBatches(c.Request.Context(), uint64(siteID)) if err != nil { writeError(c, err) return } response.OK(c, gin.H{"items": items}) } func (h *Handler) CreateSettlementBatch(c *gin.Context) { adminID, ok := currentAdminID(c) if !ok { response.Unauthorized(c, "缺少管理员上下文") return } var req CreateSettlementBatchRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "结算周期参数不正确") return } item, err := h.service.CreateSettlementBatch(c.Request.Context(), adminID, req) if err != nil { writeError(c, err) return } response.Created(c, item) } func (h *Handler) MarkSettlementBatch(c *gin.Context) { id, ok := parseID(c) if !ok { return } item, err := h.service.MarkSettlementBatch(c.Request.Context(), id) if err != nil { writeError(c, err) return } response.OK(c, item) } // parseQueryUint 返回 -1 表示格式错误,0 表示未传入。 func parseQueryUint(c *gin.Context, key string) int64 { raw := strings.TrimSpace(c.Query(key)) if raw == "" { return 0 } id, err := strconv.ParseUint(raw, 10, 64) if err != nil || id == 0 { response.BadRequest(c, key+" 不正确") return -1 } return int64(id) } 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 && id > 0 } func parseID(c *gin.Context) (uint64, bool) { id, err := strconv.ParseUint(c.Param("id"), 10, 64) if err != nil || id == 0 { response.BadRequest(c, "ID 不正确") return 0, false } return id, true } func writeError(c *gin.Context, err error) { switch { case errors.Is(err, ErrSiteNotFound), errors.Is(err, ErrRuleNotFound), errors.Is(err, ErrOrderNotFound), errors.Is(err, ErrAccountDisplayNotFound), errors.Is(err, ErrPaymentChannelNotFound), errors.Is(err, ErrSettlementBatchNotFound): response.NotFound(c, "分销资源不存在") case errors.Is(err, ErrInvalidAmount), errors.Is(err, ErrInvalidRate), errors.Is(err, ErrInvalidServiceUnit), errors.Is(err, ErrUnsupportedMode), errors.Is(err, ErrInvalidOrderKind), errors.Is(err, ErrInvalidPeriod), errors.Is(err, ErrBatchAlreadySettled): response.BadRequest(c, "分销规则参数不正确") case errors.Is(err, ErrDependencyUnavailable): response.ServiceUnavailable(c, "分销服务暂时不可用") default: response.RecordError(c, err) response.Error(c, http.StatusInternalServerError, "distribution_error", "分销服务暂时不可用") } }