Files
affiliate_dash/backend/internal/handler/merchant_product.go
T
yml2213 ae71bc99b8 refactor(handler): 按业务域拆分 merchant.go(847 → 最大 182 行)
纯文件级移动,无行为变更:
- merchant.go            结构体、构造函数与跨域共用辅助(mapKeys/pageParams)
- merchant_product.go    商品目录与分配
- merchant_order.go      订单、人工/测试下单与发货链接
- merchant_wallet.go     钱包、积分流水与管理员调账
- merchant_api_client.go API 客户端与回调订阅
- merchant_member.go     成员与角色
- merchant_platform.go   平台侧租户管理

校验:与 HEAD 的声明行 diff 为空,MerchantHandler 方法数 41 → 41。
2026-10-06 19:43:13 +08:00

183 lines
6.0 KiB
Go

package handler
import (
"strconv"
"strings"
"affiliate_dash/internal/middleware"
"affiliate_dash/internal/model"
"affiliate_dash/internal/pkg/response"
"affiliate_dash/internal/service"
"github.com/gin-gonic/gin"
)
func (h *MerchantHandler) ListProducts(c *gin.Context) {
page, size := pageParams(c)
list, total, err := h.merchantSvc.ListMerchantProductsWithOptions(middleware.GetMerchantID(c), page, size, service.ListMerchantProductsOptions{
Status: strings.TrimSpace(c.Query("status")),
Keyword: strings.TrimSpace(c.Query("keyword")),
})
if err != nil {
if err.Error() == "无效的商品状态" {
response.BadRequest(c, err.Error())
return
}
response.ServerError(c, err.Error())
return
}
response.Page(c, list, total, page, size)
}
type merchantProductStatusReq struct {
Status string `json:"status" binding:"required"`
}
// UpdateProductStatus PATCH /api/merchant/products/:id/status
// 商户仅能上架/下架商品,价格、成本等配置由平台管理员维护。
// UpdateProduct PATCH /api/merchant/products/:id — 编辑商品(显示名称、售价、成本、库存、状态)。
// 严格风控门禁:仅平台超级管理员(model.RoleAdmin)拥有修改商品价格、成本、库存与名称的权限,普通分销商严禁修改。
func (h *MerchantHandler) UpdateProduct(c *gin.Context) {
if middleware.GetRole(c) != model.RoleAdmin {
response.Forbidden(c, "权限不足:仅平台超级管理员可编辑商品价格、成本与库存")
return
}
id, _ := strconv.ParseUint(c.Param("id"), 10, 64)
if id == 0 {
response.BadRequest(c, "参数错误")
return
}
var req merchantProductUpdateReq
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "参数错误")
return
}
if err := h.merchantSvc.UpdateMerchantProduct(middleware.GetMerchantID(c), uint(id), service.UpdateMerchantProductInput{
DisplayName: req.DisplayName,
PriceAmount: req.PriceAmount,
CostAmount: req.CostAmount,
Stock: req.Stock,
Status: req.Status,
FulfillmentConfig: req.FulfillmentConfig,
}, middleware.GetUserID(c)); err != nil {
response.BadRequest(c, err.Error())
return
}
response.OK(c, nil)
}
func (h *MerchantHandler) UpdateProductStatus(c *gin.Context) {
var req merchantProductStatusReq
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "参数错误:status 必填")
return
}
id, _ := strconv.ParseUint(c.Param("id"), 10, 64)
if err := h.merchantSvc.UpdateMerchantProduct(middleware.GetMerchantID(c), uint(id), service.UpdateMerchantProductInput{
Status: &req.Status,
}, middleware.GetUserID(c)); err != nil {
response.BadRequest(c, err.Error())
return
}
response.OK(c, nil)
}
// DeleteProduct DELETE /api/merchant/products/:id — 仅已下架可删(软删除)。
func (h *MerchantHandler) DeleteProduct(c *gin.Context) {
id, _ := strconv.ParseUint(c.Param("id"), 10, 64)
if err := h.merchantSvc.DeleteMerchantProduct(middleware.GetMerchantID(c), uint(id), middleware.GetUserID(c)); err != nil {
response.BadRequest(c, err.Error())
return
}
response.OK(c, nil)
}
// ListManualOrderProducts returns active products for order creation without granting product-management access.
func (h *MerchantHandler) ListManualOrderProducts(c *gin.Context) {
list, _, err := h.merchantSvc.ListMerchantProductsForClient(middleware.GetMerchantID(c), 1, 100)
if err != nil {
response.ServerError(c, err.Error())
return
}
response.OK(c, list)
}
// ListProductCatalog 返回自营商户的全部可售商品,作为平台默认商品目录供分配。
func (h *MerchantHandler) ListProductCatalog(c *gin.Context) {
list, err := h.merchantSvc.ListProductCatalog()
if err != nil {
response.ServerError(c, err.Error())
return
}
response.OK(c, list)
}
// ListMerchantProductsByAdmin 供平台管理员查看指定商户的可售商品。
func (h *MerchantHandler) ListMerchantProductsByAdmin(c *gin.Context) {
id, _ := strconv.ParseUint(c.Param("id"), 10, 64)
list, err := h.merchantSvc.ListMerchantProductsByAdmin(uint(id))
if err != nil {
response.ServerError(c, err.Error())
return
}
response.OK(c, list)
}
type merchantProductUpdateReq struct {
DisplayName *string `json:"display_name"`
PriceAmount *int64 `json:"price_amount"`
CostAmount *int64 `json:"cost_amount"`
Stock *int64 `json:"stock"`
Status *string `json:"status"`
FulfillmentConfig *string `json:"fulfillment_config"`
}
// AdminUpdateMerchantProduct 供平台管理员编辑指定商户的商品(价格、成本、库存、状态等)。
func (h *MerchantHandler) AdminUpdateMerchantProduct(c *gin.Context) {
merchantID, _ := strconv.ParseUint(c.Param("id"), 10, 64)
productID, _ := strconv.ParseUint(c.Param("pid"), 10, 64)
if merchantID == 0 || productID == 0 {
response.BadRequest(c, "参数错误")
return
}
var req merchantProductUpdateReq
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "参数错误")
return
}
if err := h.merchantSvc.UpdateMerchantProduct(uint(merchantID), uint(productID), service.UpdateMerchantProductInput{
DisplayName: req.DisplayName,
PriceAmount: req.PriceAmount,
CostAmount: req.CostAmount,
Stock: req.Stock,
Status: req.Status,
FulfillmentConfig: req.FulfillmentConfig,
}, middleware.GetUserID(c)); err != nil {
response.BadRequest(c, err.Error())
return
}
response.OK(c, nil)
}
type assignProductsReq struct {
CatalogIDs []uint `json:"catalog_ids"`
}
// AssignProducts 按商品目录 ID 批量同步商户的可售商品。
func (h *MerchantHandler) AssignProducts(c *gin.Context) {
id, _ := strconv.ParseUint(c.Param("id"), 10, 64)
var req assignProductsReq
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "参数错误")
return
}
count, err := h.merchantSvc.AssignProducts(uint(id), service.AssignProductsInput{
CatalogIDs: req.CatalogIDs,
}, middleware.GetUserID(c))
if err != nil {
response.BadRequest(c, err.Error())
return
}
response.OK(c, gin.H{"assigned": count})
}