daShangDao_psiServer/controllers/product.go

543 lines
15 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package controllers
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"net/url"
"psi/constant"
"psi/database"
systemReq "psi/models/request"
systemRes "psi/models/response"
"psi/service"
"psi/utils"
"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)
}
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
}