daShangDao_getErpSendPublis.../controller/moveRepeat.go
2026-06-15 16:18:50 +08:00

647 lines
17 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 controller
import (
"context"
"crypto/md5"
"fmt"
"getErpSendPublishing/utils"
"getErpSendPublishing/utils/dbConnectUtil"
"log"
"net/http"
"strconv"
"strings"
"github.com/gin-gonic/gin"
)
// GoodsFormRequest 定义接收的表单数据结构
type GoodsFormRequest struct {
ShopID int64 `form:"shopid" binding:"required,min=1"` // 店铺ID必须大于0
GoodsID int64 `form:"goodsid" binding:"required,min=1"` // 商品ID必须大于0
ISBN string `form:"isbn" binding:"required"` // ISBN必须提供
}
// CenterBookBatchItem 批量提交的单个商品数据结构
type CenterBookBatchItem struct {
ISBN string `json:"isbn"`
TotalPrice string `json:"totalPrice"`
ImgBigUrl string `json:"imgBigUrl"`
}
// GoodsController 控制器结构
type GoodsController struct {
// 可以在这里注入服务层依赖
}
// BatchProcessCenterBooks 批量处理中心图书数据
func BatchProcessCenterBooks(ctx *gin.Context) {
// 1. 直接获取参数
shopIDStr := ctx.PostForm("shopid")
// 2. 空值检查
if shopIDStr == "" {
log.Printf("[WARN] shopid参数为空 (路径: %s, IP: %s)",
ctx.FullPath(), ctx.ClientIP())
ctx.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "shopid不能为空",
"success": false,
})
return
}
// 3. 转换并验证shopid格式
shopID, err := strconv.ParseInt(shopIDStr, 10, 64)
if err != nil || shopID <= 0 {
log.Printf("[WARN] 无效的shopid: %s (错误: %v)", shopIDStr, err)
ctx.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "shopid必须为正整数",
"success": false,
})
return
}
// 4. 解析JSON请求体中的图书列表
var bookItems []CenterBookBatchItem
if err := ctx.BindJSON(&bookItems); err != nil {
log.Printf("[WARN] JSON解析失败: %v (路径: %s, IP: %s)",
err, ctx.FullPath(), ctx.ClientIP())
ctx.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "JSON格式错误",
"success": false,
})
return
}
// 5. 检查图书列表是否为空
if len(bookItems) == 0 {
log.Printf("[WARN] 图书列表为空 (shopid: %d)", shopID)
ctx.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "图书列表不能为空",
"success": false,
})
return
}
// 6. 使用全局的Redis连接池避免每次创建新连接
redisClient := utils.RedisTwoForParseFormData
if redisClient == nil {
log.Printf("[ERROR] Redis连接未初始化")
ctx.JSON(http.StatusInternalServerError, gin.H{
"code": 500,
"message": "系统内部错误",
"success": false,
})
return
}
// 7. 构建Redis key
redisKey := fmt.Sprintf("%d", shopID)
// 8. 去重处理遍历图书列表移除重复的ISBN
var deduplicatedItems []CenterBookBatchItem
var skippedItems []CenterBookBatchItem
for _, item := range bookItems {
// 检查ISBN是否为空
if item.ISBN == "" {
log.Printf("[WARN] 发现空的ISBN跳过处理 (shopid: %d)", shopID)
continue
}
// 生成MD5加密的ISBN
hash := md5.Sum([]byte(item.ISBN))
encryptedIsbn := fmt.Sprintf("%x", hash)
// 检查是否存在重复数据
exists, err := redisClient.HGet(redisKey, encryptedIsbn)
if err == nil && exists != "" {
// 存在重复数据,记录并跳过
log.Printf("[INFO] 检测到重复数据: shopid=%d, isbn=%s", shopID, item.ISBN)
skippedItems = append(skippedItems, item)
continue
}
// 非重复数据,添加到去重后列表
deduplicatedItems = append(deduplicatedItems, item)
}
// 9. 如果没有有效数据,返回错误
if len(deduplicatedItems) == 0 {
log.Printf("[INFO] 所有数据均为重复数据,无有效处理项 (shopid: %d)", shopID)
ctx.JSON(http.StatusOK, gin.H{
"code": 1,
"message": "所有数据均为重复数据",
"success": false,
"data": gin.H{
"total": len(bookItems),
"skipped": len(skippedItems),
"processed": 0,
"original_items": bookItems,
"deduplicated_items": deduplicatedItems,
"skipped_items": skippedItems,
},
})
return
}
// 10. 关键成功日志
log.Printf("[INFO] 批量处理图书数据: shopid=%d, 总数=%d, 去重后=%d, 跳过=%d",
shopID, len(bookItems), len(deduplicatedItems), len(skippedItems))
// 11. 返回结果
ctx.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
"success": true,
"data": gin.H{
"shopid": shopID,
"total": len(bookItems),
"deduplicated_count": len(deduplicatedItems),
"skipped_count": len(skippedItems),
"original_items": bookItems,
"deduplicated_items": deduplicatedItems,
"skipped_items": skippedItems,
},
})
}
// validateGoodsRequest 业务层面的验证
func (c *GoodsController) validateGoodsRequest(ctx context.Context, req *GoodsFormRequest) error {
// 基础验证
if req.ShopID <= 0 {
return fmt.Errorf("店铺ID必须大于0")
}
if req.GoodsID <= 0 {
return fmt.Errorf("商品ID必须大于0")
}
if req.ISBN == "" {
return fmt.Errorf("ISBN不能为空")
}
// 业务限制(根据实际情况调整)
if req.ShopID > 1000000000 {
return fmt.Errorf("店铺ID超出系统限制")
}
if req.GoodsID > 1000000000 {
return fmt.Errorf("商品ID超出系统限制")
}
// ISBN长度限制
if len(req.ISBN) > 20 {
return fmt.Errorf("ISBN长度超出限制")
}
return nil
}
// ParseFormData 表单解析
func ParseFormData(ctx *gin.Context) {
// 1. 直接获取参数
shopIDStr := ctx.PostForm("shopid")
isbn := ctx.PostForm("isbn")
// 2. 空值检查(移除了 goodsid
if shopIDStr == "" || isbn == "" {
log.Printf("[WARN] 参数为空 (路径: %s, IP: %s)",
ctx.FullPath(), ctx.ClientIP())
ctx.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "shopid和isbn不能为空",
"success": false,
})
return
}
// 3. 转换并验证数字格式(只保留 shopid 验证)
shopID, err := strconv.ParseInt(shopIDStr, 10, 64)
if err != nil || shopID <= 0 {
log.Printf("[WARN] 无效的shopid: %s (错误: %v)", shopIDStr, err)
ctx.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "shopid必须为正整数",
"success": false,
})
return
}
// 4. 使用全局的Redis连接池避免每次创建新连接
redisClient := utils.RedisTwoForParseFormData
if redisClient == nil {
log.Printf("[ERROR] Redis连接未初始化")
ctx.JSON(http.StatusInternalServerError, gin.H{
"code": 500,
"message": "系统内部错误",
"success": false,
})
return
}
// 5. 生成MD5加密的ISBN
hash := md5.Sum([]byte(isbn))
encryptedIsbn := fmt.Sprintf("%x", hash)
//fmt.Println("encryptedIsbn:", encryptedIsbn)
// 6. 构建Redis key
redisKey := fmt.Sprintf("%d", shopID)
// 7. 检查是否存在重复数据
exists, err := redisClient.HGet(redisKey, encryptedIsbn)
if err == nil && exists != "" {
// 存在重复数据
log.Printf("[INFO] 检测到重复数据: shopid=%d, isbn=%s", shopID, isbn)
ctx.JSON(http.StatusOK, gin.H{
"code": 1,
"message": "已有重复数据",
"success": false,
})
return
}
// 8. 关键成功日志
log.Printf("[INFO] 表单数据解析成功: shopid=%d, isbn=%s", shopID, isbn)
// 9. 返回结果
ctx.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
"data": gin.H{
"shopid": shopID,
"isbn": isbn,
},
"success": true,
})
}
// NewParseFormData 处理包含更多参数的表单数据
func NewParseFormData(ctx *gin.Context) {
// 1. 直接获取参数
shopIDStr := ctx.PostForm("shopId")
isbn := ctx.PostForm("isbn")
shopType := ctx.PostForm("shopType")
price := ctx.PostForm("price")
condition := ctx.PostForm("condition")
// 2. 空值检查
if shopIDStr == "" || isbn == "" {
log.Printf("[WARN] 参数为空 (路径: %s, IP: %s)",
ctx.FullPath(), ctx.ClientIP())
ctx.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "shopId和isbn不能为空",
"success": false,
})
return
}
// 3. 转换并验证数字格式
shopID, err := strconv.ParseInt(shopIDStr, 10, 64)
if err != nil || shopID <= 0 {
log.Printf("[WARN] 无效的shopId: %s (错误: %v)", shopIDStr, err)
ctx.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "shopId必须为正整数",
"success": false,
})
return
}
// 4. 使用全局的Redis连接池避免每次创建新连接
redisClient := utils.RedisTwoForParseFormData
if redisClient == nil {
log.Printf("[ERROR] Redis连接未初始化")
ctx.JSON(http.StatusInternalServerError, gin.H{
"code": 500,
"message": "系统内部错误",
"success": false,
})
return
}
// 5. 构建Redis key
redisKey := fmt.Sprintf("%d", shopID)
// 6. 根据shopType生成不同的加密key
var encryptedKey string
switch shopType {
case "1", "5":
// shopType为1或5时使用ISBN的MD5
hash := md5.Sum([]byte(isbn))
encryptedKey = fmt.Sprintf("%x", hash)
case "2":
// shopType为2时拼接isbn:price:condition后MD5
combinedKey := fmt.Sprintf("%s:%s:%s", isbn, price, condition)
hash := md5.Sum([]byte(combinedKey))
encryptedKey = fmt.Sprintf("%x", hash)
default:
// 其他情况默认使用ISBN的MD5
hash := md5.Sum([]byte(isbn))
encryptedKey = fmt.Sprintf("%x", hash)
}
// 7. 检查是否存在重复数据
exists, err := redisClient.HGet(redisKey, encryptedKey)
if err == nil && exists != "" {
// 存在重复数据
log.Printf("[INFO] 检测到重复数据: shopId=%d, isbn=%s, shopType=%s", shopID, isbn, shopType)
ctx.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
"success": true,
"data": gin.H{
"deduplicated": false,
"isRepeat": true,
"shopId": shopID,
"isbn": isbn,
"shopType": shopType,
"price": price,
"condition": condition,
},
})
return
}
// 8. 关键成功日志
log.Printf("[INFO] 数据检查完成: shopId=%d, isbn=%s, shopType=%s, price=%s, condition=%s",
shopID, isbn, shopType, price, condition)
// 9. 返回结果
ctx.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
"success": true,
"data": gin.H{
"deduplicated": true,
"isRepeat": false,
"shopId": shopID,
"isbn": isbn,
"shopType": shopType,
"price": price,
"condition": condition,
},
})
}
// MultipleStores 闲鱼多点店铺去重
func MultipleStores(ctx *gin.Context) {
// 1. 直接获取参数
shopIDsStr := ctx.PostForm("shopIds")
isbn := ctx.PostForm("isbn")
// 2. 空值检查
if shopIDsStr == "" || isbn == "" {
log.Printf("[WARN] 参数为空 (路径: %s, IP: %s)",
ctx.FullPath(), ctx.ClientIP())
ctx.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "shopIds和isbn不能为空",
"success": false,
})
return
}
// 3. 使用全局的Redis连接池避免每次创建新连接
redisClient := utils.RedisTwoForParseFormData
if redisClient == nil {
log.Printf("[ERROR] Redis连接未初始化")
ctx.JSON(http.StatusInternalServerError, gin.H{
"code": 500,
"message": "系统内部错误",
"success": false,
})
return
}
// 4. 生成MD5加密的ISBN
hash := md5.Sum([]byte(isbn))
encryptedIsbn := fmt.Sprintf("%x", hash)
// 5. 解析shopIds数组支持逗号分隔兼容JSON数组格式如 [id1,id2,id3]
// 去除可能的首尾方括号
shopIDsStr = strings.TrimSpace(shopIDsStr)
shopIDsStr = strings.TrimPrefix(shopIDsStr, "[")
shopIDsStr = strings.TrimSuffix(shopIDsStr, "]")
shopIDStrs := strings.Split(shopIDsStr, ",")
// 6. 遍历每个shopId逐个检查是否存在重复数据
for _, idStr := range shopIDStrs {
idStr = strings.TrimSpace(idStr)
// 跳过空字符串
if idStr == "" {
continue
}
// 转换并验证shopId格式
shopID, err := strconv.ParseInt(idStr, 10, 64)
if err != nil || shopID <= 0 {
log.Printf("[WARN] 无效的shopId: %s (错误: %v)", idStr, err)
continue
}
// 构建Redis key
redisKey := fmt.Sprintf("%d", shopID)
// 检查是否存在重复数据
exists, err := redisClient.HGet(redisKey, encryptedIsbn)
if err == nil && exists != "" {
// 存在重复数据,立即返回不继续查询
log.Printf("[INFO] 检测到重复数据: shopId=%d, isbn=%s", shopID, isbn)
ctx.JSON(http.StatusOK, gin.H{
"code": 1,
"message": "已有重复数据",
"success": false,
"data": gin.H{
"shopId": shopID,
"isbn": isbn,
},
})
return
}
}
// 7. 关键成功日志
log.Printf("[INFO] 表单数据解析成功: shopIds=%s, isbn=%s", shopIDsStr, isbn)
// 8. 返回结果
ctx.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
"data": gin.H{
"shopIds": shopIDsStr,
"isbn": isbn,
},
"success": true,
})
}
func SingleShopMultipleStores(ctx *gin.Context) {
// 1. 直接获取参数
shopIDStr := ctx.PostForm("shopId")
isbn := ctx.PostForm("isbn")
// 2. 空值检查(移除了 goodsid
if shopIDStr == "" || isbn == "" {
log.Printf("[WARN] 参数为空 (路径: %s, IP: %s)",
ctx.FullPath(), ctx.ClientIP())
ctx.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "shopid和isbn不能为空",
"success": false,
})
return
}
// 3. 转换并验证数字格式(只保留 shopid 验证)
shopID, err := strconv.ParseInt(shopIDStr, 10, 64)
if err != nil || shopID <= 0 {
log.Printf("[WARN] 无效的shopid: %s (错误: %v)", shopIDStr, err)
ctx.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "shopid必须为正整数",
"success": false,
})
return
}
// 4. 使用全局的Redis连接池避免每次创建新连接
redisClient := utils.RedisTwoForParseFormData
if redisClient == nil {
log.Printf("[ERROR] Redis连接未初始化")
ctx.JSON(http.StatusInternalServerError, gin.H{
"code": 500,
"message": "系统内部错误",
"success": false,
})
return
}
// 5. 使用全局MySQL连接池单例在main.go启动时初始化
db := dbConnectUtil.DB
if db == nil {
log.Printf("[ERROR] 全局MySQL连接池未初始化")
ctx.JSON(http.StatusInternalServerError, gin.H{
"code": 500,
"message": "系统内部错误",
"success": false,
})
return
}
// 6. 生成MD5加密的ISBN
hash := md5.Sum([]byte(isbn))
encryptedIsbn := fmt.Sprintf("%x", hash)
// 7. 查询当前店铺的mall_id
var mallID string
err = db.QueryRow(`
SELECT mall_id
FROM t_shop
WHERE shop_type LIKE '%5%'
AND del_flag LIKE '%0%'
AND id = ?`, shopID).Scan(&mallID)
if err != nil {
// mall_id未找到不做去重处理直接返回成功
log.Printf("[INFO] 未找到店铺mall_id: shopid=%d, err=%v", shopID, err)
ctx.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
"data": gin.H{
"shopid": shopID,
"isbn": isbn,
},
"success": true,
})
return
}
// 8. 根据mall_id查询所有关联店铺id
rows, err := db.Query(`
SELECT id FROM t_shop
WHERE shop_type LIKE '%5%'
AND del_flag LIKE '%0%'
AND mall_id = ?`, mallID)
if err != nil {
log.Printf("[ERROR] 查询关联店铺失败: mall_id=%s, err=%v", mallID, err)
ctx.JSON(http.StatusInternalServerError, gin.H{
"code": 500,
"message": "系统内部错误",
"success": false,
})
return
}
defer rows.Close()
// 9. 遍历所有关联店铺id参考ParseFormData第5步之后的逻辑检查重复
var relatedShopIDs []int64
for rows.Next() {
var relatedShopID int64
if err := rows.Scan(&relatedShopID); err != nil {
log.Printf("[WARN] 扫描关联店铺id失败: %v", err)
continue
}
relatedShopIDs = append(relatedShopIDs, relatedShopID)
}
for _, relatedShopID := range relatedShopIDs {
// 构建Redis key
redisKey := fmt.Sprintf("%d", relatedShopID)
// 检查是否存在重复数据
exists, err := redisClient.HGet(redisKey, encryptedIsbn)
if err == nil && exists != "" {
// 存在重复数据,立即返回不继续查询
log.Printf("[INFO] 检测到重复数据: shopId=%d, isbn=%s (关联mall_id=%s)", relatedShopID, isbn, mallID)
ctx.JSON(http.StatusOK, gin.H{
"code": 1,
"message": "已有重复数据",
"success": false,
"data": gin.H{
"shopId": relatedShopID,
"isbn": isbn,
"mallId": mallID,
"relatedShopCount": len(relatedShopIDs),
},
})
return
}
}
// 10. 关键成功日志
log.Printf("[INFO] 多点店铺去重检查完成: shopid=%d, isbn=%s, mall_id=%s, 关联店铺数=%d",
shopID, isbn, mallID, len(relatedShopIDs))
// 11. 返回结果
ctx.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
"data": gin.H{
"shopid": shopID,
"isbn": isbn,
"mallId": mallID,
"relatedShopCount": len(relatedShopIDs),
"relatedShopIds": relatedShopIDs,
},
"success": true,
})
}