From f5c9d4c54da8d60d8b798f67679263a8aec1607f Mon Sep 17 00:00:00 2001
From: gongchunyi <deslre0381@gmail.com>
Date: 星期三, 15 四月 2026 11:16:48 +0800
Subject: [PATCH] feat: 库存区分产品大类

---
 src/main/resources/mapper/basic/ProductModelMapper.xml                  |   43 ++++++++++++--
 src/main/java/com/ruoyi/basic/controller/ProductController.java         |   14 ++++
 src/main/java/com/ruoyi/basic/service/impl/ProductServiceImpl.java      |   45 +++++++++++----
 src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java |    7 ++
 src/main/java/com/ruoyi/basic/pojo/ProductModel.java                    |    6 ++
 src/main/java/com/ruoyi/basic/service/IProductModelService.java         |    4 +
 doc/河南鹤壁天沐钢化玻璃厂.sql                                                     |    9 ++
 7 files changed, 108 insertions(+), 20 deletions(-)

diff --git "a/doc/\346\262\263\345\215\227\351\271\244\345\243\201\345\244\251\346\262\220\351\222\242\345\214\226\347\216\273\347\222\203\345\216\202.sql" "b/doc/\346\262\263\345\215\227\351\271\244\345\243\201\345\244\251\346\262\220\351\222\242\345\214\226\347\216\273\347\222\203\345\216\202.sql"
index 863106f..190bcec 100644
--- "a/doc/\346\262\263\345\215\227\351\271\244\345\243\201\345\244\251\346\262\220\351\222\242\345\214\226\347\216\273\347\222\203\345\216\202.sql"
+++ "b/doc/\346\262\263\345\215\227\351\271\244\345\243\201\345\244\251\346\262\220\351\222\242\345\214\226\347\216\273\347\222\203\345\216\202.sql"
@@ -90,4 +90,11 @@
     ADD COLUMN `delivery_status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '鍙戣揣鐘舵�侊細0-鏈彂璐э紝1-宸插彂璐�' AFTER `delivery_date`;
 
 ALTER TABLE `product-inventory-management-hbtmblc`.`sales_ledger`
-    MODIFY COLUMN `delivery_status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '鍙戣揣鐘舵�侊細1-鏈彂璐э紝2-瀹℃壒涓紝3-瀹℃壒涓嶉�氳繃锛�4-瀹℃壒閫氳繃锛�5-宸插彂璐�' AFTER `delivery_date`;
\ No newline at end of file
+    MODIFY COLUMN `delivery_status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '鍙戣揣鐘舵�侊細1-鏈彂璐э紝2-瀹℃壒涓紝3-瀹℃壒涓嶉�氳繃锛�4-瀹℃壒閫氳繃锛�5-宸插彂璐�' AFTER `delivery_date`;
+
+ALTER TABLE `product-inventory-management-hbtmblc`.`sales_ledger_product`
+    MODIFY COLUMN `quantity` decimal(18, 2) NULL COMMENT '鏁伴噺' AFTER `unit`,
+    MODIFY COLUMN `tax_rate` decimal(5, 0) NULL COMMENT '绋庣巼' AFTER `min_stock`,
+    MODIFY COLUMN `tax_inclusive_unit_price` decimal(18, 2) NULL COMMENT '鍚◣鍗曚环' AFTER `tax_rate`,
+    MODIFY COLUMN `tax_inclusive_total_price` decimal(18, 2) NULL COMMENT '鍚◣鎬讳环' AFTER `tax_inclusive_unit_price`,
+    MODIFY COLUMN `tax_exclusive_total_price` decimal(18, 2) NULL COMMENT '涓嶅惈绋庢�讳环' AFTER `tax_inclusive_total_price`;
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/basic/controller/ProductController.java b/src/main/java/com/ruoyi/basic/controller/ProductController.java
index 252ab4d..2d211b7 100644
--- a/src/main/java/com/ruoyi/basic/controller/ProductController.java
+++ b/src/main/java/com/ruoyi/basic/controller/ProductController.java
@@ -7,6 +7,7 @@
 import com.ruoyi.basic.dto.ProductModelDto;
 import com.ruoyi.basic.dto.ProductModelExportDto;
 import com.ruoyi.basic.dto.ProductTreeDto;
+import com.ruoyi.basic.pojo.Product;
 import com.ruoyi.basic.pojo.ProductModel;
 import com.ruoyi.basic.service.IProductModelService;
 import com.ruoyi.basic.service.IProductService;
@@ -38,6 +39,7 @@
     private IProductModelService productModelService;
     @Autowired
     private ISalesLedgerProductService salesLedgerProductService;
+
     /**
      * 鏌ヨ浜у搧
      */
@@ -85,7 +87,7 @@
         LambdaQueryWrapper<SalesLedgerProduct> queryWrapper = new LambdaQueryWrapper<>();
         queryWrapper.in(SalesLedgerProduct::getProductId, ids);
         List<SalesLedgerProduct> salesLedgerProductList = salesLedgerProductService.list(queryWrapper);
-        if (salesLedgerProductList.size() > 0) {
+        if (!salesLedgerProductList.isEmpty()) {
             return AjaxResult.error("璇ヤ骇鍝佸瓨鍦ㄩ攢鍞�/閲囪喘璁板綍锛屼笉鑳藉垹闄�");
         }
         return toAjax(productService.delProductByIds(ids));
@@ -143,4 +145,14 @@
         ExcelUtil<ProductModelExportDto> excelUtil = new ExcelUtil<>(ProductModelExportDto.class);
         excelUtil.importTemplateExcel(response, "浜у搧瑙勬牸瀵煎叆妯℃澘");
     }
+
+    /**
+     * 鑾峰彇浜у搧澶х被
+     */
+    @GetMapping("/getParentNames")
+    @ApiOperation("鑾峰彇浜у搧澶х被")
+    public AjaxResult getParentNames() {
+        List<Product> list = productModelService.getParentNames();
+        return AjaxResult.success(list);
+    }
 }
diff --git a/src/main/java/com/ruoyi/basic/pojo/ProductModel.java b/src/main/java/com/ruoyi/basic/pojo/ProductModel.java
index 7369e19..7aa975f 100644
--- a/src/main/java/com/ruoyi/basic/pojo/ProductModel.java
+++ b/src/main/java/com/ruoyi/basic/pojo/ProductModel.java
@@ -69,4 +69,10 @@
 
     @TableField(exist = false)
     private LocalDateTime createTime;
+
+    @TableField(exist = false)
+    private Long parentId;
+
+    @TableField(exist = false)
+    private String parentName;
 }
diff --git a/src/main/java/com/ruoyi/basic/service/IProductModelService.java b/src/main/java/com/ruoyi/basic/service/IProductModelService.java
index dd268d6..f752566 100644
--- a/src/main/java/com/ruoyi/basic/service/IProductModelService.java
+++ b/src/main/java/com/ruoyi/basic/service/IProductModelService.java
@@ -5,6 +5,7 @@
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.ruoyi.basic.dto.ProductDto;
 import com.ruoyi.basic.dto.ProductModelDto;
+import com.ruoyi.basic.pojo.Product;
 import com.ruoyi.basic.pojo.ProductModel;
 import com.ruoyi.framework.web.domain.AjaxResult;
 import org.springframework.web.multipart.MultipartFile;
@@ -35,4 +36,7 @@
     IPage<ProductModel> modelListPage(Page page , ProductDto productDto);
 
     AjaxResult importProductModel(MultipartFile file, Integer productId);
+
+    List<Product> getParentNames();
+
 }
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 9382134..15ecd8e 100644
--- a/src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java
+++ b/src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java
@@ -151,4 +151,11 @@
             throw new ServiceException("瀵煎叆澶辫触");
         }
     }
+
+    @Override
+    public List<Product> getParentNames() {
+        LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.isNull(Product::getParentId).select(Product::getId, Product::getProductName);
+        return productMapper.selectList(queryWrapper);
+    }
 }
diff --git a/src/main/java/com/ruoyi/basic/service/impl/ProductServiceImpl.java b/src/main/java/com/ruoyi/basic/service/impl/ProductServiceImpl.java
index fdf2dd3..9c3cf89 100644
--- a/src/main/java/com/ruoyi/basic/service/impl/ProductServiceImpl.java
+++ b/src/main/java/com/ruoyi/basic/service/impl/ProductServiceImpl.java
@@ -89,27 +89,48 @@
 
     @Override
     public int addOrEditProduct(ProductDto productDto) {
+        checkDuplicateName(productDto);
         if (productDto.getId() == null) {
-            // 鏂板浜у搧閫昏緫
-            if (productDto.getParentId() == null) {
-                // 鑻ユ湭鎸囧畾鐖惰妭鐐癸紝榛樿涓烘牴鑺傜偣锛坧arentId 璁句负 null锛�
-                productDto.setParentId(null);
-            } else {
-                // 妫�鏌ョ埗鑺傜偣鏄惁瀛樺湪锛堝彲閫夛紝鏍规嵁涓氬姟闇�姹傦級
+            if (productDto.getParentId() != null) {
                 Product parent = productMapper.selectById(productDto.getParentId());
                 if (parent == null) {
-                    throw new IllegalArgumentException("鐖惰妭鐐逛笉瀛樺湪锛屾棤娉曟坊鍔犲瓙浜у搧");
+                    throw new IllegalArgumentException("鐖惰妭鐐逛笉瀛樺湪");
                 }
             }
-            return productMapper.insert(productDto);
+            Product product = new Product();
+            BeanUtils.copyProperties(productDto, product);
+            return productMapper.insert(product);
         } else {
-            // 缂栬緫浜у搧閫昏緫
-            // 妫�鏌ヤ骇鍝佹槸鍚﹀瓨鍦紙鍙�夛紝鏍规嵁涓氬姟闇�姹傦級
             Product existingProduct = productMapper.selectById(productDto.getId());
             if (existingProduct == null) {
-                throw new IllegalArgumentException("瑕佺紪杈戠殑浜у搧涓嶅瓨鍦�");
+                throw new IllegalArgumentException("浜у搧涓嶅瓨鍦�");
             }
-            return productMapper.updateById(productDto);
+            Product product = new Product();
+            BeanUtils.copyProperties(productDto, product);
+            return productMapper.updateById(product);
+        }
+    }
+
+    /**
+     * 鏍¢獙鍚岀骇鐩綍涓嬫槸鍚﹀瓨鍦ㄩ噸澶嶅悕绉�
+     */
+    private void checkDuplicateName(ProductDto productDto) {
+        LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<>();
+
+        if (productDto.getParentId() == null) {
+            queryWrapper.isNull(Product::getParentId);
+        } else {
+            queryWrapper.eq(Product::getParentId, productDto.getParentId());
+        }
+
+        queryWrapper.eq(Product::getProductName, productDto.getProductName());
+
+        if (productDto.getId() != null) {
+            queryWrapper.ne(Product::getId, productDto.getId());
+        }
+
+        if (productMapper.selectCount(queryWrapper) > 0) {
+            throw new IllegalArgumentException("鍦ㄨ灞傜骇涓嬪凡瀛樺湪鍚嶄负 [" + productDto.getProductName() + "] 鐨勪骇鍝�");
         }
     }
 
diff --git a/src/main/resources/mapper/basic/ProductModelMapper.xml b/src/main/resources/mapper/basic/ProductModelMapper.xml
index b0c493e..cb80816 100644
--- a/src/main/resources/mapper/basic/ProductModelMapper.xml
+++ b/src/main/resources/mapper/basic/ProductModelMapper.xml
@@ -15,20 +15,51 @@
         <result column="product_name" property="productName" />
         <result column="product_id" property="productId" />
     </resultMap>
+
     <select id="listPageProductModel" resultType="com.ruoyi.basic.pojo.ProductModel">
-        select pm.*,p.product_name
-        from product_model pm
-        left join product p on pm.product_id = p.id
+        WITH RECURSIVE product_tree AS (
+        SELECT
+        id,
+        product_name,
+        id AS top_id,
+        product_name AS top_name
+        FROM product
+        WHERE parent_id IS NULL OR parent_id = 0
+
+        UNION ALL
+
+        SELECT
+        p.id,
+        p.product_name,
+        t.top_id,
+        t.top_name
+        FROM product p
+        INNER JOIN product_tree t ON p.parent_id = t.id
+        )
+        SELECT
+        pm.*,
+        pt.product_name AS productName,
+        pt.top_name AS parentName
+        FROM product_model pm
+        LEFT JOIN product_tree pt ON pm.product_id = pt.id
         <where>
+            <if test="c.parentId != null">
+                AND pt.top_id = #{c.parentId}
+            </if>
+
             <if test="c.model != null and c.model != ''">
-                and pm.model  like  concat('%',#{c.model},'%')
+                AND pm.model LIKE CONCAT('%', #{c.model}, '%')
             </if>
             <if test="c.productName != null and c.productName != ''">
-                and p.product_name  like  concat('%',#{c.productName},'%')
+                AND pt.product_name LIKE CONCAT('%', #{c.productName}, '%')
+            </if>
+            <if test="c.parentName != null and c.parentName != ''">
+                AND pt.top_name LIKE CONCAT('%', #{c.parentName}, '%')
             </if>
         </where>
-        order by  pm.id
+        ORDER BY pm.id DESC
     </select>
+
     <select id="selectLatestRecord" resultType="com.ruoyi.basic.pojo.ProductModel">
             SELECT * FROM product_model
             ORDER BY create_time DESC, id DESC

--
Gitblit v1.9.3