拆分 service 与前端大文件,修复 CORS 配置与格式问题
- 后端 internal/service 按职责拆分: fulfillment.go(1397→527)拆出 wallet/timeout/data/order/query/dashboard/shipnotify delivery.go(1124→801)拆出 upstream/link/state/helpers merchant.go(855→251)拆出 member/product/api_client/catalog/helpers - 前端 MerchantCenter.tsx(1327→606)拆出 merchantCenterTabs/merchantCenterUtils - docker-compose backend 透传 CORS_ALLOWED_ORIGINS - CORS 白名单实现(config/router/README/.env.example 配套) - 修复 gofmt 与文件尾部多余空行
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"affiliate_dash/internal/model"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type CreateMerchantProductInput struct {
|
||||
ProductCode string
|
||||
ProductName string
|
||||
Category string
|
||||
Description string
|
||||
Attributes string
|
||||
SKU string
|
||||
DisplayName string
|
||||
PriceAmount int64
|
||||
CostAmount int64
|
||||
Currency string
|
||||
Stock int64
|
||||
Status string
|
||||
FulfillmentConfig string
|
||||
}
|
||||
|
||||
func (s *MerchantService) CreateMerchantProduct(merchantID uint, in CreateMerchantProductInput, actorUserID uint) (*model.MerchantProduct, error) {
|
||||
in.SKU = strings.TrimSpace(in.SKU)
|
||||
in.ProductCode = strings.TrimSpace(in.ProductCode)
|
||||
in.ProductName = strings.TrimSpace(in.ProductName)
|
||||
if in.SKU == "" {
|
||||
return nil, errors.New("商户商品 SKU 不能为空")
|
||||
}
|
||||
if in.PriceAmount < 0 || in.CostAmount < 0 {
|
||||
return nil, errors.New("商品金额不能小于零")
|
||||
}
|
||||
if in.Stock < -1 {
|
||||
return nil, errors.New("库存只能为 -1 或非负整数")
|
||||
}
|
||||
if in.Currency == "" {
|
||||
in.Currency = "POINT"
|
||||
}
|
||||
in.Currency = strings.ToUpper(in.Currency)
|
||||
if in.Status == "" {
|
||||
in.Status = model.ProductStatusActive
|
||||
}
|
||||
if in.Status != model.ProductStatusActive && in.Status != model.ProductStatusInactive {
|
||||
return nil, errors.New("无效的商品状态")
|
||||
}
|
||||
|
||||
merchantProduct := &model.MerchantProduct{}
|
||||
err := s.db.Transaction(func(tx *gorm.DB) error {
|
||||
var merchant model.Merchant
|
||||
if err := tx.Where("id = ? AND status = ?", merchantID, model.MerchantStatusActive).First(&merchant).Error; err != nil {
|
||||
return errors.New("商户不存在或已禁用")
|
||||
}
|
||||
product, err := ensureProduct(tx, in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
merchantProduct = &model.MerchantProduct{
|
||||
MerchantID: merchantID,
|
||||
ProductID: product.ID,
|
||||
SKU: in.SKU,
|
||||
DisplayName: fallbackName(in.DisplayName, product.Name),
|
||||
PriceAmount: in.PriceAmount,
|
||||
CostAmount: in.CostAmount,
|
||||
Currency: in.Currency,
|
||||
Stock: in.Stock,
|
||||
Status: in.Status,
|
||||
FulfillmentConfig: in.FulfillmentConfig,
|
||||
}
|
||||
if err := tx.Create(merchantProduct).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return writeAudit(tx, &merchantID, &actorUserID, nil, "merchant_product.create", "merchant_product", fmt.Sprint(merchantProduct.ID), map[string]string{"sku": in.SKU})
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return merchantProduct, nil
|
||||
}
|
||||
|
||||
func (s *MerchantService) ListMerchantProducts(merchantID uint, page, size int, activeOnly bool) ([]model.MerchantProduct, int64, error) {
|
||||
page, size = normalizePage(page, size)
|
||||
tx := s.db.Model(&model.MerchantProduct{}).Where("merchant_id = ?", merchantID)
|
||||
if activeOnly {
|
||||
tx = tx.Where("status = ?", model.ProductStatusActive)
|
||||
}
|
||||
var total int64
|
||||
if err := tx.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
var products []model.MerchantProduct
|
||||
err := tx.Preload("Product").Order("id DESC").Offset((page - 1) * size).Limit(size).Find(&products).Error
|
||||
return products, total, err
|
||||
}
|
||||
|
||||
type UpdateMerchantProductInput struct {
|
||||
DisplayName *string
|
||||
PriceAmount *int64
|
||||
CostAmount *int64
|
||||
Stock *int64
|
||||
Status *string
|
||||
FulfillmentConfig *string
|
||||
}
|
||||
|
||||
func (s *MerchantService) UpdateMerchantProduct(merchantID, id uint, in UpdateMerchantProductInput, actorUserID uint) error {
|
||||
updates := make(map[string]interface{})
|
||||
if in.DisplayName != nil {
|
||||
updates["display_name"] = *in.DisplayName
|
||||
}
|
||||
if in.PriceAmount != nil {
|
||||
if *in.PriceAmount < 0 {
|
||||
return errors.New("商品售价不能小于零")
|
||||
}
|
||||
updates["price_amount"] = *in.PriceAmount
|
||||
}
|
||||
if in.CostAmount != nil {
|
||||
if *in.CostAmount < 0 {
|
||||
return errors.New("商品成本不能小于零")
|
||||
}
|
||||
updates["cost_amount"] = *in.CostAmount
|
||||
}
|
||||
if in.Stock != nil {
|
||||
if *in.Stock < -1 {
|
||||
return errors.New("库存只能为 -1 或非负整数")
|
||||
}
|
||||
updates["stock"] = *in.Stock
|
||||
}
|
||||
if in.Status != nil {
|
||||
if *in.Status != model.ProductStatusActive && *in.Status != model.ProductStatusInactive {
|
||||
return errors.New("无效的商品状态")
|
||||
}
|
||||
updates["status"] = *in.Status
|
||||
}
|
||||
if in.FulfillmentConfig != nil {
|
||||
updates["fulfillment_config"] = *in.FulfillmentConfig
|
||||
}
|
||||
if len(updates) == 0 {
|
||||
return errors.New("没有可更新字段")
|
||||
}
|
||||
return s.db.Transaction(func(tx *gorm.DB) error {
|
||||
result := tx.Model(&model.MerchantProduct{}).Where("id = ? AND merchant_id = ?", id, merchantID).Updates(updates)
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
if result.RowsAffected == 0 {
|
||||
return errors.New("商户商品不存在")
|
||||
}
|
||||
return writeAudit(tx, &merchantID, &actorUserID, nil, "merchant_product.update", "merchant_product", fmt.Sprint(id), nil)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user