修正了在向任务池发送任务时候提交实拍图片的格式

This commit is contained in:
xiaodongzhu825 2026-06-16 16:30:17 +08:00
parent fafac05570
commit 7923a99c77

View File

@ -383,6 +383,7 @@ func (s *ProductService) SaveProduct(req systemReq.ProductRequest, db ...*gorm.D
return s.createProduct(req, now, databaseConn) return s.createProduct(req, now, databaseConn)
} }
// createProduct 创建商品
func (s *ProductService) createProduct(req systemReq.ProductRequest, now int64, db *gorm.DB) (int64, error) { func (s *ProductService) createProduct(req systemReq.ProductRequest, now int64, db *gorm.DB) (int64, error) {
var liveImage datatypes.JSON var liveImage datatypes.JSON
@ -416,6 +417,7 @@ func (s *ProductService) createProduct(req systemReq.ProductRequest, now int64,
return product.ID, nil return product.ID, nil
} }
// updateProduct 修改商品
func (s *ProductService) updateProduct(req systemReq.ProductRequest, now int64, db *gorm.DB) (int64, error) { func (s *ProductService) updateProduct(req systemReq.ProductRequest, now int64, db *gorm.DB) (int64, error) {
var product models.Product var product models.Product
if err := db.Where("id = ? AND is_del = 0", req.ID).First(&product).Error; err != nil { if err := db.Where("id = ? AND is_del = 0", req.ID).First(&product).Error; err != nil {
@ -651,123 +653,18 @@ func (s *ProductService) UpdatePrice(req systemReq.UpdatePriceRequest) error {
return nil return nil
} }
//// GetProductInventory 获取商品库存数量 // GetProductInventory 获取商品库存数量
//func (s *ProductService) GetProductInventory(req systemReq.GetProductInventoryRequest) (*systemRes.ProductInventoryResponse, error) {
// databaseConn, err := database.GetTenantDB(req.UserID)
// if err != nil {
// return nil, fmt.Errorf("获取数据库连接失败: %v", err)
// }
//
// // 验证商品是否存在
// var product models.Product
// if err := databaseConn.Where("id = ? AND is_del = ?", req.ProductID, 0).First(&product).Error; err != nil {
// return nil, fmt.Errorf("商品不存在")
// }
//
// //// type=1: 按品相+ISBN+仓库聚合
// //if req.Type == 1 {
// // type warehouseStock struct {
// // WarehouseID int64 `gorm:"column:warehouse_id"`
// // WarehouseName string `gorm:"column:warehouse_name"`
// // WarehouseCode string `gorm:"column:warehouse_code"`
// // ProductName string `gorm:"column:product_name"`
// // ISBN string `gorm:"column:isbn"`
// // Appearance int64 `gorm:"column:appearance"`
// // TotalQuantity int64 `gorm:"column:total_quantity"`
// // }
// //
// // var warehouseList []warehouseStock
// // databaseConn.Table("inventory").
// // Select(`
// // inventory.warehouse_id,
// // w.name as warehouse_name,
// // w.code as warehouse_code,
// // p.name as product_name,
// // p.barcode as isbn,
// // p.appearance as appearance,
// // COALESCE(SUM(inventory.quantity), 0) as total_quantity
// // `).
// // Joins("LEFT JOIN warehouse w ON inventory.warehouse_id = w.id AND w.is_del = ?", 0).
// // Joins("LEFT JOIN product p ON inventory.product_id = p.id AND p.is_del = ?", 0).
// // Where("inventory.product_id = ? AND inventory.is_del = ?", req.ProductID, 0).
// // Group("inventory.warehouse_id, w.name, w.code, p.name, p.barcode, p.appearance").
// // Scan(&warehouseList)
// //
// // warehouses := make([]systemRes.ProductInventoryWarehouse, 0, len(warehouseList))
// // totalQuantity := int64(0)
// // for _, ws := range warehouseList {
// // warehouses = append(warehouses, systemRes.ProductInventoryWarehouse{
// // WarehouseID: ws.WarehouseID,
// // WarehouseName: ws.WarehouseName,
// // WarehouseCode: ws.WarehouseCode,
// // ProductName: ws.ProductName,
// // ISBN: ws.ISBN,
// // Appearance: ws.Appearance,
// // TotalQuantity: ws.TotalQuantity,
// // })
// // totalQuantity += ws.TotalQuantity
// // }
//
// return &systemRes.ProductInventoryResponse{
// Quantity: totalQuantity,
// //Warehouses: warehouses,
// }, nil
// }
//
// // type=0: 返回原始数据(总库存)
// var totalQuantity int64
// //databaseConn.Table("inventory").
// // Select("COALESCE(SUM(quantity), 0)").
// // Where("product_id = ? AND is_del = ?", req.ProductID, 0).
// // Scan(&totalQuantity)
//
// return &systemRes.ProductInventoryResponse{
// Quantity: totalQuantity,
// }, nil
//}
func (s *ProductService) GetProductInventory(req systemReq.GetProductInventoryRequest) (*systemRes.ProductInventoryResponse, error) { func (s *ProductService) GetProductInventory(req systemReq.GetProductInventoryRequest) (*systemRes.ProductInventoryResponse, error) {
databaseConn, err := database.GetTenantDB(req.UserID) databaseConn, err := database.GetTenantDB(req.UserID)
if err != nil { if err != nil {
return nil, fmt.Errorf("获取数据库连接失败: %v", err) return nil, fmt.Errorf("获取数据库连接失败: %v", err)
} }
// 验证商品是否存在,并获取商品信息
var product models.Product
if err := databaseConn.Where("id = ? AND is_del = ?", req.ProductID, 0).First(&product).Error; err != nil {
return nil, fmt.Errorf("商品不存在")
}
var totalQuantity int64 var totalQuantity int64
// type=1: 按品相+ISBN+仓库分组后统计总数量
if req.Type == 1 {
type GroupStock struct {
TotalQuantity int64 `gorm:"column:total_quantity"`
}
var groupList []GroupStock
// 先根据商品的 ISBN 和品相,查询所有匹配的库存记录,再按仓库分组统计
databaseConn.Table("inventory").
Select(`
COALESCE(SUM(inventory.quantity), 0) as total_quantity
`).
Joins("LEFT JOIN product p ON inventory.product_id = p.id AND p.is_del = ?", 0).
Where("p.barcode = ? AND p.appearance = ? AND inventory.warehouse_id IS NOT NULL AND inventory.is_del = ?",
product.Barcode, product.Appearance, 0).
Group("inventory.warehouse_id").
Scan(&groupList)
// 累加所有分组的数量
for _, group := range groupList {
totalQuantity += group.TotalQuantity
}
} else {
databaseConn.Table("inventory"). databaseConn.Table("inventory").
Select("COALESCE(SUM(quantity), 0)"). Select("COALESCE(SUM(quantity), 0)").
Where("product_id = ? AND is_del = ?", req.ProductID, 0). Where("product_id = ? AND is_del = ?", req.ProductID, 0).
Scan(&totalQuantity) Scan(&totalQuantity)
}
return &systemRes.ProductInventoryResponse{ return &systemRes.ProductInventoryResponse{
Quantity: totalQuantity, Quantity: totalQuantity,
@ -914,8 +811,7 @@ func (s *ProductService) RetryOutTask(req systemReq.RetryOutTaskRequest, db ...*
// BatchPushProducts 批量推送商品到多个店铺 // BatchPushProducts 批量推送商品到多个店铺
func (s *ProductService) BatchPushProducts(req systemReq.BatchPushProductRequest) error { func (s *ProductService) BatchPushProducts(req systemReq.BatchPushProductRequest) error {
fmt.Printf("[DEBUG BatchPushProducts] 入口 user_id=%d shop_ids=%v shop_types=%v product_ids=%v\n", fmt.Printf("[DEBUG BatchPushProducts] 入口 user_id=%d shop_ids=%v shop_types=%v product_ids=%v\n", req.UserID, req.ShopIDs, req.ShopTypes, req.ProductIDs)
req.UserID, req.ShopIDs, req.ShopTypes, req.ProductIDs)
utils.InfoLog(constant.LoggerChannelWork, map[string]interface{}{ utils.InfoLog(constant.LoggerChannelWork, map[string]interface{}{
"source": "批量推送-入口", "source": "批量推送-入口",
"user_id": req.UserID, "user_id": req.UserID,
@ -1548,100 +1444,28 @@ func (s *ProductService) PushProductToShop(req systemReq.PushProductToShopReques
}, nil }, nil
} }
// 批量上架 // batchPushProductBody 批量上架
/*func (s *ProductService) batchPushProductBody(db *gorm.DB, outTask models.OutTask, product models.Product, stock, salePrice, cost, now, userID int64, warehouseCode string, locationCode string, condition int64) { func (s *ProductService) batchPushProductBody(db *gorm.DB, outTask models.OutTask, product models.Product, stock, salePrice, cost, now, userID int64, warehouseCode string, locationCode string, condition int64) {
isbn := product.Barcode isbn := product.Barcode
var imgList []string var imgList []string
if product.LiveImage != nil && len(product.LiveImage) > 0 { if product.LiveImage != nil && len(product.LiveImage) > 0 {
if err := json.Unmarshal(product.LiveImage, &imgList); err != nil { var rawImgList []string
if err := json.Unmarshal(product.LiveImage, &rawImgList); err != nil {
s.saveOutTaskLogWithStock(outTask, product.ID, isbn, product.LiveImage, stock, salePrice, cost, fmt.Sprintf("解析图片失败: %v", err), db) s.saveOutTaskLogWithStock(outTask, product.ID, isbn, product.LiveImage, stock, salePrice, cost, fmt.Sprintf("解析图片失败: %v", err), db)
return return
} }
for _, imgStr := range rawImgList {
urls := strings.Split(imgStr, ",")
for _, url := range urls {
url = strings.TrimSpace(url)
if url != "" {
imgList = append(imgList, url)
} }
msgData := map[string]interface{}{
"product_id": product.ID,
"user_id": strconv.FormatInt(userID, 10),
"is_distribution": "1",
} }
msgJSON, _ := json.Marshal(msgData)
bodyData := map[string]interface{}{
"book_info": map[string]interface{}{
"isbn": isbn,
"image_object": map[string]interface{}{
"carousel_url_array": imgList,
},
},
"detail": map[string]interface{}{
"stock": stock,
"price": salePrice,
"shipping_cost": cost,
"msg": string(msgJSON),
"sku_code": warehouseCode + "##" + locationCode,
"condition": condition,
},
} }
bodyDataJSON, err := json.Marshal(bodyData)
if err != nil {
s.saveOutTaskLogWithStock(outTask, product.ID, isbn, product.LiveImage, stock, salePrice, cost, fmt.Sprintf("序列化请求体失败: %v", err), db)
return
} }
bodyList := []string{string(bodyDataJSON)}
taskID := fmt.Sprintf("%d", outTask.OutTaskID)
allBody := strings.Join(bodyList, "")
signParams := map[string]string{
"task_id": taskID,
"body": allBody,
}
sign := utils.SignParams(signParams)
url := config.AppConfig.ExternalAPI.SyncTaskBodyURL
resp, err := utils.SubmitMultiBody(url, taskID, bodyList, sign)
if err != nil {
s.saveOutTaskLogWithStock(outTask, product.ID, isbn, product.LiveImage, stock, salePrice, cost, fmt.Sprintf("请求外部接口失败: %v", err), db)
return
}
var resData systemRes.ExternalAPIResponse
if err := json.Unmarshal([]byte(resp), &resData); err != nil {
s.saveOutTaskLogWithStock(outTask, product.ID, isbn, product.LiveImage, stock, salePrice, cost, fmt.Sprintf("解析响应失败: %v", err), db)
return
}
if resData.Code != "200" {
s.saveOutTaskLogWithStock(outTask, product.ID, isbn, product.LiveImage, stock, salePrice, cost, fmt.Sprintf("外部接口返回错误: code=%s, msg=%s", resData.Code, resData.Msg), db)
return
}
if updateErr := db.Model(&models.OutTaskLog{}).
Where("shop_id = ? AND product_id = ? AND is_del = ?", outTask.ShopID, product.ID, 0).
Updates(map[string]interface{}{
"status": 1,
"msg": "成功",
"updated_at": now,
}).Error; updateErr != nil {
utils.ErrorLog(constant.LoggerChannelWork, map[string]interface{}{
"source": "批量推送-更新历史日志状态失败",
"shop_id": outTask.ShopID,
"product_id": product.ID,
"error": fmt.Sprintf("更新失败: %v", updateErr),
})
}
}
*/
// batchPushProductBody 批量上架商品到外部任务
func (s *ProductService) batchPushProductBody(db *gorm.DB, outTask models.OutTask, product models.Product, stock, salePrice, cost, now, userID int64, warehouseCode string, locationCode string, condition int64) {
isbn := product.Barcode
// 使用 parseImageList 解析图片列表,支持多种格式
imgList := s.parseImageList(product.LiveImage)
msgData := map[string]interface{}{ msgData := map[string]interface{}{
"product_id": product.ID, "product_id": product.ID,
"user_id": strconv.FormatInt(userID, 10), "user_id": strconv.FormatInt(userID, 10),
@ -1765,9 +1589,20 @@ func (s *ProductService) syncPriceToExternalTaskWithOptionalWave(outTask models.
isbn := product.Barcode isbn := product.Barcode
var imgList []string var imgList []string
if product.LiveImage != nil && len(product.LiveImage) > 0 { if product.LiveImage != nil && len(product.LiveImage) > 0 {
if err := json.Unmarshal(product.LiveImage, &imgList); err != nil { var rawImgList []string
if err := json.Unmarshal(product.LiveImage, &rawImgList); err != nil {
return fmt.Errorf("解析json失败: %v", err) return fmt.Errorf("解析json失败: %v", err)
} }
for _, imgStr := range rawImgList {
urls := strings.Split(imgStr, ",")
for _, url := range urls {
url = strings.TrimSpace(url)
if url != "" {
imgList = append(imgList, url)
}
}
}
} }
msgData := map[string]interface{}{ msgData := map[string]interface{}{
@ -1954,87 +1789,26 @@ func (s *ProductService) syncPriceToExternal(waveTaskDetail models.WaveTaskDetai
} }
// syncPriceToExternalTask 同步售价到单个外部任务 // syncPriceToExternalTask 同步售价到单个外部任务
/*func (s *ProductService) syncPriceToExternalTask(outTask models.OutTask, product models.Product, waveTaskDetail models.WaveTaskDetail, salePrice, cost, userId int64, db *gorm.DB) error { func (s *ProductService) syncPriceToExternalTask(outTask models.OutTask, product models.Product, waveTaskDetail models.WaveTaskDetail, salePrice, cost, userId int64, db *gorm.DB) error {
isbn := product.Barcode isbn := product.Barcode
var imgList []string var imgList []string
if product.LiveImage != nil && len(product.LiveImage) > 0 { if product.LiveImage != nil && len(product.LiveImage) > 0 {
if err := json.Unmarshal(product.LiveImage, &imgList); err != nil { var rawImgList []string
if err := json.Unmarshal(product.LiveImage, &rawImgList); err != nil {
return fmt.Errorf("解析json失败: %v", err) return fmt.Errorf("解析json失败: %v", err)
} }
for _, imgStr := range rawImgList {
urls := strings.Split(imgStr, ",")
for _, url := range urls {
url = strings.TrimSpace(url)
if url != "" {
imgList = append(imgList, url)
} }
msgData := map[string]interface{}{
"product_id": product.ID,
"user_id": fmt.Sprintf("%d", userId),
} }
msgJSON, _ := json.Marshal(msgData)
bodyData := map[string]interface{}{
"book_info": map[string]interface{}{
"isbn": isbn,
"image_object": map[string]interface{}{
"carousel_url_array": imgList,
},
},
"detail": map[string]interface{}{
"stock": waveTaskDetail.PlannedQuantity,
"price": salePrice,
"shipping_cost": cost,
"msg": string(msgJSON),
},
} }
bodyDataJSON, err := json.Marshal(bodyData)
if err != nil {
return fmt.Errorf("序列化请求体失败: %v", err)
} }
bodyList := []string{
string(bodyDataJSON),
}
taskID := fmt.Sprintf("%d", outTask.OutTaskID)
allBody := strings.Join(bodyList, "") // 直接无缝拼接(和服务端一致)
signParams := map[string]string{
"task_id": taskID,
"body": allBody,
}
sign := utils.SignParams(signParams)
// 发送请求
url := config.AppConfig.ExternalAPI.SyncTaskBodyURL
resp, err := utils.SubmitMultiBody(url, taskID, bodyList, sign)
if err != nil {
s.saveOutTaskLog(outTask, product.ID, isbn, product.LiveImage, waveTaskDetail.PlannedQuantity, salePrice, cost, fmt.Sprintf("请求外部接口失败: %v", err), db)
return fmt.Errorf("请求外部接口失败: %v", err)
}
var resData systemRes.ExternalAPIResponse
if err := json.Unmarshal([]byte(resp), &resData); err != nil {
return fmt.Errorf("解析响应失败: %v", err)
}
if resData.Code != "200" {
s.saveOutTaskLog(outTask, product.ID, isbn, product.LiveImage, waveTaskDetail.PlannedQuantity, salePrice, cost, fmt.Sprintf("外部接口返回错误: code=%s, msg=%s", resData.Code, resData.Msg), db)
return fmt.Errorf("外部接口返回错误: code=%s, msg=%s", resData.Code, resData.Msg)
}
s.saveOutTaskLog(outTask, product.ID, isbn, product.LiveImage, waveTaskDetail.PlannedQuantity, salePrice, cost, "成功", db)
return nil
}
*/
// syncPriceToExternalTask 同步售价到单个外部任务
func (s *ProductService) syncPriceToExternalTask(outTask models.OutTask, product models.Product, waveTaskDetail models.WaveTaskDetail, salePrice, cost, userId int64, db *gorm.DB) error {
isbn := product.Barcode
// 使用 parseImageList 解析图片列表,支持多种格式
imgList := s.parseImageList(product.LiveImage)
msgData := map[string]interface{}{ msgData := map[string]interface{}{
"product_id": product.ID, "product_id": product.ID,
"user_id": fmt.Sprintf("%d", userId), "user_id": fmt.Sprintf("%d", userId),
@ -2314,6 +2088,7 @@ func (s *ProductService) ExportProducts(req systemReq.ExportProductRequest, db .
}, nil }, nil
} }
// GetProductLogList 导出商品
func (s *ProductService) GetProductLogList(req systemReq.GetProductLogListRequest, aboutID int64) (*systemRes.ProductLogListResponse, error) { func (s *ProductService) GetProductLogList(req systemReq.GetProductLogListRequest, aboutID int64) (*systemRes.ProductLogListResponse, error) {
// TODO // TODO
//if aboutID != 0 { //if aboutID != 0 {
@ -2948,45 +2723,6 @@ func (s *ProductService) convertProductLogToItem(log models.ProductLog) systemRe
} }
} }
// parseImageList 解析图片列表支持JSON数组和逗号分隔字符串两种格式
func (s *ProductService) parseImageList(liveImage datatypes.JSON) []string {
if liveImage == nil || len(liveImage) == 0 {
return []string{}
}
// 尝试解析为字符串数组
var imgList []string
if err := json.Unmarshal(liveImage, &imgList); err == nil {
// 成功解析为数组,过滤空字符串后返回
result := make([]string, 0, len(imgList))
for _, img := range imgList {
trimmed := strings.TrimSpace(img)
if trimmed != "" {
result = append(result, trimmed)
}
}
return result
}
// 如果解析失败,尝试解析为字符串,然后按逗号分割
var imgStr string
if err := json.Unmarshal(liveImage, &imgStr); err == nil {
// 去除空格并按逗号分割
parts := strings.Split(imgStr, ",")
result := make([]string, 0, len(parts))
for _, part := range parts {
trimmed := strings.TrimSpace(part)
if trimmed != "" {
result = append(result, trimmed)
}
}
return result
}
// 都不成功,返回空数组
return []string{}
}
func (s *ProductService) getShopTypeName(shopType int8) string { func (s *ProductService) getShopTypeName(shopType int8) string {
switch shopType { switch shopType {
case 1: case 1: