优化管理后台

This commit is contained in:
2026-09-14 01:16:47 +08:00
parent 3e31cccae3
commit b80e7495b9
5 changed files with 68 additions and 5 deletions
+4
View File
@@ -51,6 +51,8 @@ type GoodsCreateRequest struct {
ValidDays int64 `json:"valid_days" binding:"omitempty,min=0,max=3650"`
Description string `json:"description" binding:"omitempty,max=500"`
Status int8 `json:"status" binding:"omitempty,oneof=1 2"`
ProductID string `json:"product_id" binding:"omitempty,max=64"` // 虚拟支付道具ID
ProductStatus int8 `json:"product_status" binding:"omitempty,oneof=0 2"` // 虚拟支付道具发布状态 0=未发布 2=已发布
}
// GoodsUpdateRequest 更新商品请求(传什么改什么)。
@@ -65,6 +67,8 @@ type GoodsUpdateRequest struct {
OutfitShareQuota *int64 `json:"outfit_share_quota" binding:"omitempty,min=0"`
ValidDays *int64 `json:"valid_days" binding:"omitempty,min=0,max=3650"`
Description *string `json:"description" binding:"omitempty,max=500"`
ProductID *string `json:"product_id" binding:"omitempty,max=64"` // 虚拟支付道具ID(传空串表示解除登记)
ProductStatus *int8 `json:"product_status" binding:"omitempty,oneof=0 2"` // 虚拟支付道具发布状态 0=未发布 2=已发布
}
// GoodsStatusRequest 商品上下架请求。
+13
View File
@@ -82,6 +82,19 @@ func (d *GoodsDao) GoodsGetByCode(ctx context.Context, code string) (*mysqlmodel
return &goods, nil
}
// GoodsGetByProductID 按虚拟支付道具 ID 查询商品(用于道具 ID 唯一性校验,不含软删)
func (d *GoodsDao) GoodsGetByProductID(ctx context.Context, productID string) (*mysqlmodel.Goods, error) {
ctx, span := global.Tracer.Start(ctx, "mysqldao.GoodsGetByProductID")
defer span.End()
var goods mysqlmodel.Goods
if err := d.db.WithContext(ctx).Where("product_id = ?", productID).First(&goods).Error; err != nil {
span.RecordError(err)
return nil, err
}
return &goods, nil
}
// GoodsCreate 创建商品
func (d *GoodsDao) GoodsCreate(ctx context.Context, goods *mysqlmodel.Goods) error {
ctx, span := global.Tracer.Start(ctx, "mysqldao.GoodsCreate")
+45 -1
View File
@@ -69,6 +69,19 @@ func (s *GoodsService) Create(ctx context.Context, adminID int64, request *dto.G
return nil, errcode.DatabaseError
}
// 虚拟支付道具登记校验:已发布必须有道具 ID;道具 ID 全局唯一(防两个商品指向同一微信道具导致发货金额校验失败)。
productID := strings.TrimSpace(request.ProductID)
if request.ProductStatus == GoodsProductPublished && productID == "" {
return nil, errcode.GoodsProductInvalid.WithDetails("发布状态为「已发布」时必须填写道具 ID")
}
if productID != "" {
if _, err := s.goodsDao.GoodsGetByProductID(ctx, productID); err == nil {
return nil, errcode.GoodsProductIDExists
} else if !isNotFound(err) {
return nil, errcode.DatabaseError
}
}
status := request.Status
if status == 0 {
status = GoodsStatusOffShelf // 新建默认下架,运营确认后再上架。
@@ -88,6 +101,8 @@ func (s *GoodsService) Create(ctx context.Context, adminID int64, request *dto.G
ValidDays: request.ValidDays,
Description: request.Description,
Status: status,
ProductID: productID,
ProductStatus: request.ProductStatus,
}
goods.CreatedBy = adminID
goods.UpdatedBy = adminID
@@ -104,13 +119,36 @@ func (s *GoodsService) Update(ctx context.Context, adminID int64, id int64, requ
ctx, span := global.Tracer.Start(ctx, "svc.AdminGoodsUpdate")
defer span.End()
if _, err := s.goodsDao.GoodsGetByID(ctx, id); err != nil {
existing, err := s.goodsDao.GoodsGetByID(ctx, id)
if err != nil {
if isNotFound(err) {
return errcode.GoodsNotFound
}
return errcode.DatabaseError
}
// 虚拟支付道具登记:以「现有值 + 本次改动」的最终态校验,防止只改其中一个字段绕过校验。
productID := existing.ProductID
if request.ProductID != nil {
productID = strings.TrimSpace(*request.ProductID)
}
productStatus := existing.ProductStatus
if request.ProductStatus != nil {
productStatus = *request.ProductStatus
}
if productStatus == GoodsProductPublished && productID == "" {
return errcode.GoodsProductInvalid.WithDetails("发布状态为「已发布」时必须填写道具 ID")
}
if request.ProductID != nil && productID != "" {
if other, derr := s.goodsDao.GoodsGetByProductID(ctx, productID); derr == nil {
if other.ID != id {
return errcode.GoodsProductIDExists
}
} else if !isNotFound(derr) {
return errcode.DatabaseError
}
}
updates := map[string]any{"updated_by": adminID}
if request.GoodsName != nil {
updates["goods_name"] = strings.TrimSpace(*request.GoodsName)
@@ -142,6 +180,12 @@ func (s *GoodsService) Update(ctx context.Context, adminID int64, id int64, requ
if request.Description != nil {
updates["description"] = *request.Description
}
if request.ProductID != nil {
updates["product_id"] = productID
}
if request.ProductStatus != nil {
updates["product_status"] = *request.ProductStatus
}
if len(updates) == 1 {
return nil // 无可更新字段。
}