2.从系统导出的excel数据,在外部对excel某一列进行更改时,新增的要回传到原来的地方;并对改动的地方进行覆盖。
3.销售单管理、出库管理、发货单三个接口里面展示第三方订单编号和快递单号
4.选择多个仓库时,只要选择发货单子就会报错
5.在这个/api/split-account-deduction-log/create接口里,当传参时,如果参数 total_amount 是0,则会报错 {"code":204,"data":{},"msg":"TotalAmount不能为空"} 0是金额数字,不能当空值进行判断(T)
传递参数created_by,没有往数据表里写入
6.商品销毁的同时写入日志,也能通过读取这个日志,还原销毁的商品。传出这个新增的接口
7.新增一个不需要签名认证的分帐扣钱日志列表接口,新增一个返回字段buniness_no,并对这个字段进行模糊查询。
测试接口:/open/split-account-deduction-log/list
8.增加个新接口:首先 调用 /api/sales-order/create 创建销售订单的时候会锁定库存,
现在我需要一个解锁库存的接口,传递参数是订单编号
POST /api/sales-order/unlock-inventory // 解锁销售订单库存
/api/split-account-deduction-log/update /api/sales-order/unlock-inventory 在这两个接口里不需要签名认证
/api/sales-order/unlock-inventory 在这个接口里面返回解锁的所有商品信息
/api/split-account-deduction-log/update 在这个接口里面的status也需要更改,status没有变化
726 lines
20 KiB
Go
726 lines
20 KiB
Go
package controllers
|
||
|
||
import (
|
||
"fmt"
|
||
"github.com/gin-gonic/gin"
|
||
"io"
|
||
"net/http"
|
||
"net/url"
|
||
"psi/constant"
|
||
"psi/database"
|
||
systemReq "psi/models/request"
|
||
systemRes "psi/models/response"
|
||
"psi/service"
|
||
"psi/utils"
|
||
"strconv"
|
||
"strings"
|
||
)
|
||
|
||
type ProductApi struct{}
|
||
|
||
var productService = service.ProductService{}
|
||
|
||
// GetProductList 获取商品列表
|
||
func (r *ProductApi) GetProductList(c *gin.Context) {
|
||
var req systemReq.GetProductListRequest
|
||
|
||
if err := c.ShouldBindQuery(&req); err != nil {
|
||
ValidAndFail(constant.LoggerChannelRequest, "商品列表请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
|
||
if len(req.IDs) == 0 {
|
||
ids, err := parseIds(c)
|
||
if err != nil {
|
||
systemRes.FailWithValidateMessage("参数错误: "+err.Error(), c)
|
||
return
|
||
}
|
||
req.IDs = ids
|
||
}
|
||
|
||
result, err := productService.GetProductList(req, database.GetDB(c))
|
||
if err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "商品列表异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"code": 200,
|
||
"data": result,
|
||
})
|
||
}
|
||
|
||
// GetDistributionProductList 获取分销商品列表
|
||
func (r *ProductApi) GetDistributionProductList(c *gin.Context) {
|
||
var req systemReq.GetDistributionProductListRequest
|
||
|
||
if err := c.ShouldBindQuery(&req); err != nil {
|
||
ValidAndFail(constant.LoggerChannelRequest, "分销商品列表请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
|
||
// Name支持双重编码:如果绑定后仍含%编码字符,再解码一次
|
||
if req.Name != "" && strings.Contains(req.Name, "%") {
|
||
if decoded, err := url.QueryUnescape(req.Name); err == nil {
|
||
req.Name = decoded
|
||
}
|
||
}
|
||
// StockOperator支持双重编码
|
||
if req.StockOperator != "" && strings.Contains(req.StockOperator, "%") {
|
||
if decoded, err := url.QueryUnescape(req.StockOperator); err == nil {
|
||
req.StockOperator = decoded
|
||
}
|
||
}
|
||
// SalePriceOperator支持双重编码
|
||
if req.SalePriceOperator != "" && strings.Contains(req.SalePriceOperator, "%") {
|
||
if decoded, err := url.QueryUnescape(req.SalePriceOperator); err == nil {
|
||
req.SalePriceOperator = decoded
|
||
}
|
||
}
|
||
|
||
result, err := productService.GetDistributionProductList(req)
|
||
if err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "分销商品列表异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"code": 200,
|
||
"data": result,
|
||
})
|
||
}
|
||
|
||
// GetProductDetail 获取商品详情
|
||
func (r *ProductApi) GetProductDetail(c *gin.Context) {
|
||
var req systemReq.GetProductDetailRequest
|
||
|
||
if err := c.ShouldBindQuery(&req); err != nil {
|
||
ValidAndFail(constant.LoggerChannelRequest, "商品详情请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
|
||
result, err := productService.GetProductDetail(req, database.GetDB(c))
|
||
if err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "商品详情异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"code": 200,
|
||
"data": result,
|
||
})
|
||
}
|
||
|
||
// GetProductFullInfo 获取商品完整信息(无需签名认证) - 从租户分库查询
|
||
func (r *ProductApi) GetProductFullInfo(c *gin.Context) {
|
||
var req systemReq.GetProductFullInfoRequest
|
||
|
||
fmt.Printf("========== 【接口入口】获取商品完整信息 ==========\n")
|
||
|
||
if err := c.ShouldBindQuery(&req); err != nil {
|
||
fmt.Printf("【参数验证失败】%v\n", err)
|
||
utils.InfoLog(constant.LoggerChannelRequest, map[string]interface{}{
|
||
"action": "获取商品完整信息参数验证失败",
|
||
"error": err.Error(),
|
||
})
|
||
systemRes.FailWithValidateMessage("参数错误: "+err.Error(), c)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("【参数验证通过】UserID(租户): %d, ProductID: %d\n", req.UserID, req.ProductID)
|
||
|
||
result, err := productService.GetProductFullInfo(req, database.GetDB(c))
|
||
if err != nil {
|
||
fmt.Printf("【查询失败】%v\n", err)
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "获取商品完整信息异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("【查询成功】返回商品完整信息\n")
|
||
fmt.Printf("========== 【接口完成】 ==========\n")
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"code": 200,
|
||
"data": result,
|
||
})
|
||
}
|
||
|
||
// SaveProduct 保存商品(添加或修改)
|
||
func (r *ProductApi) SaveProduct(c *gin.Context) {
|
||
var req systemReq.ProductRequest
|
||
|
||
fmt.Printf("【断点1】接收到保存商品请求\n")
|
||
if err := c.ShouldBind(&req); err != nil {
|
||
fmt.Printf("【断点2】参数绑定失败: %v\n", err)
|
||
ValidAndFail(constant.LoggerChannelRequest, "保存商品请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
fmt.Printf("【断点3】参数绑定成功, 商品信息: %+v\n", req)
|
||
if len(req.LiveImage) == 0 {
|
||
image, err := parseImageFromForm(c)
|
||
if err != nil {
|
||
systemRes.FailWithValidateMessage("参数错误: "+err.Error(), c)
|
||
return
|
||
}
|
||
req.LiveImage = image
|
||
}
|
||
id, err := productService.SaveProduct(req, database.GetDB(c))
|
||
if err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "保存商品异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
systemRes.OkWithDetailed(gin.H{"id": id}, "操作成功", c)
|
||
}
|
||
|
||
// UpdatePrice 修改商品售价
|
||
func (r *ProductApi) UpdatePrice(c *gin.Context) {
|
||
var req systemReq.UpdatePriceRequest
|
||
|
||
if err := c.ShouldBind(&req); err != nil {
|
||
ValidAndFail(constant.LoggerChannelRequest, "修改售价请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
|
||
if err := productService.UpdatePrice(req); err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "修改售价异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
systemRes.OkWithMessage("售价修改成功", c)
|
||
}
|
||
|
||
// DeleteProduct 删除商品
|
||
func (r *ProductApi) DeleteProduct(c *gin.Context) {
|
||
var req systemReq.DeleteProductRequest
|
||
|
||
if err := c.ShouldBind(&req); err != nil {
|
||
ValidAndFail(constant.LoggerChannelRequest, "删除商品请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
|
||
err := productService.DeleteProduct(req, database.GetDB(c))
|
||
if err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "删除商品异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
systemRes.OkWithMessage("删除成功", c)
|
||
}
|
||
|
||
// GetProductInventory 获取商品库存数量
|
||
func (r *ProductApi) GetProductInventory(c *gin.Context) {
|
||
var req systemReq.GetProductInventoryRequest
|
||
|
||
if err := c.ShouldBind(&req); err != nil {
|
||
ValidAndFail(constant.LoggerChannelRequest, "获取商品库存请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
|
||
result, err := productService.GetProductInventory(req)
|
||
if err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "获取商品库存异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"code": 200,
|
||
"data": result,
|
||
})
|
||
}
|
||
|
||
// RetryOutTask 重试失败的外部任务
|
||
func (r *ProductApi) RetryOutTask(c *gin.Context) {
|
||
var req systemReq.RetryOutTaskRequest
|
||
|
||
if err := c.ShouldBind(&req); err != nil {
|
||
ValidAndFail(constant.LoggerChannelRequest, "重试任务请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
|
||
if err := productService.RetryOutTask(req, database.GetDB(c)); err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "重试任务异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
systemRes.OkWithMessage("重试任务已提交", c)
|
||
}
|
||
|
||
// ExportProducts 导出商品到Excel
|
||
func (r *ProductApi) ExportProducts(c *gin.Context) {
|
||
var req systemReq.ExportProductRequest
|
||
|
||
if err := c.ShouldBindQuery(&req); err != nil {
|
||
ValidAndFail(constant.LoggerChannelRequest, "导出商品请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
|
||
result, err := productService.ExportProducts(req, database.GetDB(c))
|
||
if err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "导出商品异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"code": 200,
|
||
"data": result,
|
||
})
|
||
}
|
||
|
||
// PushProductToShop 上架到商铺:创建商品、库存记录,并推送到商铺
|
||
func (r *ProductApi) PushProductToShop(c *gin.Context) {
|
||
var req systemReq.PushProductToShopRequest
|
||
|
||
if err := c.ShouldBind(&req); err != nil {
|
||
ValidAndFail(constant.LoggerChannelRequest, "上架到商铺请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
|
||
// 处理photos参数: 如果表单未绑定,尝试从原始表单解析
|
||
if len(req.Photos) == 0 {
|
||
var photos []string
|
||
for i := 0; i < 20; i++ {
|
||
photoStr := c.PostForm(fmt.Sprintf("photos[%d]", i))
|
||
if photoStr == "" {
|
||
break
|
||
}
|
||
photos = append(photos, photoStr)
|
||
}
|
||
req.Photos = photos
|
||
}
|
||
|
||
result, err := productService.PushProductToShop(req)
|
||
if err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "上架到商铺异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"code": 200,
|
||
"data": result,
|
||
})
|
||
}
|
||
|
||
// BatchPushProducts 批量推送商品到多个店铺
|
||
func (r *ProductApi) BatchPushProducts(c *gin.Context) {
|
||
var req systemReq.BatchPushProductRequest
|
||
|
||
if err := c.ShouldBind(&req); err != nil {
|
||
ValidAndFail(constant.LoggerChannelRequest, "批量推送请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
|
||
if err := productService.BatchPushProducts(req); err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "批量推送异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
systemRes.OkWithMessage("批量推送完成", c)
|
||
}
|
||
|
||
/*func (r *ProductApi) BatchPushProducts(c *gin.Context) {
|
||
var req systemReq.BatchPushProductRequest
|
||
|
||
if err := c.ShouldBind(&req); err != nil {
|
||
utils.InfoLog(constant.LoggerChannelRequest, map[string]interface{}{
|
||
"action": "批量推送参数验证失败",
|
||
"error": err.Error(),
|
||
})
|
||
ValidAndFail(constant.LoggerChannelRequest, "批量推送请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
|
||
utils.InfoLog(constant.LoggerChannelWork, map[string]interface{}{
|
||
"action": "开始批量推送商品",
|
||
"shop_ids": req.ShopIDs,
|
||
"product_id": req.ProductID,
|
||
})
|
||
|
||
if err := productService.BatchPushProducts(req); err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "批量推送异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
utils.InfoLog(constant.LoggerChannelWork, map[string]interface{}{
|
||
"action": "批量推送完成",
|
||
"product_id": req.ProductID,
|
||
"success": true,
|
||
})
|
||
|
||
systemRes.OkWithMessage("批量推送完成", c)*/
|
||
|
||
// GetProductLogList 商品日志列表
|
||
func (r *ProductApi) GetProductLogList(c *gin.Context) {
|
||
var req systemReq.GetProductLogListRequest
|
||
|
||
if err := c.ShouldBindQuery(&req); err != nil {
|
||
ValidAndFail(constant.LoggerChannelRequest, "商品日志列表请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
|
||
userInfo := utils.GetUserInfo(c)
|
||
result, err := productService.GetProductLogList(req, userInfo.AboutID)
|
||
if err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "商品日志列表异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"code": 200,
|
||
"data": result,
|
||
})
|
||
}
|
||
|
||
// SaveProductLog 保存商品日志(添加或修改)
|
||
func (r *ProductApi) SaveProductLog(c *gin.Context) {
|
||
var req systemReq.ProductLogRequest
|
||
if err := c.ShouldBind(&req); err != nil {
|
||
ValidAndFail(constant.LoggerChannelRequest, "保存商品日志请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
|
||
if len(req.OldLiveImage) == 0 {
|
||
image, err := parseOldImageFromForm(c)
|
||
if err != nil {
|
||
systemRes.FailWithValidateMessage("参数错误: "+err.Error(), c)
|
||
return
|
||
}
|
||
req.OldLiveImage = image
|
||
}
|
||
|
||
if len(req.NewLiveImage) == 0 {
|
||
image, err := parseNewImageFromForm(c)
|
||
if err != nil {
|
||
systemRes.FailWithValidateMessage("参数错误: "+err.Error(), c)
|
||
return
|
||
}
|
||
req.NewLiveImage = image
|
||
}
|
||
|
||
userInfo := utils.GetUserInfo(c)
|
||
id, err := productService.SaveProductLog(req, userInfo.ID)
|
||
if err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "保存商品日志异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
systemRes.OkWithDetailed(gin.H{"id": id}, "操作成功", c)
|
||
}
|
||
|
||
// AuditProductLog 审核商品日志
|
||
func (r *ProductApi) AuditProductLog(c *gin.Context) {
|
||
var req systemReq.AuditProductLogRequest
|
||
|
||
if err := c.ShouldBind(&req); err != nil {
|
||
ValidAndFail(constant.LoggerChannelRequest, "审核商品日志请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
|
||
if len(req.NewLiveImage) == 0 {
|
||
image, err := parseNewImageFromForm(c)
|
||
if err != nil {
|
||
systemRes.FailWithValidateMessage("参数错误: "+err.Error(), c)
|
||
return
|
||
}
|
||
req.NewLiveImage = image
|
||
}
|
||
|
||
userInfo := utils.GetUserInfo(c)
|
||
if err := productService.AuditProductLog(req, userInfo.ID); err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "审核商品日志异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
systemRes.OkWithMessage("审核成功", c)
|
||
}
|
||
|
||
// DeleteProductLog 删除商品日志
|
||
func (r *ProductApi) DeleteProductLog(c *gin.Context) {
|
||
var req systemReq.DeleteProductLogRequest
|
||
|
||
if err := c.ShouldBind(&req); err != nil {
|
||
ValidAndFail(constant.LoggerChannelRequest, "删除商品日志请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
|
||
if err := productService.DeleteProductLog(req); err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "删除商品日志异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
systemRes.OkWithMessage("删除成功", c)
|
||
}
|
||
|
||
// GetShopProductDetail 获取店铺商品详情(包含商品数据和发送记录)
|
||
func (r *ProductApi) GetShopProductDetail(c *gin.Context) {
|
||
var req systemReq.GetShopProductDetailRequest
|
||
|
||
if err := c.ShouldBindQuery(&req); err != nil {
|
||
ValidAndFail(constant.LoggerChannelRequest, "获取店铺商品详情请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
|
||
result, err := productService.GetShopProductDetail(req, database.GetDB(c))
|
||
if err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "获取店铺商品详情异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"code": 200,
|
||
"data": result,
|
||
})
|
||
}
|
||
|
||
// parseIds 解析ID列表
|
||
func parseIds(c *gin.Context) ([]int64, error) {
|
||
var ids []int64
|
||
|
||
for i := 0; i < 100; i++ {
|
||
idStr := c.Query(fmt.Sprintf("ids[%d]", i))
|
||
if idStr == "" {
|
||
break
|
||
}
|
||
|
||
var id int64
|
||
if _, err := fmt.Sscanf(idStr, "%d", &id); err != nil {
|
||
return nil, fmt.Errorf("第%d个ID格式错误", i)
|
||
}
|
||
if id <= 0 {
|
||
return nil, fmt.Errorf("第%d个ID必须大于0", i)
|
||
}
|
||
ids = append(ids, id)
|
||
}
|
||
|
||
return ids, nil
|
||
}
|
||
|
||
// parseImageFromForm 解析图片列表
|
||
func parseImageFromForm(c *gin.Context) ([]string, error) {
|
||
var images []string
|
||
|
||
for i := 0; i < 10; i++ {
|
||
imageStr := c.PostForm(fmt.Sprintf("live_image[%d]", i))
|
||
if imageStr == "" {
|
||
break
|
||
}
|
||
|
||
images = append(images, imageStr)
|
||
}
|
||
// 如果解析到了数组格式,直接返回
|
||
if len(images) > 0 {
|
||
return images, nil
|
||
}
|
||
|
||
// 方式2: 尝试解析 liveimage 逗号分隔格式
|
||
liveimageStr := c.PostForm("liveimage")
|
||
if liveimageStr != "" {
|
||
// 按逗号分割
|
||
parts := strings.Split(liveimageStr, ",")
|
||
for _, part := range parts {
|
||
part = strings.TrimSpace(part)
|
||
if part != "" {
|
||
images = append(images, part)
|
||
}
|
||
}
|
||
return images, nil
|
||
}
|
||
|
||
// 方式3: 尝试解析 live_image 逗号分隔格式
|
||
liveImageStr := c.PostForm("live_image")
|
||
if liveImageStr != "" {
|
||
// 按逗号分割
|
||
parts := strings.Split(liveImageStr, ",")
|
||
for _, part := range parts {
|
||
part = strings.TrimSpace(part)
|
||
if part != "" {
|
||
images = append(images, part)
|
||
}
|
||
}
|
||
return images, nil
|
||
}
|
||
|
||
return images, nil
|
||
}
|
||
|
||
// parseOldImageFromForm 解析图片列表
|
||
func parseOldImageFromForm(c *gin.Context) ([]string, error) {
|
||
var images []string
|
||
|
||
for i := 0; i < 10; i++ {
|
||
imageStr := c.PostForm(fmt.Sprintf("old_live_image[%d]", i))
|
||
if imageStr == "" {
|
||
break
|
||
}
|
||
|
||
images = append(images, imageStr)
|
||
}
|
||
|
||
return images, nil
|
||
}
|
||
|
||
// parseNewImageFromForm 解析图片列表
|
||
func parseNewImageFromForm(c *gin.Context) ([]string, error) {
|
||
var images []string
|
||
|
||
for i := 0; i < 10; i++ {
|
||
imageStr := c.PostForm(fmt.Sprintf("new_live_image[%d]", i))
|
||
if imageStr == "" {
|
||
break
|
||
}
|
||
|
||
images = append(images, imageStr)
|
||
}
|
||
|
||
return images, nil
|
||
}
|
||
|
||
// UpdateProductNameAndImages 修改商品名称和实拍图
|
||
func (r *ProductApi) UpdateProductNameAndImages(c *gin.Context) {
|
||
var req systemReq.UpdateProductNameAndImagesRequest
|
||
|
||
if err := c.ShouldBind(&req); err != nil {
|
||
ValidAndFail(constant.LoggerChannelRequest, "修改商品信息请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
|
||
// 始终从表单解析图片参数,确保能接收到空数组或新图片
|
||
image, err := parseImageFromForm(c)
|
||
if err != nil {
|
||
systemRes.FailWithValidateMessage("参数错误: "+err.Error(), c)
|
||
return
|
||
}
|
||
// 如果解析到了图片,使用解析的结果;否则保留ShouldBind的结果
|
||
if len(image) > 0 || c.PostForm("live_image[0]") != "" {
|
||
req.LiveImage = image
|
||
}
|
||
|
||
fmt.Printf("【UpdateProductNameAndImages】最终请求参数 - ProductID: %d, Name: %s, LiveImage数量: %d, LiveImage: %+v\n",
|
||
req.ProductID, req.Name, len(req.LiveImage), req.LiveImage)
|
||
|
||
if err := productService.UpdateProductNameAndImages(req, database.GetDB(c)); err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "修改商品信息异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
systemRes.OkWithMessage("修改成功", c)
|
||
}
|
||
|
||
// ReimportProducts 将导出的Excel修改后重新导入(覆盖更新或新增)
|
||
func (r *ProductApi) ReimportProducts(c *gin.Context) {
|
||
warehouseIDStr := c.PostForm("warehouse_id")
|
||
if warehouseIDStr == "" {
|
||
systemRes.FailWithValidateMessage("warehouse_id不能为空", c)
|
||
return
|
||
}
|
||
warehouseID, err := strconv.ParseInt(warehouseIDStr, 10, 64)
|
||
if err != nil || warehouseID <= 0 {
|
||
systemRes.FailWithValidateMessage("warehouse_id格式错误", c)
|
||
return
|
||
}
|
||
|
||
file, _, err := c.Request.FormFile("file")
|
||
if err != nil {
|
||
systemRes.FailWithValidateMessage("请上传Excel文件", c)
|
||
return
|
||
}
|
||
defer file.Close()
|
||
|
||
fileBytes, err := io.ReadAll(file)
|
||
if err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelRequest, "商品回传导入-读取文件失败", err, c, nil)
|
||
return
|
||
}
|
||
|
||
result, err := productService.ReimportProducts(fileBytes, warehouseID, database.GetDB(c))
|
||
if err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "商品回传导入异常", err, c, nil)
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"code": 200,
|
||
"msg": "导入完成",
|
||
"data": result,
|
||
})
|
||
}
|
||
|
||
// DestroyProduct 销毁商品
|
||
func (r *ProductApi) DestroyProduct(c *gin.Context) {
|
||
var req systemReq.DestroyProductRequest
|
||
|
||
if err := c.ShouldBind(&req); err != nil {
|
||
ValidAndFail(constant.LoggerChannelRequest, "销毁商品请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
|
||
userInfo := utils.GetUserInfo(c)
|
||
logID, err := productService.DestroyProduct(req, userInfo.Username, userInfo.ID, database.GetDB(c))
|
||
if err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "销毁商品异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
systemRes.OkWithDetailed(gin.H{"destroy_log_id": logID}, "商品已销毁", c)
|
||
}
|
||
|
||
// RestoreProduct 还原商品
|
||
func (r *ProductApi) RestoreProduct(c *gin.Context) {
|
||
var req systemReq.RestoreProductRequest
|
||
|
||
if err := c.ShouldBind(&req); err != nil {
|
||
ValidAndFail(constant.LoggerChannelRequest, "还原商品请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
|
||
userInfo := utils.GetUserInfo(c)
|
||
if err := productService.RestoreProduct(req, userInfo.Username, userInfo.ID, database.GetDB(c)); err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "还原商品异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
systemRes.OkWithMessage("商品已还原", c)
|
||
}
|
||
|
||
// GetDestroyLogList 获取销毁日志列表
|
||
func (r *ProductApi) GetDestroyLogList(c *gin.Context) {
|
||
var req systemReq.GetDestroyLogListRequest
|
||
|
||
if err := c.ShouldBindQuery(&req); err != nil {
|
||
ValidAndFail(constant.LoggerChannelRequest, "销毁日志列表请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
|
||
result, err := productService.GetDestroyLogList(req, database.GetDB(c))
|
||
if err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "销毁日志列表异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"code": 200,
|
||
"data": result,
|
||
})
|
||
}
|
||
|
||
// GetDestroyLogDetail 获取销毁日志详情
|
||
func (r *ProductApi) GetDestroyLogDetail(c *gin.Context) {
|
||
var req systemReq.GetDestroyLogDetailRequest
|
||
|
||
if err := c.ShouldBindQuery(&req); err != nil {
|
||
ValidAndFail(constant.LoggerChannelRequest, "销毁日志详情请求参数异常", "参数错误: "+err.Error(), c, err)
|
||
return
|
||
}
|
||
|
||
result, err := productService.GetDestroyLogDetail(req, database.GetDB(c))
|
||
if err != nil {
|
||
utils.FailWithRequestLog(constant.LoggerChannelWork, "销毁日志详情异常", err, c, req)
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"code": 200,
|
||
"data": result,
|
||
})
|
||
}
|