From f9b26d13f0a43f0bb5c8140a2de3ebd8d9c9c8d8 Mon Sep 17 00:00:00 2001
From: gongchunyi <deslre0381@gmail.com>
Date: 星期六, 12 九月 2026 11:56:34 +0800
Subject: [PATCH] fix: 产品导入去重

---
 src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java |  100 ++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 72 insertions(+), 28 deletions(-)

diff --git a/src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java b/src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java
index bd46fb4..fa75953 100644
--- a/src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java
+++ b/src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java
@@ -28,6 +28,7 @@
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -145,6 +146,9 @@
             return AjaxResult.error("鏈壘鍒� [鍘熸枡/鍗婃垚鍝�/鎴愬搧] 宸ヤ綔琛紝鎴栨枃浠朵腑娌℃湁鏁版嵁");
         }
 
+        // 鍘婚噸閿細浜у搧鍚嶇О + 瑙勬牸鍨嬪彿 + 缂栫爜锛堢┖缂栫爜鎸夌┖涓插弬涓庢瘮杈冿級
+        Set<String> seenKeys = loadExistingProductKeys(sheetMap);
+
         int successCount = 0;
         int skipCount = 0;
         Set<String> generatedCodes = new HashSet<>();
@@ -155,45 +159,47 @@
             }
             Long topId = findOrCreateTopProduct(sheetName);
             Map<String, Long> nodeCache = new HashMap<>();
-            Map<Long, Set<String>> codeCache = new HashMap<>();
             for (int i = 0; i < rows.size(); i++) {
                 ProductImportRowDto row = rows.get(i);
                 int rowNum = i + 2;
                 String parentName = trimToNull(row.getProductParentName());
                 String categoryName = trimToNull(row.getProductCategoryName());
                 String productName = trimToNull(row.getProductName());
-                if (categoryName == null) {
-                    throw new ServiceException("绗� " + rowNum + " 琛� [浜у搧澶х被] 涓嶈兘涓虹┖");
-                }
                 if (productName == null) {
                     throw new ServiceException("绗� " + rowNum + " 琛� [浜у搧鍚嶇О] 涓嶈兘涓虹┖");
                 }
 
-                String path = String.valueOf(topId);
-                Long parentNodeId = topId;
-                if (parentName != null) {
-                    path = path + ">" + parentName;
-                    parentNodeId = ensureChildNode(nodeCache, path, parentNodeId, parentName);
+                String model = trimToNull(row.getModel());
+                if (model == null) {
+                    model = "/";
                 }
-                path = path + ">" + categoryName;
-                Long categoryId = ensureChildNode(nodeCache, path, parentNodeId, categoryName);
-                path = path + ">" + productName;
-                Long leafId = ensureChildNode(nodeCache, path, categoryId, productName);
-
                 String code = trimToNull(row.getProductCode());
-                if (code == null) {
-                    code = generateUniqueCode(generatedCodes);
-                }
-                Set<String> codes = codeCache.computeIfAbsent(leafId, this::loadProductCodes);
-                if (!codes.add(code)) {
+                if (!seenKeys.add(dedupKey(productName, model, code))) {
                     skipCount++;
                     continue;
+                }
+
+                String path = String.valueOf(topId);
+                Long currentParentId = topId;
+                if (parentName != null) {
+                    path = path + ">" + parentName;
+                    currentParentId = ensureChildNode(nodeCache, path, currentParentId, parentName);
+                }
+                if (categoryName != null) {
+                    path = path + ">" + categoryName;
+                    currentParentId = ensureChildNode(nodeCache, path, currentParentId, categoryName);
+                }
+                path = path + ">" + productName;
+                Long leafId = ensureChildNode(nodeCache, path, currentParentId, productName);
+
+                if (code == null) {
+                    code = generateUniqueCode(generatedCodes);
                 }
 
                 ProductModel productModel = new ProductModel();
                 productModel.setProductId(leafId);
                 productModel.setProductCode(code);
-                productModel.setModel(StringUtils.isEmpty(row.getModel()) ? "/" : row.getModel().trim());
+                productModel.setModel(model);
                 productModel.setUnit(trimToNull(row.getUnit()));
                 productModelMapper.insert(productModel);
                 successCount++;
@@ -241,16 +247,54 @@
         return product.getId();
     }
 
-    private Set<String> loadProductCodes(Long productId) {
-        List<ProductModel> list = productModelMapper.selectList(new LambdaQueryWrapper<ProductModel>()
-                .eq(ProductModel::getProductId, productId));
-        Set<String> codes = new HashSet<>();
-        for (ProductModel productModel : list) {
-            if (productModel.getProductCode() != null) {
-                codes.add(productModel.getProductCode().trim());
+    /**
+     * 棰勫姞杞藉簱涓凡瀛樺湪鐨勫幓閲嶉敭锛堜骇鍝佸悕绉� + 瑙勬牸鍨嬪彿 + 缂栫爜锛夛紝骞朵綔涓烘湰娆″鍏ョ殑鍒濆闆嗗悎銆�
+     */
+    private Set<String> loadExistingProductKeys(Map<String, List<ProductImportRowDto>> sheetMap) {
+        Set<String> productNames = new HashSet<>();
+        for (List<ProductImportRowDto> rows : sheetMap.values()) {
+            if (CollectionUtils.isEmpty(rows)) {
+                continue;
+            }
+            for (ProductImportRowDto row : rows) {
+                String productName = trimToNull(row.getProductName());
+                if (productName != null) {
+                    productNames.add(productName);
+                }
             }
         }
-        return codes;
+        Set<String> keys = new HashSet<>();
+        if (productNames.isEmpty()) {
+            return keys;
+        }
+
+        List<Product> products = productMapper.selectList(new LambdaQueryWrapper<Product>()
+                .in(Product::getProductName, productNames));
+        if (CollectionUtils.isEmpty(products)) {
+            return keys;
+        }
+        Map<Long, String> nameById = new HashMap<>();
+        List<Long> productIds = new ArrayList<>();
+        for (Product product : products) {
+            nameById.put(product.getId(), product.getProductName());
+            productIds.add(product.getId());
+        }
+
+        List<ProductModel> productModels = productModelMapper.selectList(new LambdaQueryWrapper<ProductModel>()
+                .in(ProductModel::getProductId, productIds));
+        for (ProductModel productModel : productModels) {
+            String productName = nameById.get(productModel.getProductId());
+            if (productName != null) {
+                keys.add(dedupKey(productName, productModel.getModel(), productModel.getProductCode()));
+            }
+        }
+        return keys;
+    }
+
+    private static String dedupKey(String productName, String model, String productCode) {
+        String normalizedModel = trimToNull(model) == null ? "/" : model.trim();
+        String normalizedCode = productCode == null ? "" : productCode.trim();
+        return productName.trim() + "\u0001" + normalizedModel + "\u0001" + normalizedCode;
     }
 
     private String generateUniqueCode(Set<String> generatedCodes) {

--
Gitblit v1.9.3