1.返回userlist

2.通过use_id,product_id 返回关联信息
This commit is contained in:
Administrator 2026-06-16 16:11:37 +08:00
parent 0eb07eec03
commit fafac05570
10 changed files with 622 additions and 40 deletions

View File

@ -327,3 +327,28 @@ func (r *EmployeeApi) GetUserList(c *gin.Context) {
"data": result, "data": result,
}) })
} }
// UpdateEmployeeSplitAccountConfigByAboutId 根据about_id更新员工分账配置ID
func (r *EmployeeApi) UpdateEmployeeSplitAccountConfigByAboutId(c *gin.Context) {
var req systemReq.UpdateEmployeeSplitAccountConfigRequest
if err := c.ShouldBind(&req); err != nil {
ValidAndFail(constant.LoggerChannelRequest, "更新员工分账配置请求参数异常", "参数错误: "+err.Error(), c, err)
return
}
// 获取当前用户信息
userInfo := utils.GetUserInfo(c)
result, err := employeeService.UpdateEmployeeSplitAccountConfigByAboutId(req, userInfo.Username)
if err != nil {
utils.ErrorLog(constant.LoggerChannelWork, logrus.Fields{
"source": "更新员工分账配置异常",
"err_msg": err.Error(),
})
systemRes.FailWithMessage(err.Error(), c)
return
}
systemRes.OkWithDetailed(result, "更新成功", c)
}

View File

@ -25,6 +25,19 @@ type Employee struct {
ExpireTime int64 `json:"expire_time" gorm:"not null;default:0;comment:过期时间"` ExpireTime int64 `json:"expire_time" gorm:"not null;default:0;comment:过期时间"`
} }
// UpdateEmployeeSplitAccountConfigResponse 更新员工分账配置响应
type UpdateEmployeeSplitAccountConfigResponse struct {
ID int64 `json:"id"`
EmployeeIDStr string `json:"employee_id_str"`
Username string `json:"username"`
Name string `json:"name"`
Phone string `json:"phone"`
AboutId int64 `json:"about_id"`
SplitAccountConfigId int64 `json:"split_account_config_id"`
Status int8 `json:"status"`
UpdatedAt int64 `json:"updated_at"`
}
func (Employee) TableName() string { func (Employee) TableName() string {
return "employees" return "employees"
} }

View File

