From a76f7b29357729710f9e99f0676af4635b922ea4 Mon Sep 17 00:00:00 2001
From: yuan <123@>
Date: 星期四, 10 九月 2026 11:41:55 +0800
Subject: [PATCH] fix: 更新产品导入的工作表名称

---
 src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java |  228 ++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 179 insertions(+), 49 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 ce0ba64..cf2e3d9 100644
--- a/src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java
+++ b/src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java
@@ -7,6 +7,7 @@
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ruoyi.basic.dto.ProductDto;
+import com.ruoyi.basic.dto.ProductImportRowDto;
 import com.ruoyi.basic.dto.ProductModelDto;
 import com.ruoyi.basic.mapper.ProductMapper;
 import com.ruoyi.basic.mapper.ProductModelMapper;
@@ -20,16 +21,20 @@
 import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
+import com.ruoyi.technology.mapper.TechnologyBomMapper;
+import com.ruoyi.technology.pojo.TechnologyBom;
 import lombok.AllArgsConstructor;
 import org.springframework.stereotype.Service;
 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;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
-import java.util.stream.Collectors;
+import java.util.concurrent.ThreadLocalRandom;
 
 /**
  * 銆愯濉啓鍔熻兘鍚嶇О銆慡ervice涓氬姟灞傚鐞�
@@ -43,10 +48,18 @@
 
     private final ProductMapper productMapper;
     private final SalesLedgerProductMapper salesLedgerProductMapper;
+    private final TechnologyBomMapper technologyBomMapper;
     private ProductModelMapper productModelMapper;
+
+    private static final List<String> IMPORT_SHEET_NAMES = Arrays.asList("鍘熸潗鏂�", "鍘熸枡", "鍗婃垚鍝�", "鎴愬搧");
 
     @Override
     public int addOrEditProductModel(ProductModelDto productModelDto) {
+        String model = StringUtils.trim(productModelDto.getModel());
+        String productCode = StringUtils.trim(productModelDto.getProductCode());
+        productModelDto.setModel(model);
+        productModelDto.setProductCode(productCode);
+        checkModelAndProductCodeUnique(model, productCode, productModelDto.getId());
 
         if (productModelDto.getId() == null) {
             ProductModel productModel = new ProductModel();
@@ -54,6 +67,21 @@
             return productModelMapper.insert(productModel);
         } else {
             return productModelMapper.updateById(productModelDto);
+        }
+    }
+
+    private void checkModelAndProductCodeUnique(String model, String productCode, Long currentId) {
+        if (StringUtils.isEmpty(model) || StringUtils.isEmpty(productCode)) {
+            return;
+        }
+        LambdaQueryWrapper<ProductModel> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(ProductModel::getModel, model)
+                .eq(ProductModel::getProductCode, productCode)
+                .ne(currentId != null, ProductModel::getId, currentId)
+                .last("limit 1");
+        ProductModel duplicateProductModel = productModelMapper.selectOne(queryWrapper);
+        if (duplicateProductModel != null) {
+            throw new ServiceException("瀵瑰簲鐨勫瀷鍙�" + model + "鐨勪骇鍝佺紪鐮�" + productCode + "宸茬粡瀛樺湪");
         }
     }
 
@@ -66,6 +94,14 @@
 
             throw new RuntimeException("宸茬粡瀛樺湪璇ヤ骇鍝佺殑閿�鍞彴璐﹀拰閲囪喘鍙拌处");
         }
+
+        // 鏄惁瀛樺湪BOM
+        List<TechnologyBom> technologyBoms = technologyBomMapper.selectList(new QueryWrapper<TechnologyBom>()
+                .lambda().in(TechnologyBom::getProductModelId, ids));
+        if (CollectionUtils.isNotEmpty(technologyBoms)) {
+            throw new RuntimeException("宸茬粡瀛樺湪璇ヤ骇鍝佺殑BOM鏁版嵁");
+        }
+
         return productModelMapper.deleteBatchIds(Arrays.asList(ids));
     }
 
@@ -92,66 +128,160 @@
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public AjaxResult importProductModel(MultipartFile file, Integer productId) {
-        if (productId == null) {
-            return AjaxResult.error("璇峰厛閫夋嫨浜у搧鍐嶅鍏ヨ鏍煎瀷鍙�");
+    public AjaxResult importProductModel(MultipartFile file) {
+        if (file == null || file.isEmpty()) {
+            return AjaxResult.error("璇烽�夋嫨瑕佸鍏ョ殑鏂囦欢");
         }
 
-        Product product = productMapper.selectById(productId);
-        if (product == null) {
-            return AjaxResult.error("閫夋嫨鐨勪骇鍝佷笉瀛樺湪");
-        }
-
+        Map<String, List<ProductImportRowDto>> sheetMap;
         try {
-            ExcelUtil<ProductModel> productModelExcelUtil = new ExcelUtil<>(ProductModel.class);
-            List<ProductModel> productModelList = productModelExcelUtil.importExcel(file.getInputStream());
+            ExcelUtil<ProductImportRowDto> excelUtil = new ExcelUtil<>(ProductImportRowDto.class);
+            sheetMap = excelUtil.importExcelMultiSheet(IMPORT_SHEET_NAMES, file.getInputStream(), 0);
+        } catch (Exception e) {
+            log.error("瑙f瀽浜у搧瀵煎叆鏂囦欢寮傚父", e);
+            throw new ServiceException("浜у搧瀵煎叆鏂囦欢瑙f瀽澶辫触");
+        }
+        if (sheetMap.isEmpty()) {
+            return AjaxResult.error("鏈壘鍒� [鍘熸枡/鍗婃垚鍝�/鎴愬搧] 宸ヤ綔琛紝鎴栨枃浠朵腑娌℃湁鏁版嵁");
+        }
 
-            if (CollectionUtils.isEmpty(productModelList)) {
-                return AjaxResult.error("瀵煎叆鏁版嵁涓嶈兘涓虹┖");
+        int successCount = 0;
+        int skipCount = 0;
+        Set<String> generatedCodes = new HashSet<>();
+        for (String sheetName : IMPORT_SHEET_NAMES) {
+            List<ProductImportRowDto> rows = sheetMap.get(sheetName);
+            if (CollectionUtils.isEmpty(rows)) {
+                continue;
             }
-
-            //  鑾峰彇褰撳墠浜у搧涓嬫墍鏈夌殑瑙勬牸鍨嬪彿鍚�
-            List<ProductModel> existingModels = list(new LambdaQueryWrapper<ProductModel>().eq(ProductModel::getProductId, productId));
-            Set<String> existingModelNames = existingModels.stream().map(ProductModel::getModel).collect(Collectors.toSet());
-
-            List<ProductModel> waitToSaveList = new ArrayList<>();
-            int skipCount = 0;
-
-            for (int i = 0; i < productModelList.size(); i++) {
-                ProductModel item = productModelList.get(i);
+            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;
-
-                if (StringUtils.isEmpty(item.getModel())) {
-                    return AjaxResult.error("绗� " + rowNum + " 琛屽鍏ュけ璐�: [瑙勬牸鍨嬪彿] 涓嶈兘涓虹┖");
-                }
-                if (StringUtils.isEmpty(item.getUnit())) {
-                    return AjaxResult.error("绗� " + rowNum + " 琛屽鍏ュけ璐�: [鍗曚綅] 涓嶈兘涓虹┖");
+                String parentName = trimToNull(row.getProductParentName());
+                String categoryName = trimToNull(row.getProductCategoryName());
+                String productName = trimToNull(row.getProductName());
+                if (productName == null) {
+                    throw new ServiceException("绗� " + rowNum + " 琛� [浜у搧鍚嶇О] 涓嶈兘涓虹┖");
                 }
 
-                //  鍘婚噸,濡傛灉宸插寘鍚鍨嬪彿,鍒欒烦杩�
-                if (existingModelNames.contains(item.getModel())) {
+                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);
+
+                String code = trimToNull(row.getProductCode());
+                if (code == null) {
+                    code = generateUniqueCode(generatedCodes);
+                }
+                Set<String> codes = codeCache.computeIfAbsent(leafId, this::loadProductCodes);
+                if (!codes.add(code)) {
                     skipCount++;
                     continue;
                 }
 
-                item.setProductId(product.getId());
-                waitToSaveList.add(item);
-
-                existingModelNames.add(item.getModel());
+                ProductModel productModel = new ProductModel();
+                productModel.setProductId(leafId);
+                productModel.setProductCode(code);
+                productModel.setModel(StringUtils.isEmpty(row.getModel()) ? "/" : row.getModel().trim());
+                productModel.setUnit(trimToNull(row.getUnit()));
+                productModelMapper.insert(productModel);
+                successCount++;
             }
-
-            if (!waitToSaveList.isEmpty()) {
-                saveBatch(waitToSaveList);
-            }
-
-            if (skipCount == 0) {
-                return AjaxResult.success(String.format("鎴愬姛瀵煎叆 %d 鏉℃暟鎹�", waitToSaveList.size()));
-            } else {
-                return AjaxResult.success(String.format("鎴愬姛瀵煎叆 %d 鏉★紝璺宠繃宸插瓨鍦ㄦ暟鎹� %d 鏉�", waitToSaveList.size(), skipCount));
-            }
-        } catch (Exception e) {
-            log.error("瀵煎叆浜у搧瑙勬牸寮傚父", e);
-            throw new ServiceException("瀵煎叆澶辫触");
         }
+
+        String message = skipCount > 0
+                ? String.format("鎴愬姛瀵煎叆 %d 鏉★紝璺宠繃宸插瓨鍦� %d 鏉�", successCount, skipCount)
+                : String.format("鎴愬姛瀵煎叆 %d 鏉�", successCount);
+        return AjaxResult.success(message);
+    }
+
+    private Long findOrCreateTopProduct(String name) {
+        Product root = productMapper.selectOne(new LambdaQueryWrapper<Product>()
+                .isNull(Product::getParentId)
+                .eq(Product::getProductName, name)
+                .last("limit 1"));
+        if (root != null) {
+            return root.getId();
+        }
+        Product product = new Product();
+        product.setProductName(name);
+        productMapper.insert(product);
+        return product.getId();
+    }
+
+    private Long ensureChildNode(Map<String, Long> nodeCache, String path, Long parentId, String name) {
+        Long id = nodeCache.get(path);
+        if (id != null) {
+            return id;
+        }
+        Product existing = productMapper.selectOne(new LambdaQueryWrapper<Product>()
+                .eq(Product::getParentId, parentId)
+                .eq(Product::getProductName, name)
+                .last("limit 1"));
+        if (existing != null) {
+            nodeCache.put(path, existing.getId());
+            return existing.getId();
+        }
+        Product product = new Product();
+        product.setParentId(parentId);
+        product.setProductName(name);
+        productMapper.insert(product);
+        nodeCache.put(path, product.getId());
+        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());
+            }
+        }
+        return codes;
+    }
+
+    private String generateUniqueCode(Set<String> generatedCodes) {
+        for (int i = 0; i < 200; i++) {
+            String code = randomCode(5);
+            if (generatedCodes.contains(code)) {
+                continue;
+            }
+            Long count = productModelMapper.selectCount(new LambdaQueryWrapper<ProductModel>()
+                    .eq(ProductModel::getProductCode, code));
+            if (count == null || count == 0) {
+                generatedCodes.add(code);
+                return code;
+            }
+        }
+        throw new ServiceException("鐢熸垚鍞竴浜у搧缂栫爜澶辫触锛岃閲嶈瘯");
+    }
+
+    private static String randomCode(int length) {
+        String chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < length; i++) {
+            sb.append(chars.charAt(ThreadLocalRandom.current().nextInt(chars.length())));
+        }
+        return sb.toString();
+    }
+
+    private static String trimToNull(String value) {
+        if (value == null) {
+            return null;
+        }
+        String trimmed = value.trim();
+        return trimmed.isEmpty() ? null : trimmed;
     }
 }

--
Gitblit v1.9.3