@ -65,8 +65,25 @@ type SetEmployeeLevelRequest struct {
// GetUserListRequest 获取用户列表请求 // GetUserListRequest 获取用户列表请求
type GetUserListRequest struct { type GetUserListRequest struct {
Page int `form:"page"` Page int `form:"page"` // 页码
PageSize int `form:"page_size"` PageSize int `form:"page_size"` // 页大小
Keyword string `form:"keyword"` Username string `form:"username"` // 用户名
Status string `form:"status"` Tel string `form:"tel"` // 手机号
//Keyword string `form:"keyword"` // 关键词 注释将keyword改为 username 和 tel
Status string `form:"status"` // 状态
}
// GetUserListRequest 获取用户列表请求
/*type GetUserListRequest struct {
Page int `form:"page"` // 页码
PageSize int `form:"page_size"` // 页大小
Username string `form:"username"` // 用户名
Tel string `form:"tel"` // 手机号
Status string `form:"status"` // 状态
}*/
// UpdateEmployeeSplitAccountConfigRequest 根据about_id更新员工分账配置请求
type UpdateEmployeeSplitAccountConfigRequest struct {
AboutId int64 `form:"about_id" binding:"required"`
SplitAccountConfigId int64 `form:"split_account_config_id" binding:"required"`
} }

View File

@ -154,6 +154,7 @@ type DeleteProductLogRequest struct {
type GetProductInventoryRequest struct { type GetProductInventoryRequest struct {
UserID int64 `form:"user_id" binding:"required"` // 用户ID UserID int64 `form:"user_id" binding:"required"` // 用户ID
ProductID int64 `form:"product_id" binding:"required"` // 商品ID ProductID int64 `form:"product_id" binding:"required"` // 商品ID
Type int8 `form:"type"` // 类型: 0=原始数据, 1=按商品名称+ISBN+仓库聚合
} }
type GetShopProductDetailRequest struct { type GetShopProductDetailRequest struct {

View File

@ -1,6 +1,7 @@
package response package response
import ( import (
"encoding/json"
"psi/models" "psi/models"
) )
@ -109,6 +110,7 @@ type UserListItem struct {
Role int64 `json:"role"` Role int64 `json:"role"`
Status int8 `json:"status"` Status int8 `json:"status"`
SplitAccountConfigId int64 `json:"split_account_config_id"` SplitAccountConfigId int64 `json:"split_account_config_id"`
SplitAccountConfig *SplitAccountConfigInfo `json:"split_account_config,omitempty"` // 分账配置详情
} }
// GetUserListResponse 用户列表响应 // GetUserListResponse 用户列表响应
@ -118,3 +120,47 @@ type GetUserListResponse struct {
Page int `json:"page"` Page int `json:"page"`
PageSize int `json:"page_size"` PageSize int `json:"page_size"`
} }
// UpdateEmployeeSplitAccountConfigResponse 更新员工分账配置响应
type UpdateEmployeeSplitAccountConfigResponse struct {
ID int64 `json:"id"`
EmployeeIDStr string `json:"employee_id_str"`
Username string `json:"username"`
Name string `json:"name"`
Phone string `json:"phone"`
AboutId int64 `json:"about_id"`
SplitAccountConfigId int64 `json:"split_account_config_id"`
Status int8 `json:"status"`
UpdatedAt int64 `json:"updated_at"`
}
// CurrentUserResponse 当前用户信息响应(包含分账配置)
type CurrentUserResponse struct {
ID int64 `json:"id"`
EmployeeIDStr string `json:"employee_id_str"`
Username string `json:"username"`
Name string `json:"name"`
Phone string `json:"phone"`
Role int64 `json:"role"`
Fid int64 `json:"fid"`
AboutId int64 `json:"about_id"`
Status int8 `json:"status"`
Score int64 `json:"score"`
SplitAccountConfigId int64 `json:"split_account_config_id"`
SplitAccountConfig *SplitAccountConfigInfo `json:"split_account_config,omitempty"` // 分账配置详情
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
}
// SplitAccountConfigInfo 分账配置信息
type SplitAccountConfigInfo struct {
ID int64 `json:"id"`
RuleName string `json:"rule_name"`
RuleValue json.RawMessage `json:"rule_value"`
Status int8 `json:"status"`
Description string `json:"description"`
CreatedBy string `json:"created_by"`
UpdatedBy string `json:"updated_by"`
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
}

View File

@ -146,7 +146,8 @@ type ProductLogListResponse struct {
// ProductInventoryResponse 商品库存响应 // ProductInventoryResponse 商品库存响应
type ProductInventoryResponse struct { type ProductInventoryResponse struct {
Quantity int64 `json:"quantity"` Quantity int64 `json:"quantity"` // 总库存数量type=0时使用
Warehouses []ProductInventoryWarehouse `json:"warehouses,omitempty"` // 仓库列表type=1时使用
} }
// ShopProductDetailResponse 店铺商品详情响应 // ShopProductDetailResponse 店铺商品详情响应
@ -199,3 +200,14 @@ type ProductInShop struct {
CreatedAt int64 `json:"created_at"` // 创建时间 CreatedAt int64 `json:"created_at"` // 创建时间
UpdatedAt int64 `json:"updated_at"` // 更新时间 UpdatedAt int64 `json:"updated_at"` // 更新时间
} }
// ProductInventoryWarehouse 商品库存仓库信息
type ProductInventoryWarehouse struct {
WarehouseID int64 `json:"warehouse_id"` // 仓库ID
WarehouseName string `json:"warehouse_name"` // 仓库名称
WarehouseCode string `json:"warehouse_code"` // 仓库编码
ProductName string `json:"product_name"` // 商品名称
ISBN string `json:"isbn"` // ISBN/条码
Appearance int64 `json:"appearance"` // 品相
TotalQuantity int64 `json:"total_quantity"` // 该仓库下该商品的总库存
}

View File

@ -98,7 +98,7 @@ func initRouter() (r *gin.Engine) {
// 管理员 // 管理员
auth.GET("/user/current", employeeApi.GetCurrentUser) // 获取当前用户信息 auth.GET("/user/current", employeeApi.GetCurrentUser) // 获取当前用户信息
auth.POST("/logout", employeeApi.Logout) // 登出 auth.POST("/logout", employeeApi.Logout) // 登出
auth.POST("/userList", employeeApi.GetUserList) // 获取用户列表 auth.GET("/userList", employeeApi.GetUserList) // 获取用户列表
// 配置管理 // 配置管理
auth.GET("/config/list", configApi.GetConfigList) // 获取配置列表 auth.GET("/config/list", configApi.GetConfigList) // 获取配置列表
auth.GET("/config/detail/:id", configApi.GetConfigDetail) // 获取配置详情 auth.GET("/config/detail/:id", configApi.GetConfigDetail) // 获取配置详情
@ -261,6 +261,7 @@ func initRouter() (r *gin.Engine) {
admin.GET("/employee/check_expire_time", employeeApi.CheckExpireTimeEmployee) // 检查员工到期时间 admin.GET("/employee/check_expire_time", employeeApi.CheckExpireTimeEmployee) // 检查员工到期时间
admin.POST("/employee/set_level", employeeApi.SetEmployeeLevel) // 设置员工等级 admin.POST("/employee/set_level", employeeApi.SetEmployeeLevel) // 设置员工等级
admin.GET("/employee/level_config", employeeApi.GetLevelConfigList) // 获取员工等级配置列表 admin.GET("/employee/level_config", employeeApi.GetLevelConfigList) // 获取员工等级配置列表
admin.POST("/employee/update-split-account-config", employeeApi.UpdateEmployeeSplitAccountConfigByAboutId) // 根据about_id更新员工分账配置ID
// 用户类型管理 // 用户类型管理
admin.GET("/user-type/list", userTypeApi.GetUserTypeList) // 获取用户类型列表 admin.GET("/user-type/list", userTypeApi.GetUserTypeList) // 获取用户类型列表
admin.GET("/user-type/detail/:id", userTypeApi.GetUserTypeDetail) // 获取用户类型详情 admin.GET("/user-type/detail/:id", userTypeApi.GetUserTypeDetail) // 获取用户类型详情

View File

@ -839,7 +839,7 @@ func (s *EmployeeService) createEmployeeLevelLog(empId int64, operationType int8
} }
// GetUserList 获取用户列表(主库) // GetUserList 获取用户列表(主库)
func (s *EmployeeService) GetUserList(req systemReq.GetUserListRequest) (*systemRes.GetUserListResponse, error) { /*func (s *EmployeeService) GetUserList(req systemReq.GetUserListRequest) (*systemRes.GetUserListResponse, error) {
if req.Page < 1 { if req.Page < 1 {
req.Page = 1 req.Page = 1
} }
@ -888,3 +888,149 @@ func (s *EmployeeService) GetUserList(req systemReq.GetUserListRequest) (*system
PageSize: req.PageSize, PageSize: req.PageSize,
}, nil }, nil
} }
*/
func (s *EmployeeService) GetUserList(req systemReq.GetUserListRequest) (*systemRes.GetUserListResponse, error) {
if req.Page < 1 {
req.Page = 1
}
if req.PageSize < 1 || req.PageSize > 100 {
req.PageSize = 20
}
query := database.DB.Model(&models.Employee{}).Where("deleted_at = ?", 0)
if req.Status != "" {
query = query.Where("status = ?", req.Status)
}
if req.Username != "" {
query = query.Where("username LIKE ?", "%"+req.Username+"%")
}
if req.Tel != "" {
query = query.Where("phone LIKE ?", "%"+req.Tel+"%")
}
var total int64
if err := query.Count(&total).Error; err != nil {
return nil, utils.NewError("查询总数失败")
}
var employees []models.Employee
offset := (req.Page - 1) * req.PageSize
if err := query.Order("created_at DESC").Offset(offset).Limit(req.PageSize).Find(&employees).Error; err != nil {
return nil, utils.NewError("查询用户列表失败")
}
// 收集所有需要查询的分账配置ID
splitConfigIDs := make([]int64, 0)
for _, emp := range employees {
if emp.SplitAccountConfigId > 0 {
splitConfigIDs = append(splitConfigIDs, emp.SplitAccountConfigId)
}
}
// 批量查询分账配置
splitConfigMap := make(map[int64]*systemRes.SplitAccountConfigInfo)
if len(splitConfigIDs) > 0 {
var splitConfigs []models.SplitAccountConfig
database.DB.Where("id IN ? AND deleted_at = ?", splitConfigIDs, 0).Find(&splitConfigs)
for _, config := range splitConfigs {
splitConfigMap[config.ID] = &systemRes.SplitAccountConfigInfo{
ID: config.ID,
RuleName: config.RuleName,
RuleValue: json.RawMessage(config.RuleValue),
Status: config.Status,
Description: config.Description,
CreatedBy: config.CreatedBy,
UpdatedBy: config.UpdatedBy,
CreatedAt: config.CreatedAt,
UpdatedAt: config.UpdatedAt,
}
}
}
var items []systemRes.UserListItem
for _, emp := range employees {
item := systemRes.UserListItem{
ID: emp.ID,
EmployeeIDStr: emp.EmployeeIDStr,
Username: emp.Username,
Name: emp.Name,
Role: emp.Role,
Status: emp.Status,
SplitAccountConfigId: emp.SplitAccountConfigId,
}
// 如果有关联的分账配置,添加详情
if emp.SplitAccountConfigId > 0 {
if config, exists := splitConfigMap[emp.SplitAccountConfigId]; exists {
item.SplitAccountConfig = config
}
}
items = append(items, item)
}
return &systemRes.GetUserListResponse{
List: items,
Total: total,
Page: req.Page,
PageSize: req.PageSize,
}, nil
}
// UpdateEmployeeSplitAccountConfigByAboutId 根据about_id更新员工分账配置ID
func (s *EmployeeService) UpdateEmployeeSplitAccountConfigByAboutId(req systemReq.UpdateEmployeeSplitAccountConfigRequest, username string) (*systemRes.UpdateEmployeeSplitAccountConfigResponse, error) {
var employee models.Employee
result := database.DB.Where("about_id = ? AND deleted_at = ?", req.AboutId, 0).First(&employee)
if result.Error != nil {
return nil, utils.NewError("员工不存在")
}
updateData := map[string]interface{}{
"split_account_config_id": req.SplitAccountConfigId,
"updated_at": time.Now().Unix(),
}
if err := database.DB.Model(&employee).Updates(updateData).Error; err != nil {
return nil, utils.NewError("更新员工分账配置失败: " + err.Error())
}
// 重新查询更新后的员工数据
if err := database.DB.Where("id = ? AND deleted_at = ?", employee.ID, 0).First(&employee).Error; err != nil {
return nil, utils.NewError("查询更新后的员工数据失败")
}
return &systemRes.UpdateEmployeeSplitAccountConfigResponse{
ID: employee.ID,
EmployeeIDStr: employee.EmployeeIDStr,
Username: employee.Username,
Name: employee.Name,
Phone: employee.Phone,
AboutId: employee.AboutId,
SplitAccountConfigId: employee.SplitAccountConfigId,
Status: employee.Status,
UpdatedAt: employee.UpdatedAt,
}, nil
}
// ... existing code ...
/*func (s *EmployeeService) UpdateEmployeeSplitAccountConfigByAboutId(req systemReq.UpdateEmployeeSplitAccountConfigRequest, username string) error {
var employee models.Employee
result := database.DB.Where("about_id = ? AND deleted_at = ?", req.AboutId, 0).First(&employee)
if result.Error != nil {
return utils.NewError("员工不存在")
}
updateData := map[string]interface{}{
"split_account_config_id": req.SplitAccountConfigId,
"updated_at": time.Now().Unix(),
}
if err := database.DB.Model(&employee).Updates(updateData).Error; err != nil {
return utils.NewError("更新员工分账配置失败: " + err.Error())
}
return nil
}
*/

View File

@ -3974,12 +3974,7 @@ func (s *ProcessService) syncProductsToExternal(receivingOrderID, waveTaskID, us
group.totalQty += item.quantity group.totalQty += item.quantity
} else { } else {
// 新建ISBN组 // 新建ISBN组
var imgList []string imgList := parseImageList(product.LiveImage)
if product.LiveImage != nil && len(product.LiveImage) > 0 {
if err := json.Unmarshal(product.LiveImage, &imgList); err != nil {
return fmt.Errorf("解析json失败: %v", err)
}
}
skuCode := warehouse.Code skuCode := warehouse.Code
if item.locationID > 0 { if item.locationID > 0 {
@ -4046,12 +4041,7 @@ func (s *ProcessService) syncProductsToExternal(receivingOrderID, waveTaskID, us
} }
isbn := product.Barcode isbn := product.Barcode
var imgList []string imgList := parseImageList(product.LiveImage)
if product.LiveImage != nil && len(product.LiveImage) > 0 {
if err := json.Unmarshal(product.LiveImage, &imgList); err != nil {
return fmt.Errorf("解析json失败: %v", err)
}
}
skuCode := warehouse.Code skuCode := warehouse.Code
if item.locationID > 0 { if item.locationID > 0 {
@ -4379,3 +4369,34 @@ func getSalesStatusText(status int8) string {
return "未知状态" return "未知状态"
} }
} }
// parseImageList 解析图片列表支持JSON数组和逗号分隔字符串两种格式
func parseImageList(liveImage datatypes.JSON) []string {
if liveImage == nil || len(liveImage) == 0 {
return []string{}
}
// 尝试解析为字符串数组
var imgList []string
if err := json.Unmarshal(liveImage, &imgList); err == nil {
return imgList
}
// 如果解析失败,尝试解析为字符串,然后按逗号分割
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{}
}

View File

@ -651,18 +651,123 @@ 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,
@ -1443,7 +1548,8 @@ func (s *ProductService) PushProductToShop(req systemReq.PushProductToShopReques
}, nil }, nil
} }
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 {
@ -1527,6 +1633,89 @@ func (s *ProductService) batchPushProductBody(db *gorm.DB, outTask models.OutTas
}) })
} }
} }
*/
// 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{}{
"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),
})
}
}
// saveRetryLog 保存重试任务日志 // saveRetryLog 保存重试任务日志
func (s *ProductService) saveRetryLog(shopID, outTaskID, productID int64, product models.Product, waveTaskDetail models.WaveTaskDetail, hasWaveTask bool, msg string, db *gorm.DB) { func (s *ProductService) saveRetryLog(shopID, outTaskID, productID int64, product models.Product, waveTaskDetail models.WaveTaskDetail, hasWaveTask bool, msg string, db *gorm.DB) {
@ -1765,7 +1954,7 @@ 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 {
@ -1837,6 +2026,78 @@ func (s *ProductService) syncPriceToExternalTask(outTask models.OutTask, product
return nil 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{}{
"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
}
// saveOutTaskLog 保存外部任务日志 // saveOutTaskLog 保存外部任务日志
func (s *ProductService) saveOutTaskLog(outTask models.OutTask, productID int64, isbn string, liveImage []byte, stock, salePrice, cost int64, msg string, db *gorm.DB) { func (s *ProductService) saveOutTaskLog(outTask models.OutTask, productID int64, isbn string, liveImage []byte, stock, salePrice, cost int64, msg string, db *gorm.DB) {
@ -2687,6 +2948,45 @@ 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: