1729474b4c7ffacb1790bb70981e64e7744bffb2..1cf91e355038837f30f2d727507b2229263d7de7
4 小时以前 liyong
Merge remote-tracking branch 'origin/dev_New' into dev_New
1cf91e 对比 | 目录
4 小时以前 liyong
refactor(stock): 删除getStockQuantity方法
f90a37 对比 | 目录
4 小时以前 gongchunyi
Merge remote-tracking branch 'origin/dev_New' into dev_New
0adbf5 对比 | 目录
4 小时以前 gongchunyi
fix: 审批类型、产品大类分布修改
98ed3d 对比 | 目录
4 小时以前 maven
Merge remote-tracking branch 'origin/dev_New' into dev_New
4ed692 对比 | 目录
4 小时以前 maven
yys 精创-温湿度,二氧化碳接口联调
1c2cbd 对比 | 目录
5 小时以前 liyong
fix(enum): 代码迁移
49d6ed 对比 | 目录
5 小时以前 liyong
fix(enum): 代码迁移
8ae7c0 对比 | 目录
5 小时以前 liyong
fix(enum): 代码迁移
cdf200 对比 | 目录
6 小时以前 liyong
Merge remote-tracking branch 'origin/dev_New' into dev_New
176515 对比 | 目录
6 小时以前 liyong
fix(enum): 库存冻结解冻功能添加
a0c237 对比 | 目录
6 小时以前 gongchunyi
Merge remote-tracking branch 'origin/dev_New' into dev_New
ed4dd4 对比 | 目录
6 小时以前 gongchunyi
feat: BI大屏接口
cdf97c 对比 | 目录
6 小时以前 zss
生产报工优化
94a273 对比 | 目录
6 小时以前 zss
Merge remote-tracking branch 'origin/dev_New' into dev_New
f980b0 对比 | 目录
6 小时以前 zss
迁移军泰的生产工单的附件上传+工单生成二维码
7dd84f 对比 | 目录
6 小时以前 liyong
Merge remote-tracking branch 'origin/dev_New' into dev_New
80c45e 对比 | 目录
6 小时以前 liyong
fix(enum): 修正不合格新增库存
dbaa98 对比 | 目录
6 小时以前 maven
yys
32b392 对比 | 目录
6 小时以前 maven
yys
aaaebf 对比 | 目录
7 小时以前 maven
yys 销售产品模板去掉是否质检
d3000f 对比 | 目录
7 小时以前 maven
yys 删除销售报价时同步删除报价审核
966eb4 对比 | 目录
7 小时以前 maven
yys 修改发货模块
3946d7 对比 | 目录
8 小时以前 maven
yys 修改发货模块
587b59 对比 | 目录
8 小时以前 maven
Merge remote-tracking branch 'origin/dev_New' into dev_New
77ef6f 对比 | 目录
8 小时以前 maven
yys 回显快递信息
7b4ff2 对比 | 目录
8 小时以前 liyong
fix(enum): 修正销售发货出库枚举值
6655b8 对比 | 目录
8 小时以前 maven
yys 销售,采购导出修改
95c61d 对比 | 目录
8 小时以前 liyong
Merge remote-tracking branch 'origin/dev_New' into dev_New
da0e9f 对比 | 目录
8 小时以前 liyong
fix(enum): 修正销售发货出库枚举值
6848ea 对比 | 目录
9 小时以前 maven
yys 删除销售产品时同步删除发货记录
72f484 对比 | 目录
9 小时以前 maven
yys 删除销售产品时同步删除发货记录
258c2d 对比 | 目录
10 小时以前 maven
yys
322222 对比 | 目录
10 小时以前 maven
yys
f8f7fb 对比 | 目录
10 小时以前 maven
yys 删除销售台账,采购台账同步删除附件
fe3c59 对比 | 目录
10 小时以前 maven
yys 删除销售台账同步删除发货台账,发货审批记录
89fc27 对比 | 目录
11 小时以前 maven
Merge remote-tracking branch 'origin/dev_New' into dev_New
03386a 对比 | 目录
11 小时以前 maven
yys 修改发货模块bug
926371 对比 | 目录
11 小时以前 liyong
Merge remote-tracking branch 'origin/dev_New' into dev_New
2cc19f 对比 | 目录
11 小时以前 liyong
refactor(sales): 库存报表-日报-月报-进出项报表
b9fe74 对比 | 目录
11 小时以前 maven
Merge remote-tracking branch 'origin/dev_New' into dev_New
7a792a 对比 | 目录
11 小时以前 maven
yys 优化采购审批模块
b1b1c6 对比 | 目录
12 小时以前 zss
Merge remote-tracking branch 'origin/dev_New' into dev_New
aa3d1a 对比 | 目录
12 小时以前 zss
设备保养的附件上传表调整
adaa87 对比 | 目录
12 小时以前 liyong
Merge remote-tracking branch 'origin/dev_New' into dev_New
cf77dd 对比 | 目录
12 小时以前 liyong
refactor(sales): 发货扣减库存+删除发货调整库存
a6f7ef 对比 | 目录
12 小时以前 zss
Merge remote-tracking branch 'origin/dev_New' into dev_New
f9c5f3 对比 | 目录
12 小时以前 zss
设备保养的附件上传
6c3a3e 对比 | 目录
12 小时以前 maven
yys 巡检管理模块修改
d5cc87 对比 | 目录
已添加23个文件
已修改64个文件
2555 ■■■■ 文件已修改
pom.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/pojo/ApproveProcess.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/enums/ApproveTypeEnum.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/enums/StockQualifiedRecordTypeEnum.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/utils/MatrixToImageWriter.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/utils/http/HttpUtils.java 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/controller/DeviceMaintenanceFileController.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/mapper/DeviceMaintenanceFileMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/pojo/DeviceMaintenanceFile.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/service/DeviceMaintenanceFileService.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/service/impl/DeviceMaintenanceFileServiceImpl.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/controller/HomeController.java 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/dto/CustomerContributionRankingDto.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/dto/CustomerRevenueAnalysisDto.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/dto/DeptStaffDistributionDto.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/dto/HomeSummaryDto.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/dto/ProductCategoryDistributionDto.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/dto/SupplierPurchaseRankingDto.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/service/HomeService.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java 451 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/http/service/RealTimeEnergyConsumptionService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/http/service/impl/RealTimeEnergyConsumptionServiceImpl.java 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/controller/InspectionTaskController.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/dto/InspectionTaskDto.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/service/InspectionTaskService.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/service/impl/InspectionTaskServiceImpl.java 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductWorkOrderController.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductWorkOrderFileController.java 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/dto/ProductWorkOrderDto.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductWorkOrderFileMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductWorkOrderMapper.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductProcessRoute.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductWorkOrderFile.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductionProductOutput.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductWorkOrderFileService.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductWorkOrderService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductWorkOrderFileServiceImpl.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductWorkOrderServiceImpl.java 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/pojo/PurchaseLedger.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/SalesQuotationController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/ShipmentApprovalController.java 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/ShippingInfoController.java 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/SalesLedger.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/ShippingInfo.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/ShippingInfoService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/MetricStatisticsServiceImpl.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesQuotationServiceImpl.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/controller/StockInRecordController.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/controller/StockInventoryController.java 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/controller/StockOutRecordController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/controller/StockUninventoryController.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/dto/StockInRecordDto.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/dto/StockUninventoryDto.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/execl/StockInventoryExportData.java 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/execl/StockUnInventoryExportData.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/mapper/StockInventoryMapper.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/mapper/StockUninventoryMapper.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/pojo/StockInventory.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/pojo/StockUninventory.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/StockInventoryService.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/StockUninventoryService.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/impl/StockInRecordServiceImpl.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java 98 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/impl/StockUninventoryServiceImpl.java 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductWorkOrderFileMapper.xml 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductWorkOrderMapper.xml 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/SalesLedgerMapper.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/SalesLedgerProductMapper.xml 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/ShippingInfoMapper.xml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/stock/StockInventoryMapper.xml 147 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/stock/StockUninventoryMapper.xml 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/static/work-order-template.docx 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/static/销售台账导入模板.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -301,6 +301,12 @@
            <artifactId>easyexcel</artifactId>
            <version>4.0.3</version>
        </dependency>
         <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.3.3</version>
        </dependency>
    </dependencies>
src/main/java/com/ruoyi/approve/pojo/ApproveProcess.java
@@ -127,10 +127,13 @@
    private Long tenantId;
    /**
     * å®¡æ‰¹ç±»åž‹
     * å®¡æ‰¹ç±»åž‹ 1-公出管理 2-请假管理 3-出差管理 4-报销管理 5-采购审批 6-报价审批 7-发货审批
     */
    private Integer approveType;
    @TableField(exist = false)
    private String approveTypeName;
    /**
     * å®¡æ‰¹å¤‡æ³¨
     */
src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java
@@ -362,6 +362,4 @@
        }
        return null;
    }
}
src/main/java/com/ruoyi/common/enums/ApproveTypeEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
package com.ruoyi.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
 * <br>
 * å®¡æ‰¹ç±»åž‹æžšä¸¾
 * </br>
 *
 * @author deslrey
 * @version 1.0
 * @since 2026/1/27 17:10
 */
@Getter
@AllArgsConstructor
public enum ApproveTypeEnum {
    PUBLIC_AFFAIRS(1, "公出管理"),
    LEAVE(2, "请假管理"),
    BUSINESS_TRIP(3, "出差管理"),
    REIMBURSEMENT(4, "报销管理"),
    PURCHASE(5, "采购审批"),
    QUOTATION(6, "报价审批"),
    DELIVERY(7, "发货审批");
    private final Integer code;
    private final String name;
    /**
     * æ ¹æ® code èŽ·å–å¯¹åº”çš„åç§°
     */
    public static String getNameByCode(Integer code) {
        if (code == null) return null;
        for (ApproveTypeEnum type : ApproveTypeEnum.values()) {
            if (type.getCode().equals(code)) {
                return type.getName();
            }
        }
        return "";
    }
}
src/main/java/com/ruoyi/common/enums/StockQualifiedRecordTypeEnum.java
@@ -12,7 +12,8 @@
    DEFECTIVE_PASS("6", "不合格处理-让步放行"),
    PURCHASE_STOCK_IN("7", "采购-入库"),
    SALE_STOCK_OUT("8", "销售-出库"),
    QUALITYINSPECT_STOCK_IN("11", "质检-合格入库");
    QUALITYINSPECT_STOCK_IN("11", "质检-合格入库"),
    SALE_SHIP_STOCK_OUT("13", "销售-发货出库");
    private final String code;
    private final String value;
@@ -22,4 +23,4 @@
        this.value = value;
    }
}
    }
src/main/java/com/ruoyi/common/utils/MatrixToImageWriter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,67 @@
package com.ruoyi.common.utils;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
/**
 * é…ç½®å›¾åƒå†™å…¥å™¨
 *
 * @author z1292
 *
 */
public class MatrixToImageWriter {
    private final int BLACK = 0xFF000000;
    private final int WHITE = 0xFFFFFFFF;
    private BufferedImage toBufferedImage(BitMatrix matrix) {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
            }
        }
        return image;
    }
    private void writeToFile(BitMatrix matrix, String format, File file) throws IOException {
        BufferedImage image = toBufferedImage(matrix);
        if (!ImageIO.write(image, format, file)) {
            throw new RuntimeException("Could not write an image of format " + format + " to " + file);
        }
    }
    public String code(String content, String path) {
        try {
            String codeName = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yy_MM_dd&HH_mm_ss"));// äºŒç»´ç çš„图片名
            String imageType = "jpg";// å›¾ç‰‡ç±»åž‹
            MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
            Map<EncodeHintType, Object> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            hints.put(EncodeHintType.MARGIN, 0);
            BitMatrix bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, 400, 400, hints);
            File file1 = new File(path, codeName + "." + imageType);
            writeToFile(bitMatrix, imageType, file1);
            return file1.getPath();
        } catch (WriterException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        throw new RuntimeException("二维码生成失败");
    }
}
src/main/java/com/ruoyi/common/utils/http/HttpUtils.java
@@ -290,4 +290,93 @@
            return true;
        }
    }
    /**
     * å‘指定URL发送JSON格式的POST请求(推荐通用方法,默认UTF-8编码)
     * @param url å‘送请求的URL
     * @param jsonParam JSON格式的请求参数(直接传入JSON字符串)
     * @return è¿œç¨‹èµ„源的响应结果
     */
    public static String sendPostJson(String url, String jsonParam) {
        // é‡è½½è°ƒç”¨ï¼Œé»˜è®¤ä½¿ç”¨UTF-8编码,Content-Type固定为application/json
        return sendPostJson(url, jsonParam, StandardCharsets.UTF_8.name(),null);
    }
    /**
     * å‘指定URL发送JSON格式的POST请求(自定义编码,灵活适配特殊场景)
     * @param url å‘送请求的URL
     * @param jsonParam JSON格式的请求参数(直接传入JSON字符串)
     * @param headerValue è¯·æ±‚头的值
     * @return è¿œç¨‹èµ„源的响应结果
     */
    public static String sendPostJson(String url, String jsonParam, String headerValue) {
        // é‡è½½è°ƒç”¨ï¼Œé»˜è®¤ä½¿ç”¨UTF-8编码,Content-Type固定为application/json
        return sendPostJson(url, jsonParam, StandardCharsets.UTF_8.name(),headerValue);
    }
    /**
     * å‘指定URL发送JSON格式的POST请求(自定义编码,灵活适配特殊场景)
     * @param url å‘送请求的URL
     * @param jsonParam JSON格式的请求参数(直接传入JSON字符串)
     * @param charset ç¼–码类型(如UTF-8、GBK等,建议使用StandardCharsets常量)
     * @return è¿œç¨‹èµ„源的响应结果
     */
    public static String sendPostJson(String url, String jsonParam, String charset,String headerValue) {
        PrintWriter out = null;
        BufferedReader in = null;
        StringBuilder result = new StringBuilder();
        try {
            log.info("sendPostJson - {}", url);
            URL realUrl = new URL(url);
            URLConnection conn = realUrl.openConnection();
            // 1. è®¾ç½®è¯·æ±‚头:固定Content-Type为application/json,适配JSON传参规范
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
            conn.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON_VALUE); // æ ¸å¿ƒï¼šJSON专属Content-Type
            conn.setRequestProperty("Accept-Charset", charset);
            // 1.1 è®¾ç½®è¯·æ±‚头:可选,根据实际需要设置
            if(StringUtils.isNotEmpty(headerValue)){
                conn.setRequestProperty("Authorization", headerValue);
            }
            // 2. å¼€å¯è¾“入输出流(POST请求必须)
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 3. å†™å…¥JSON参数(使用指定编码,避免中文乱码)
            out = new PrintWriter(conn.getOutputStream(), true);
            out.print(jsonParam);
            out.flush();
            // 4. è¯»å–响应结果(与请求编码一致,保证解析正确)
            in = new BufferedReader(new InputStreamReader(conn.getInputStream(), charset));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
            log.info("recv - {}", result);
        } catch (ConnectException e) {
            log.error("调用HttpUtils.sendPostJson ConnectException, url=" + url + ",jsonParam=" + jsonParam, e);
        } catch (SocketTimeoutException e) {
            log.error("调用HttpUtils.sendPostJson SocketTimeoutException, url=" + url + ",jsonParam=" + jsonParam, e);
        } catch (IOException e) {
            log.error("调用HttpUtils.sendPostJson IOException, url=" + url + ",jsonParam=" + jsonParam, e);
        } catch (Exception e) {
            log.error("调用HttpUtils.sendPostJson Exception, url=" + url + ",jsonParam=" + jsonParam, e);
        } finally {
            // 5. å…³é—­æµèµ„源(避免内存泄漏,与原代码finally逻辑保持一致)
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                log.error("调用流关闭异常 sendPostJson, url=" + url + ",jsonParam=" + jsonParam, ex);
            }
        }
        return result.toString();
    }
}
src/main/java/com/ruoyi/device/controller/DeviceMaintenanceFileController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,68 @@
package com.ruoyi.device.controller;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.device.pojo.DeviceMaintenanceFile;
import com.ruoyi.device.service.DeviceMaintenanceFileService;
import com.ruoyi.framework.web.domain.AjaxResult;
import io.swagger.annotations.Api;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
 * <p>
 * è®¾å¤‡ä¿å…»é™„ä»¶ å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-27 09:48:09
 */
@RestController
@RequestMapping("/maintenanceTaskFile")
@Api(tags = "设备保养附件")
public class DeviceMaintenanceFileController {
    @Resource
    private DeviceMaintenanceFileService deviceMaintenanceFileService;
    /**
     * æ–°å¢ž
     * @param deviceMaintenanceFile
     * @return
     */
    @PostMapping("/add")
    public AjaxResult add(@RequestBody DeviceMaintenanceFile deviceMaintenanceFile) {
        return AjaxResult.success(deviceMaintenanceFileService.save(deviceMaintenanceFile));
    }
    /**
     * åˆ é™¤
     * @param ids
     * @return
     */
    @DeleteMapping("/del")
    public AjaxResult delQualityUnqualified(@RequestBody List<Integer> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
        }
        //删除检验附件
        return AjaxResult.success(deviceMaintenanceFileService.removeBatchByIds(ids));
    }
    /**
     *分页查询
     * @param page
     * @param deviceMaintenanceFile
     * @return
     */
    @GetMapping("/listPage")
    public AjaxResult qualityInspectFileListPage(Page page, DeviceMaintenanceFile deviceMaintenanceFile) {
        return AjaxResult.success(deviceMaintenanceFileService.page(page, Wrappers.<DeviceMaintenanceFile>lambdaQuery().eq(DeviceMaintenanceFile::getDeviceMaintenanceId,deviceMaintenanceFile.getDeviceMaintenanceId())));
    }
}
src/main/java/com/ruoyi/device/mapper/DeviceMaintenanceFileMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.device.mapper;
import com.ruoyi.device.pojo.DeviceMaintenanceFile;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
 * <p>
 * è®¾å¤‡ä¿å…»é™„ä»¶ Mapper æŽ¥å£
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-27 09:48:09
 */
@Mapper
public interface DeviceMaintenanceFileMapper extends BaseMapper<DeviceMaintenanceFile> {
}
src/main/java/com/ruoyi/device/pojo/DeviceMaintenanceFile.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,65 @@
package com.ruoyi.device.pojo;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
/**
 * <p>
 * è®¾å¤‡ä¿å…»é™„ä»¶
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-27 09:48:09
 */
@Getter
@Setter
@TableName("device_maintenance_file")
@ApiModel(value = "DeviceMaintenanceFile对象", description = "设备保养记录附件")
public class DeviceMaintenanceFile implements Serializable {
    private static final long serialVersionUID = 1L;
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    @ApiModelProperty("文件名称")
    private String name;
    @ApiModelProperty("文件路径")
    private String url;
    @ApiModelProperty("文件大小")
    private Integer fileSize;
    @ApiModelProperty("设备保养记录ID")
    private Integer deviceMaintenanceId;
    @ApiModelProperty("创建时间")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @ApiModelProperty("创建用户")
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;
    @ApiModelProperty("修改时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    @ApiModelProperty("修改用户")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;
    @ApiModelProperty("租户ID")
    @TableField(fill = FieldFill.INSERT)
    private Long tenantId;
}
src/main/java/com/ruoyi/device/service/DeviceMaintenanceFileService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package com.ruoyi.device.service;
import com.ruoyi.device.pojo.DeviceMaintenanceFile;
import com.baomidou.mybatisplus.extension.service.IService;
/**
 * <p>
 * è®¾å¤‡ä¿å…»é™„ä»¶ æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-27 09:48:09
 */
public interface DeviceMaintenanceFileService extends IService<DeviceMaintenanceFile> {
}
src/main/java/com/ruoyi/device/service/impl/DeviceMaintenanceFileServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
package com.ruoyi.device.service.impl;
import com.ruoyi.device.mapper.DeviceMaintenanceFileMapper;
import com.ruoyi.device.pojo.DeviceMaintenanceFile;
import com.ruoyi.device.service.DeviceMaintenanceFileService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
 * <p>
 * è®¾å¤‡ä¿å…»é™„ä»¶ æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-27 09:48:09
 */
@Service
public class DeviceMaintenanceFileServiceImpl extends ServiceImpl<DeviceMaintenanceFileMapper, DeviceMaintenanceFile> implements DeviceMaintenanceFileService {
}
src/main/java/com/ruoyi/home/controller/HomeController.java
@@ -1,7 +1,5 @@
package com.ruoyi.home.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.approve.pojo.ApproveProcess;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
@@ -9,9 +7,6 @@
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.home.dto.*;
import com.ruoyi.home.service.HomeService;
import com.ruoyi.production.dto.ProductOrderDto;
import com.ruoyi.production.dto.ProductWorkOrderDto;
import com.ruoyi.production.dto.SalesLedgerWorkDto;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
@@ -59,6 +54,47 @@
        return AjaxResult.success(count);
    }
    @GetMapping("/deptStaffDistribution")
    @ApiOperation("各部门人员分布")
    public AjaxResult deptStaffDistribution() {
        DeptStaffDistributionDto dto = homeService.deptStaffDistribution();
        return AjaxResult.success(dto);
    }
    @GetMapping("/summaryStatistics")
    @ApiOperation("员工-客户-供应商总数")
    public AjaxResult summaryStatistics() {
        HomeSummaryDto homeSummaryDto = homeService.summaryStatistics();
        return AjaxResult.success(homeSummaryDto);
    }
    @GetMapping("/supplierPurchaseRanking")
    @ApiOperation("供应商采购排名")
    public AjaxResult supplierPurchaseRanking(@RequestParam(value = "type", defaultValue = "1") Integer type) {
        List<SupplierPurchaseRankingDto> list = homeService.supplierPurchaseRanking(type);
        return AjaxResult.success(list);
    }
    @GetMapping("/customerRevenueAnalysis")
    @ApiOperation("客户营收贡献数值分析")
    public AjaxResult customerRevenueAnalysis(@RequestParam("customerId") Long customerId, @RequestParam(value = "type", defaultValue = "1") Integer type) {
        CustomerRevenueAnalysisDto dto = homeService.customerRevenueAnalysis(customerId, type);
        return AjaxResult.success(dto);
    }
    @GetMapping("/productCategoryDistribution")
    @ApiOperation("产品大类分布")
    public AjaxResult productCategoryDistribution() {
        ProductCategoryDistributionDto dto = homeService.productCategoryDistribution();
        return AjaxResult.success(dto);
    }
    @GetMapping("/customerContributionRanking")
    @ApiOperation("客户金额贡献排名")
    public AjaxResult customerContributionRanking(@RequestParam(value = "type", defaultValue = "1") Integer type) {
        List<CustomerContributionRankingDto> list = homeService.customerContributionRanking(type);
        return AjaxResult.success(list);
    }
    /********************************************************营销采购类**************************************************/
    @GetMapping("/business")
src/main/java/com/ruoyi/home/dto/CustomerContributionRankingDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
package com.ruoyi.home.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
 * å®¢æˆ·é‡‘额贡献排名DTO
 */
@Data
@ApiModel("客户金额贡献排名")
public class CustomerContributionRankingDto {
    @ApiModelProperty("客户名称")
    private String customerName;
    @ApiModelProperty("合同总金额")
    private BigDecimal totalAmount;
}
src/main/java/com/ruoyi/home/dto/CustomerRevenueAnalysisDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,19 @@
package com.ruoyi.home.dto;
import com.ruoyi.dto.MapDto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
 * å®¢æˆ·è¥æ”¶è´¡çŒ®æ•°å€¼åˆ†æžDTO
 */
@Data
@ApiModel("客户营收贡献数值分析")
public class CustomerRevenueAnalysisDto {
    @ApiModelProperty("分析条目列表")
    private List<MapDto> items;
}
src/main/java/com/ruoyi/home/dto/DeptStaffDistributionDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
package com.ruoyi.home.dto;
import com.ruoyi.dto.MapDto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
 * éƒ¨é—¨äººå‘˜åˆ†å¸ƒç»Ÿè®¡DTO
 */
@Data
@ApiModel("部门人员分布统计")
public class DeptStaffDistributionDto {
    @ApiModelProperty("部门总人数")
    private Long total;
    @ApiModelProperty("部门分布列表")
    private List<MapDto> items;
}
src/main/java/com/ruoyi/home/dto/HomeSummaryDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
package com.ruoyi.home.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * é¦–页汇总统计DTO
 */
@Data
@ApiModel("首页汇总统计")
public class HomeSummaryDto {
    @ApiModelProperty("总工作人员")
    private Long totalStaff;
    @ApiModelProperty("总工作人员同比增长率")
    private String staffGrowthRate;
    @ApiModelProperty("总客户数")
    private Long totalCustomer;
    @ApiModelProperty("总客户同比增长率")
    private String customerGrowthRate;
    @ApiModelProperty("总供应商数")
    private Long totalSupplier;
    @ApiModelProperty("总供应商同比增长率")
    private String supplierGrowthRate;
}
src/main/java/com/ruoyi/home/dto/ProductCategoryDistributionDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
package com.ruoyi.home.dto;
import com.ruoyi.dto.MapDto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
 * äº§å“å¤§ç±»åˆ†å¸ƒç»Ÿè®¡DTO
 */
@Data
@ApiModel("产品大类分布统计")
public class ProductCategoryDistributionDto {
    @ApiModelProperty("大类分布列表")
    private List<MajorCategoryDto> items;
    @Data
    public static class MajorCategoryDto {
        @ApiModelProperty("大类名称")
        private String name;
        @ApiModelProperty("库存总数")
        private String value;
        @ApiModelProperty("占比")
        private String rate;
        @ApiModelProperty("小类分布详情")
        private List<MinorCategoryDto> children;
    }
    @Data
    public static class MinorCategoryDto {
        @ApiModelProperty("小类名称")
        private String name;
        @ApiModelProperty("库存数量")
        private String value;
        @ApiModelProperty("占比")
        private String rate;
        @ApiModelProperty("型号分布详情")
        private List<MapDto> children;
    }
}
src/main/java/com/ruoyi/home/dto/SupplierPurchaseRankingDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
package com.ruoyi.home.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
 * ä¾›åº”商采购排名DTO
 */
@Data
@ApiModel("供应商采购排名")
public class SupplierPurchaseRankingDto {
    @ApiModelProperty("供应商名称")
    private String supplierName;
    @ApiModelProperty("采购总金额")
    private BigDecimal totalAmount;
}
src/main/java/com/ruoyi/home/service/HomeService.java
@@ -33,4 +33,16 @@
    ProductionProgressDto productionProgress();
    ProductionTurnoverDto workInProcessTurnover();
    DeptStaffDistributionDto deptStaffDistribution();
    HomeSummaryDto summaryStatistics();
    List<SupplierPurchaseRankingDto> supplierPurchaseRanking(Integer type);
    CustomerRevenueAnalysisDto customerRevenueAnalysis(Long customerId, Integer type);
    ProductCategoryDistributionDto productCategoryDistribution();
    List<CustomerContributionRankingDto> customerContributionRanking(Integer type);
}
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -1,45 +1,43 @@
package com.ruoyi.home.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.approve.mapper.ApproveProcessMapper;
import com.ruoyi.approve.pojo.ApproveProcess;
import com.ruoyi.basic.mapper.CustomerMapper;
import com.ruoyi.basic.mapper.ProductMapper;
import com.ruoyi.basic.mapper.ProductModelMapper;
import com.ruoyi.basic.mapper.SupplierManageMapper;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.basic.pojo.Product;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.basic.pojo.SupplierManage;
import com.ruoyi.collaborativeApproval.mapper.NoticeMapper;
import com.ruoyi.collaborativeApproval.pojo.Notice;
import com.ruoyi.common.enums.ApproveTypeEnum;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.device.mapper.DeviceMaintenanceMapper;
import com.ruoyi.device.mapper.DeviceRepairMapper;
import com.ruoyi.device.pojo.DeviceMaintenance;
import com.ruoyi.device.pojo.DeviceRepair;
import com.ruoyi.dto.MapDto;
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.home.dto.*;
import com.ruoyi.home.service.HomeService;
import com.ruoyi.lavorissue.mapper.LavorIssueMapper;
import com.ruoyi.lavorissue.pojo.LaborIssue;
import com.ruoyi.procurementrecord.mapper.CustomStorageMapper;
import com.ruoyi.procurementrecord.mapper.ProcurementRecordMapper;
import com.ruoyi.procurementrecord.mapper.ProcurementRecordOutMapper;
import com.ruoyi.procurementrecord.pojo.CustomStorage;
import com.ruoyi.procurementrecord.pojo.ProcurementRecordOut;
import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.production.dto.ProductOrderDto;
import com.ruoyi.production.dto.ProductWorkOrderDto;
import com.ruoyi.production.dto.ProductionProductMainDto;
import com.ruoyi.production.mapper.ProductOrderMapper;
import com.ruoyi.production.mapper.ProductProcessMapper;
import com.ruoyi.production.mapper.ProductWorkOrderMapper;
import com.ruoyi.production.mapper.ProductionProductMainMapper;
import com.ruoyi.production.pojo.ProductOrder;
import com.ruoyi.production.pojo.ProductProcess;
import com.ruoyi.production.pojo.ProductWorkOrder;
import com.ruoyi.project.system.domain.SysDept;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.domain.SysUserDept;
import com.ruoyi.project.system.mapper.SysDeptMapper;
import com.ruoyi.project.system.mapper.SysUserDeptMapper;
import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.purchase.mapper.PaymentRegistrationMapper;
import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
import com.ruoyi.purchase.pojo.PaymentRegistration;
@@ -52,6 +50,9 @@
import com.ruoyi.sales.pojo.ReceiptPayment;
import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.staff.mapper.StaffOnJobMapper;
import com.ruoyi.staff.pojo.StaffOnJob;
import com.ruoyi.stock.mapper.StockInventoryMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -60,13 +61,11 @@
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/**
@@ -87,13 +86,7 @@
    private SalesLedgerProductMapper salesLedgerProductMapper;
    @Autowired
    private ProcurementRecordOutMapper procurementRecordOutMapper;
    @Autowired
    private ProcurementRecordMapper procurementRecordStorageMapper;
    @Autowired
    private CustomStorageMapper customStorageMapper;
    @Autowired
    private QualityInspectMapper qualityStatisticsMapper;
@@ -108,9 +101,6 @@
    private PaymentRegistrationMapper paymentRegistrationMapper;
    @Autowired
    private LavorIssueMapper lavorIssueMapper;
    @Autowired
    private SysDeptMapper sysDeptMapper;
    @Autowired
@@ -118,13 +108,25 @@
    @Autowired
    private ProductOrderMapper productOrderMapper;
    @Autowired
    private ProductProcessMapper productProcessMapper;
    @Autowired
    private ProductWorkOrderMapper productWorkOrderMapper;
    @Autowired
    private ProductModelMapper productModelMapper;
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private StockUtils stockUtils;
    @Autowired
    private StaffOnJobMapper staffOnJobMapper;
    @Autowired
    private CustomerMapper customerMapper;
    @Autowired
    private SupplierManageMapper supplierManageMapper;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private SysUserDeptMapper sysUserDeptMapper;
    private StockInventoryMapper stockInventoryMapper;
    @Override
    public HomeBusinessDto business() {
        // æž„建结果
@@ -136,7 +138,7 @@
        salesLedgerLambdaQueryWrapper.ge(SalesLedger::getEntryDate, currentMonth.atDay(1).atStartOfDay())  // å¤§äºŽç­‰äºŽæœ¬æœˆç¬¬ä¸€å¤©
                .lt(SalesLedger::getEntryDate, currentMonth.plusMonths(1).atDay(1).atStartOfDay()); // å°äºŽä¸‹æœˆç¬¬ä¸€å¤©
        List<SalesLedger> salesLedgers = salesLedgerMapper.selectList(salesLedgerLambdaQueryWrapper);
        if(!CollectionUtils.isEmpty(salesLedgers)){
        if (!CollectionUtils.isEmpty(salesLedgers)) {
            // åˆè®¡åˆåŒé‡‘额
            BigDecimal contractAmount = salesLedgers.stream().map(SalesLedger::getContractAmount)
                    .filter(Objects::nonNull)
@@ -158,7 +160,7 @@
                .lt(PurchaseLedger::getEntryDate, currentMonth.plusMonths(1).atDay(1).atStartOfDay()); // å°äºŽä¸‹æœˆç¬¬ä¸€å¤©
        // æ‰§è¡ŒæŸ¥è¯¢å¹¶è®¡ç®—总和
        List<PurchaseLedger> purchaseLedgers = purchaseLedgerMapper.selectList(queryWrapper);
        if(!CollectionUtils.isEmpty(purchaseLedgers)){
        if (!CollectionUtils.isEmpty(purchaseLedgers)) {
            LambdaQueryWrapper<SalesLedgerProduct> salesLedgerProductMapperLambdaQueryWrapperCopy = new LambdaQueryWrapper<SalesLedgerProduct>();
            salesLedgerProductMapperLambdaQueryWrapperCopy.eq(SalesLedgerProduct::getType, 2)
                    .in(SalesLedgerProduct::getSalesLedgerId, purchaseLedgers.stream().map(PurchaseLedger::getId).collect(Collectors.toList()));
@@ -194,17 +196,9 @@
//                .filter(Objects::nonNull)
//                .reduce(BigDecimal.ZERO, BigDecimal::add);
//        BigDecimal stock = stockAmount.add(customStockAmount).subtract(outboundAmount);
        IPage<ProductModel> productModelIPage = productModelMapper.listPageProductModel(new Page<>(1, -1), new ProductModel());
        if(!CollectionUtils.isEmpty(productModelIPage.getRecords())){
            //获取规格id
            List<Long> modelIds = productModelIPage.getRecords().stream().map(ProductModel::getId).collect(Collectors.toList());
            BigDecimal stockQuantityTotal = modelIds.stream()
                    .map(stockUtils::getStockQuantity)
                    .map(map -> map.get("stockQuantity"))
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            homeBusinessDto.setInventoryNum(stockQuantityTotal.setScale(2, RoundingMode.HALF_UP).toString());
        }
        BigDecimal stockQuantityTotal = stockInventoryMapper.selectTotal();
        homeBusinessDto.setInventoryNum(stockQuantityTotal.setScale(2, RoundingMode.HALF_UP).toString());
        // èŽ·å–å½“å¤©å…¥åº“æ•°é‡
        LambdaQueryWrapper<ProcurementRecordStorage> procurementRecordStorageLambdaQueryWrapper = new LambdaQueryWrapper<>();
@@ -254,9 +248,9 @@
        BigDecimal subtract = weekContractAmount.subtract(lastYearWeekContractAmount);
        String weekYny = "";
        // å‘¨åŒæ¯”
        if(subtract.compareTo(BigDecimal.ZERO) == 0 || lastYearWeekContractAmount.compareTo(BigDecimal.ZERO) == 0){
        if (subtract.compareTo(BigDecimal.ZERO) == 0 || lastYearWeekContractAmount.compareTo(BigDecimal.ZERO) == 0) {
            weekYny = "0.00";
        }else{
        } else {
            weekYny = String.format("%.2f", subtract.divide(lastYearWeekContractAmount, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));
        }
@@ -279,9 +273,9 @@
        BigDecimal subtract1 = todayContractAmount.subtract(lastYearYesterdayContractAmount); // ä¿®æ”¹ï¼šä½¿ç”¨ todayContractAmount è€Œä¸æ˜¯ yesterdayContractAmount
        // æ—¥çŽ¯æ¯”
        String chain = "";
        if(subtract1.compareTo(BigDecimal.ZERO) == 0 || lastYearYesterdayContractAmount.compareTo(BigDecimal.ZERO) == 0){
        if (subtract1.compareTo(BigDecimal.ZERO) == 0 || lastYearYesterdayContractAmount.compareTo(BigDecimal.ZERO) == 0) {
            chain = "0.00";
        }else{
        } else {
            chain = String.format("%.2f", subtract1.divide(lastYearYesterdayContractAmount, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));
        }
@@ -295,14 +289,14 @@
        Map<String, BigDecimal> collect = salesLedgers.stream().collect(Collectors.groupingBy(SalesLedger::getCustomerName, Collectors.reducing(BigDecimal.ZERO,
                SalesLedger::getContractAmount, BigDecimal::add)));
        List<MapDto> mapDtos = new ArrayList<>();
        collect.forEach((k,v)->{
        collect.forEach((k, v) -> {
            MapDto mapDto = new MapDto();
            mapDto.setName(k);
            // ä¿®æ”¹ï¼šå°†é‡‘额值保留两位小数
            mapDto.setValue(v.setScale(2, RoundingMode.HALF_UP).toString());
            if(contractAmount.compareTo(new BigDecimal(0)) == 0){
            if (contractAmount.compareTo(new BigDecimal(0)) == 0) {
                mapDto.setRate("0");
            }else{
            } else {
                mapDto.setRate(String.format("%.2f", v.divide(contractAmount, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100"))));
            }
            mapDtos.add(mapDto);
@@ -348,7 +342,7 @@
                    .filter(inspect -> inspect.getInspectType().equals(1))
                    .map(QualityInspect::getQuantity)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            processNum= processNum.add(reduce1);
            processNum = processNum.add(reduce1);
            BigDecimal reduce2 = monthInspects.stream()
                    .filter(inspect -> inspect.getInspectType().equals(2))
                    .map(QualityInspect::getQuantity)
@@ -403,9 +397,15 @@
                .ne(ApproveProcess::getApproveStatus, 2);
//                .eq(ApproveProcess::getTenantId, loginUser.getTenantId());
        List<ApproveProcess> approveProcesses = approveProcessMapper.selectList(approveProcessLambdaQueryWrapper);
        if(CollectionUtils.isEmpty(approveProcesses)){
        if (CollectionUtils.isEmpty(approveProcesses)) {
            approveProcesses = new ArrayList<>();
        }
        approveProcesses.forEach(a -> {
            if (a.getApproveType() != null) {
                a.setApproveTypeName(ApproveTypeEnum.getNameByCode(a.getApproveType()));
            }
        });
//        // æŸ¥è¯¢æœªé¢†ç”¨åŠ³ä¿è®°å½•
//        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//
@@ -423,11 +423,12 @@
//                approveProcesses.add(approveProcess);
//            }
//        }
        return approveProcesses;
    }
    /**
     *
     * @param type 1-周 2-月 3-季度
     * @return
     */
@@ -436,7 +437,7 @@
        LocalDate today = LocalDate.now();
        LocalDate startDate = null;
        LocalDate endDate = null;
        switch (type){
        switch (type) {
            case 1:
                // èŽ·å–æœ¬å‘¨å‘¨ä¸€
                startDate = today.with(DayOfWeek.MONDAY);
@@ -494,6 +495,7 @@
        return statisticsReceivablePayableDto;
    }
    public static <T> BigDecimal sumAmount(List<T> list, java.util.function.Function<T, BigDecimal> amountExtractor) {
        return list.stream()
                // æå–金额时,将null替换为BigDecimal.ZERO
@@ -501,6 +503,7 @@
                // ç´¯åŠ ï¼Œåˆå§‹å€¼ä¸º0,避免空流问题
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
    @Autowired
    private DeviceRepairMapper deviceRepairMapper;
@@ -543,9 +546,10 @@
        productionProgressDto.setTotalOrderCount(totalCount);
        productionProgressDto.setCompletedOrderCount(count);
        productionProgressDto.setUncompletedOrderCount(count2);
        productionProgressDto.setPartialCompletedOrderCount(totalCount-count-count2);
        productionProgressDto.setPartialCompletedOrderCount(totalCount - count - count2);
        return productionProgressDto;
    }
    @Override
    public ProductionTurnoverDto workInProcessTurnover() {
        ProductionTurnoverDto productionTurnoverDto = new ProductionTurnoverDto();
@@ -558,15 +562,15 @@
                .map(ProductWorkOrder::getPlanQuantity)
                .mapToLong(BigDecimal::longValue)
                .sum();
        if (sum == 0)return null;
        if (sum == 0) return null;
        productionTurnoverDto.setTotalOrderCount(sum);//总在制品数量
        productionTurnoverDto.setAverageTurnoverDays(BigDecimal.valueOf(sum).divide(BigDecimal.valueOf(ChronoUnit.DAYS.between(LocalDateTime.now().minusMonths(1), LocalDateTime.now())),2,RoundingMode.HALF_UP));
        productionTurnoverDto.setAverageTurnoverDays(BigDecimal.valueOf(sum).divide(BigDecimal.valueOf(ChronoUnit.DAYS.between(LocalDateTime.now().minusMonths(1), LocalDateTime.now())), 2, RoundingMode.HALF_UP));
        long completeQuantity = productWorkOrders.stream()
                .filter(productWorkOrder -> productWorkOrder.getCompleteQuantity().compareTo(productWorkOrder.getPlanQuantity()) >= 0)
                .map(ProductWorkOrder::getCompleteQuantity)
                .mapToLong(BigDecimal::longValue)
                .sum();
        productionTurnoverDto.setTurnoverEfficiency(BigDecimal.valueOf(completeQuantity).divide(BigDecimal.valueOf(sum),2,RoundingMode.HALF_UP));
        productionTurnoverDto.setTurnoverEfficiency(BigDecimal.valueOf(completeQuantity).divide(BigDecimal.valueOf(sum), 2, RoundingMode.HALF_UP));
        Map<String, List<ProductWorkOrderDto>> map = productWorkOrders.stream()
                .filter(productWorkOrder -> productWorkOrder.getPlanQuantity().compareTo(productWorkOrder.getCompleteQuantity()) > 0)
                .collect(Collectors.groupingBy(ProductWorkOrderDto::getProcessName));
@@ -581,6 +585,343 @@
        productionTurnoverDto.setProcessDetails(strings);
        productionTurnoverDto.setProcessQuantityDetails(processQuantityDetails);
        return productionTurnoverDto;
    }
    @Override
    public DeptStaffDistributionDto deptStaffDistribution() {
        DeptStaffDistributionDto dto = new DeptStaffDistributionDto();
        List<MapDto> items = new ArrayList<>();
        // æŸ¥è¯¢æ‰€æœ‰æ­£å¸¸ä¸”未删除的部门
        List<SysDept> depts = sysDeptMapper.selectDeptList(new SysDept());
        if (CollectionUtils.isEmpty(depts)) {
            dto.setItems(items);
            return dto;
        }
        long totalUsers = 0;
        List<Map<String, Object>> countsByDept = new ArrayList<>();
        for (SysDept dept : depts) {
            if ("0".equals(dept.getStatus()) && "0".equals(dept.getDelFlag())) {
                Long count = sysUserDeptMapper.selectCount(new LambdaQueryWrapper<SysUserDept>()
                        .eq(SysUserDept::getDeptId, dept.getDeptId()));
                if (count > 0) {
                    Map<String, Object> map = new HashMap<>();
                    map.put("name", dept.getDeptName());
                    map.put("count", count);
                    countsByDept.add(map);
                    totalUsers += count;
                }
            }
        }
        if (totalUsers > 0) {
            BigDecimal total = BigDecimal.valueOf(totalUsers);
            for (Map<String, Object> map : countsByDept) {
                MapDto mapDto = new MapDto();
                mapDto.setName((String) map.get("name"));
                Long count = (Long) map.get("count");
                mapDto.setValue(count.toString());
                mapDto.setRate(BigDecimal.valueOf(count).multiply(new BigDecimal("100"))
                        .divide(total, 2, RoundingMode.HALF_UP).toString());
                items.add(mapDto);
            }
        }
        dto.setTotal(totalUsers);
        dto.setItems(items);
        return dto;
    }
    @Override
    public HomeSummaryDto summaryStatistics() {
        HomeSummaryDto dto = new HomeSummaryDto();
        LocalDate now = LocalDate.now();
        YearMonth currentMonth = YearMonth.from(now);
        YearMonth prevMonth = currentMonth.minusMonths(1);
        LocalDateTime currentMonthEnd = currentMonth.atEndOfMonth().atTime(23, 59, 59);
        LocalDateTime prevMonthEnd = prevMonth.atEndOfMonth().atTime(23, 59, 59);
        //  æ€»å·¥ä½œäººå‘˜
        Long currentStaff = countStaff(currentMonthEnd);
        Long prevStaff = countStaff(prevMonthEnd);
        dto.setTotalStaff(currentStaff);
        dto.setStaffGrowthRate(calculateMoM(currentStaff, prevStaff));
        //  æ€»å®¢æˆ·æ•°
        Long currentCustomers = countCustomers(currentMonthEnd);
        Long prevCustomers = countCustomers(prevMonthEnd);
        dto.setTotalCustomer(currentCustomers);
        dto.setCustomerGrowthRate(calculateMoM(currentCustomers, prevCustomers));
        //  æ€»ä¾›åº”商数
        Long currentSuppliers = countSuppliers(currentMonthEnd);
        Long prevSuppliers = countSuppliers(prevMonthEnd);
        dto.setTotalSupplier(currentSuppliers);
        dto.setSupplierGrowthRate(calculateMoM(currentSuppliers, prevSuppliers));
        return dto;
    }
    private Long countStaff(LocalDateTime dateTime) {
        Long sysUserCount = sysUserMapper.selectCount(new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getDelFlag, "0")
                .le(SysUser::getCreateTime, dateTime));
        Long staffCountItem = staffOnJobMapper.selectCount(new LambdaQueryWrapper<StaffOnJob>()
                .le(StaffOnJob::getCreateTime, dateTime));
        return sysUserCount + staffCountItem;
    }
    private Long countCustomers(LocalDateTime dateTime) {
        return customerMapper.selectCount(new LambdaQueryWrapper<Customer>()
                .le(Customer::getMaintenanceTime, dateTime.toLocalDate()));
    }
    private Long countSuppliers(LocalDateTime dateTime) {
        return supplierManageMapper.selectCount(new LambdaQueryWrapper<SupplierManage>()
                .le(SupplierManage::getCreateTime, dateTime));
    }
    private String calculateMoM(Number current, Number prev) {
        BigDecimal curVal = new BigDecimal(current.toString());
        BigDecimal prevVal = new BigDecimal(prev.toString());
        if (prevVal.compareTo(BigDecimal.ZERO) == 0) {
            return curVal.compareTo(BigDecimal.ZERO) > 0 ? "100.00" : "0.00";
        }
        return curVal.subtract(prevVal)
                .divide(prevVal, 4, RoundingMode.HALF_UP)
                .multiply(new BigDecimal("100"))
                .setScale(2, RoundingMode.HALF_UP)
                .toString();
    }
    @Override
    public List<SupplierPurchaseRankingDto> supplierPurchaseRanking(Integer type) {
        LocalDate today = LocalDate.now();
        LocalDate startDate;
        LocalDate endDate;
        switch (type) {
            case 1: // å‘¨
                startDate = today.with(DayOfWeek.MONDAY);
                endDate = today.with(DayOfWeek.SUNDAY);
                break;
            case 2: // æœˆ
                startDate = today.with(TemporalAdjusters.firstDayOfMonth());
                endDate = today.with(TemporalAdjusters.lastDayOfMonth());
                break;
            case 3: // å­£åº¦
                Month currentMonth = today.getMonth();
                Month firstMonthOfQuarter = currentMonth.firstMonthOfQuarter();
                Month lastMonthOfQuarter = Month.of(firstMonthOfQuarter.getValue() + 2);
                startDate = today.withMonth(firstMonthOfQuarter.getValue()).with(TemporalAdjusters.firstDayOfMonth());
                endDate = today.withMonth(lastMonthOfQuarter.getValue()).with(TemporalAdjusters.lastDayOfMonth());
                break;
            default:
                return new ArrayList<>();
        }
        QueryWrapper<PurchaseLedger> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("supplier_name", "SUM(contract_amount) as total_amount")
                .ge("entry_date", startDate)
                .le("entry_date", endDate)
//                .ne("approval_status", 3)
                .groupBy("supplier_name")
                .orderByDesc("total_amount")
                .last("LIMIT 5");
        List<Map<String, Object>> maps = purchaseLedgerMapper.selectMaps(queryWrapper);
        return maps.stream().map(map -> {
            SupplierPurchaseRankingDto dto = new SupplierPurchaseRankingDto();
            dto.setSupplierName(map.get("supplier_name") != null ? map.get("supplier_name").toString() : "");
            Object amount = map.get("total_amount");
            dto.setTotalAmount(amount != null ? new BigDecimal(amount.toString()) : BigDecimal.ZERO);
            return dto;
        }).collect(Collectors.toList());
    }
    @Override
    public CustomerRevenueAnalysisDto customerRevenueAnalysis(Long customerId, Integer type) {
        CustomerRevenueAnalysisDto dto = new CustomerRevenueAnalysisDto();
        List<MapDto> items = new ArrayList<>();
        LocalDate today = LocalDate.now();
        LocalDate start;
        LocalDate end;
        boolean groupByMonth = false;
        switch (type) {
            case 1: // å‘¨
                start = today.with(DayOfWeek.MONDAY);
                end = today.with(DayOfWeek.SUNDAY);
                break;
            case 2: // æœˆ
                start = today.with(TemporalAdjusters.firstDayOfMonth());
                end = today.with(TemporalAdjusters.lastDayOfMonth());
                break;
            case 3: // å­£åº¦
                Month firstMonthOfQuarter = today.getMonth().firstMonthOfQuarter();
                start = today.withMonth(firstMonthOfQuarter.getValue()).with(TemporalAdjusters.firstDayOfMonth());
                end = today.withMonth(firstMonthOfQuarter.plus(2).getValue()).with(TemporalAdjusters.lastDayOfMonth());
                groupByMonth = true;
                break;
            default:
                dto.setItems(items);
                return dto;
        }
        List<SalesLedger> list = salesLedgerMapper.selectList(new LambdaQueryWrapper<SalesLedger>()
                .eq(SalesLedger::getCustomerId, customerId)
                .ge(SalesLedger::getEntryDate, start)
                .le(SalesLedger::getEntryDate, end));
        if (groupByMonth) {
            for (int i = 0; i < 3; i++) {
                LocalDate m = start.plusMonths(i);
                String monthName = m.getMonthValue() + "月";
                BigDecimal sum = list.stream()
                        .filter(l -> l.getEntryDate() != null)
                        .filter(l -> {
                            LocalDate ld = l.getEntryDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                            return ld.getMonth() == m.getMonth() && ld.getYear() == m.getYear();
                        })
                        .map(SalesLedger::getContractAmount)
                        .filter(Objects::nonNull)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                MapDto mapDto = new MapDto();
                mapDto.setName(monthName);
                mapDto.setValue(sum.setScale(2, RoundingMode.HALF_UP).toString());
                items.add(mapDto);
            }
        } else {
            long days = ChronoUnit.DAYS.between(start, end) + 1;
            for (int i = 0; i < days; i++) {
                LocalDate d = start.plusDays(i);
                String dayName = d.getMonthValue() + "/" + d.getDayOfMonth();
                BigDecimal sum = list.stream()
                        .filter(l -> l.getEntryDate() != null)
                        .filter(l -> l.getEntryDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().equals(d))
                        .map(SalesLedger::getContractAmount)
                        .filter(Objects::nonNull)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                MapDto mapDto = new MapDto();
                mapDto.setName(dayName);
                mapDto.setValue(sum.setScale(2, RoundingMode.HALF_UP).toString());
                items.add(mapDto);
            }
        }
        dto.setItems(items);
        return dto;
    }
    @Override
    public ProductCategoryDistributionDto productCategoryDistribution() {
        ProductCategoryDistributionDto dto = new ProductCategoryDistributionDto();
        List<ProductCategoryDistributionDto.MajorCategoryDto> majorItems = new ArrayList<>();
        // æŸ¥è¯¢æ‰€æœ‰çš„产品类别
        List<Product> allProducts = productMapper.selectList(new LambdaQueryWrapper<>());
        if (CollectionUtils.isEmpty(allProducts)) {
            dto.setItems(majorItems);
            return dto;
        }
        // åˆ†ç¦»å¤§ç±»å’Œå°ç±»
        List<Product> majorCategories = allProducts.stream()
                .filter(p -> p.getParentId() == null)
                .collect(Collectors.toList());
        List<Product> minorCategories = allProducts.stream()
                .filter(p -> p.getParentId() != null)
                .collect(Collectors.toList());
        // æŒ‰çˆ¶ç±»ID对小类进行分组
        Map<Long, List<Product>> minorGroupMap = minorCategories.stream()
                .collect(Collectors.groupingBy(Product::getParentId));
        int totalMinorCount = minorCategories.size();
        for (Product major : majorCategories) {
            ProductCategoryDistributionDto.MajorCategoryDto majorDto = new ProductCategoryDistributionDto.MajorCategoryDto();
            majorDto.setName(major.getProductName());
            List<Product> children = minorGroupMap.getOrDefault(major.getId(), new ArrayList<>());
            int childrenSize = children.size();
            // è®¾ç½®å°ç±»çš„æ€»æ•°
            majorDto.setValue(String.valueOf(childrenSize));
            // è®¡ç®—占比
            if (totalMinorCount > 0) {
                BigDecimal rate = BigDecimal.valueOf(childrenSize)
                        .multiply(new BigDecimal("100"))
                        .divide(BigDecimal.valueOf(totalMinorCount), 2, RoundingMode.HALF_UP);
                majorDto.setRate(rate.toString());
            } else {
                majorDto.setRate("0.00");
            }
            List<ProductCategoryDistributionDto.MinorCategoryDto> minorDtos = new ArrayList<>();
            for (Product minor : children) {
                ProductCategoryDistributionDto.MinorCategoryDto minorDto = new ProductCategoryDistributionDto.MinorCategoryDto();
                minorDto.setName(minor.getProductName());
                minorDto.setValue("0");
                minorDto.setRate("0.00");
                minorDto.setChildren(new ArrayList<>());
                minorDtos.add(minorDto);
            }
            majorDto.setChildren(minorDtos);
            majorItems.add(majorDto);
        }
        dto.setItems(majorItems);
        return dto;
    }
    @Override
    public List<CustomerContributionRankingDto> customerContributionRanking(Integer type) {
        LocalDate today = LocalDate.now();
        LocalDate startDate = null;
        LocalDate endDate = null;
        switch (type) {
            case 1:
                startDate = today.with(DayOfWeek.MONDAY);
                endDate = today.with(DayOfWeek.SUNDAY);
                break;
            case 2:
                startDate = today.with(TemporalAdjusters.firstDayOfMonth());
                endDate = today.with(TemporalAdjusters.lastDayOfMonth());
                break;
            case 3:
                Month currentMonth = today.getMonth();
                Month firstMonthOfQuarter = currentMonth.firstMonthOfQuarter();
                Month lastMonthOfQuarter = Month.of(firstMonthOfQuarter.getValue() + 2);
                startDate = today.withMonth(firstMonthOfQuarter.getValue()).with(TemporalAdjusters.firstDayOfMonth());
                endDate = today.withMonth(lastMonthOfQuarter.getValue()).with(TemporalAdjusters.lastDayOfMonth());
                break;
        }
        QueryWrapper<SalesLedger> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("customer_name", "SUM(contract_amount) as total_amount")
                .isNotNull("customer_name")
                .groupBy("customer_name")
                .orderByDesc("total_amount")
                .last("LIMIT 5");
        if (startDate != null && endDate != null) {
            queryWrapper.between("entry_date", startDate, endDate);
        }
        List<Map<String, Object>> maps = salesLedgerMapper.selectMaps(queryWrapper);
        List<CustomerContributionRankingDto> result = new ArrayList<>();
        for (Map<String, Object> map : maps) {
            CustomerContributionRankingDto rankingDto = new CustomerContributionRankingDto();
            rankingDto.setCustomerName(map.get("customer_name").toString());
            rankingDto.setTotalAmount(map.get("total_amount") != null ? new BigDecimal(map.get("total_amount").toString()) : BigDecimal.ZERO);
            result.add(rankingDto);
        }
        return result;
    }
}
src/main/java/com/ruoyi/http/service/RealTimeEnergyConsumptionService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
package com.ruoyi.http.service;
/**
 * @author :yys
 * @date : 2026/1/27 16:02
 */
public interface RealTimeEnergyConsumptionService {
}
src/main/java/com/ruoyi/http/service/impl/RealTimeEnergyConsumptionServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,130 @@
package com.ruoyi.http.service.impl;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.http.service.RealTimeEnergyConsumptionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @author :yys
 * @date : 2026/1/27 16:02
 */
@Service
@Slf4j
public class RealTimeEnergyConsumptionServiceImpl implements RealTimeEnergyConsumptionService {
    private static final String URL = "https://new.e-elitech.cn/api/data-api";
    private static final String TOKEN_URL = "/elitechAccess/getToken";
    private static final String REAL_TIME_URL = "/elitechAccess/v2/getRealTimeData"; //获取设备实时数据
    private static final String KET_ID = "75804708";
    private static final String KEY_SECRET = "xTUGToozKpYgUPqTsZzB";
    private static final String USER_NAME = "用户30773662";
    private static final String PASS_WORD = "y17775163675";
    private static final String DEVICE_GUID = "90444196515214284663";
    /**
     * æ ¹æ®paramCode提取探头参数
     * @param paramList è®¾å¤‡å‚数数组
     * @param targetCode ç›®æ ‡æŽ¢å¤´ç¼–码
     * @return æŽ¢å¤´å‚数对象(包含name/value/unit)
     */
    private static JSONObject getProbeParam(JSONArray paramList, String targetCode) {
        for (int i = 0; i < paramList.size(); i++) {
            JSONObject paramObj = paramList.getJSONObject(i);
            if (targetCode.equals(paramObj.getString("paramCode"))) {
                return paramObj;
            }
        }
        return new JSONObject(); // æœªåŒ¹é…åˆ°è¿”回空对象,避免空指针
    }
    /**
     * å®žæ—¶èŽ·å–æ¸©æ¹¿åº¦ï¼ŒäºŒæ°§åŒ–ç¢³æ•°æ®
     */
    public static void main(String[] args) {
        String realTimeData = getRealTimeData(getToken());
        Map<String, Object> map = JSON.parseObject(realTimeData, Map.class);
        if(map.get("code").equals(0)){
            // 1. è§£æžå¤–层data为JSON数组(接口返回的设备列表)
            JSONArray deviceList = JSON.parseArray(map.get("data").toString());
            // 2. éåŽ†è®¾å¤‡åˆ—è¡¨ï¼ˆæ­¤å¤„ä»…å–ç¬¬ä¸€ä¸ªè®¾å¤‡ï¼Œè‹¥æœ‰å¤šä¸ªè®¾å¤‡å¯å¾ªçŽ¯å¤„ç†ï¼‰
            if (!deviceList.isEmpty()) {
                JSONObject deviceObj = deviceList.getJSONObject(0);
                // 3. è§£æžè®¾å¤‡å†…的参数数组(所有paramCode对应的参数)
                JSONArray paramList = deviceObj.getJSONArray("data");
                // 4. å®šä¹‰ç›®æ ‡æŽ¢å¤´çš„paramCode,按需扩展
                String[] targetCodes = {"0100", "0110", "0120", "0130"};
                for (String code : targetCodes) {
                    // 5. éåŽ†å‚æ•°æ•°ç»„ï¼ŒåŒ¹é…ç›®æ ‡paramCode
                    for (int i = 0; i < paramList.size(); i++) {
                        JSONObject paramObj = paramList.getJSONObject(i);
                        String currentCode = paramObj.getString("paramCode");
                        if (code.equals(currentCode)) {
                            // 6. æå–核心字段(值、单位、探头名称)
                            String paramName = paramObj.getString("paramName"); // æŽ¢å¤´1/探头2...
                            String value = paramObj.getString("value");       // æ•°å€¼ï¼ˆ345.80/24.90...)
                            String unitCode = paramObj.getString("unitCode"); // å•位(Lux/℃/%RH/ppm)
                            // 7. ä¸šåŠ¡å¤„ç†ï¼šæ‰“å°/赋值/存储等(按需修改)
                            System.out.println(paramName + ":" + value + " " + unitCode);
                            // åŒ¹é…åˆ°åŽç›´æŽ¥è·³å‡ºå†…层循环,提升效率
                            break;
                        }
                    }
                }
            }
        }
        System.out.println();
    }
    public static String getToken(){
        Map<String, String> param = new HashMap<>();
        param.put("keyId", KET_ID);
        param.put("keySecret", KEY_SECRET);
        param.put("userName", USER_NAME);
        param.put("password", PASS_WORD);
        log.info("请求参数:{}", JSON.toJSONString( param));
        String result = HttpUtils.sendPostJson(URL + TOKEN_URL, JSON.toJSONString(param));
        log.info("返回结果:{}", result);
        Map<String, Object> map = JSON.parseObject(result, Map.class);
        if (map.get("code").equals(0)) {
            Object token = map.get("data");
            log.info("token:{}", token);
            return token.toString();
        }
        return result;
    }
    public static String getRealTimeData(String  token){
        Map<String, Object> param = new HashMap<>();
        param.put("keyId", KET_ID);
        param.put("keySecret", KEY_SECRET);
        param.put("deviceGuids", Collections.singletonList(DEVICE_GUID));
        log.info("请求参数:{}", JSON.toJSONString( param));
        String result = HttpUtils.sendPostJson(URL + REAL_TIME_URL, JSON.toJSONString(param),token);
        log.info("返回结果:{}", result);
        return result;
    }
}
src/main/java/com/ruoyi/inspectiontask/controller/InspectionTaskController.java
@@ -15,6 +15,7 @@
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
 * @author :yys
@@ -58,7 +59,7 @@
    @PostMapping("/addOrEditInspectionTask")
    @ApiOperation("巡检任务表新增修改")
    @Transactional(rollbackFor = Exception.class)
    public R addOrEditInspectionTask(@RequestBody InspectionTaskDto inspectionTaskDto) {
    public R addOrEditInspectionTask(@RequestBody InspectionTaskDto inspectionTaskDto) throws IOException {
        return R.ok(inspectionTaskService.addOrEditInspectionTask(inspectionTaskDto));
    }
src/main/java/com/ruoyi/inspectiontask/dto/InspectionTaskDto.java
@@ -3,6 +3,7 @@
import com.ruoyi.basic.dto.StorageBlobDTO;
import com.ruoyi.basic.pojo.StorageAttachment;
import com.ruoyi.inspectiontask.pojo.InspectionTask;
import com.ruoyi.sales.pojo.CommonFile;
import lombok.Data;
import java.util.List;
@@ -10,11 +11,16 @@
@Data
public class InspectionTaskDto extends InspectionTask {
    private List<StorageBlobDTO> storageBlobDTO;
    private List<StorageBlobDTO> beforeProduction;
    private List<StorageBlobDTO> afterProduction;
    private List<StorageBlobDTO> productionIssues;
//    private List<StorageBlobDTO> storageBlobDTO;
//    private List<StorageBlobDTO> beforeProduction;
//    private List<StorageBlobDTO> afterProduction;
//    private List<StorageBlobDTO> productionIssues;
//
//    private List<StorageAttachment> attachments;
    private List<StorageAttachment> attachments;
    private List<String> tempFileIds;
    private List<CommonFile> commonFileList; //生产中
    private List<CommonFile> commonFileListAfter;  //生产后
    private List<CommonFile> commonFileListBefore; //生产前
}
src/main/java/com/ruoyi/inspectiontask/service/InspectionTaskService.java
@@ -6,6 +6,8 @@
import com.ruoyi.inspectiontask.dto.InspectionTaskDto;
import com.ruoyi.inspectiontask.pojo.InspectionTask;
import java.io.IOException;
/**
 * @author :yys
 * @date : 2025/9/19 10:49
@@ -14,7 +16,7 @@
    IPage<InspectionTaskDto> selectInspectionTaskList(Page<InspectionTask> page, InspectionTaskDto inspectionTaskDto);
    int addOrEditInspectionTask(InspectionTaskDto inspectionTaskDto);
    int addOrEditInspectionTask(InspectionTaskDto inspectionTaskDto) throws IOException;
    int delByIds(Long[] ids);
}
src/main/java/com/ruoyi/inspectiontask/service/impl/InspectionTaskServiceImpl.java
@@ -11,6 +11,7 @@
import com.ruoyi.basic.pojo.StorageAttachment;
import com.ruoyi.basic.pojo.StorageBlob;
import com.ruoyi.basic.service.StorageAttachmentService;
import com.ruoyi.common.enums.FileNameType;
import com.ruoyi.common.utils.MinioUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
@@ -21,10 +22,15 @@
import com.ruoyi.inspectiontask.service.InspectionTaskService;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.sales.mapper.CommonFileMapper;
import com.ruoyi.sales.pojo.CommonFile;
import com.ruoyi.sales.service.impl.CommonFileServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
@@ -59,6 +65,12 @@
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private CommonFileMapper commonFileMapper;
    @Autowired
    private CommonFileServiceImpl commonFileService;
    @Override
    public IPage<InspectionTaskDto> selectInspectionTaskList(Page<InspectionTask> page, InspectionTaskDto inspectionTaskDto) {
@@ -114,21 +126,13 @@
                        (existing, replacement) -> existing));
        //处理附件
        Map<Long, List<StorageAttachment>> attachmentsMap = storageAttachmentMapper.selectList(new LambdaQueryWrapper<StorageAttachment>().in(StorageAttachment::getRecordId, ids)
                        .eq(StorageAttachment::getRecordType, InspectionTasks.ordinal()))
                .stream()
                .collect(Collectors.groupingBy(StorageAttachment::getRecordId));
        //  æ‰¹é‡æŸ¥è¯¢æ‰€æœ‰éœ€è¦çš„æ–‡ä»¶æ•°æ®
        Set<Long> blobIds = attachmentsMap.values()
                .stream()
                .flatMap(List::stream)
                .map(StorageAttachment::getStorageBlobId)
                .collect(Collectors.toSet());
        Map<Long, StorageBlob> blobMap = blobIds.isEmpty()
                ? Collections.emptyMap()
                : storageBlobMapper.selectList(new LambdaQueryWrapper<StorageBlob>().in(StorageBlob::getId, blobIds))
                .stream()
                .collect(Collectors.toMap(StorageBlob::getId, Function.identity()));
        List<CommonFile> commonFiles = commonFileMapper.selectList(new LambdaQueryWrapper<CommonFile>()
                .in(CommonFile::getCommonId, ids)
                .in(CommonFile::getType, Arrays.asList(FileNameType.INSPECTION.getValue(), FileNameType.INSPECTION_PRODUCTION_BEFORE.getValue(), FileNameType.INSPECTION_PRODUCTION_AFTER.getValue())));
        if(commonFiles == null){
            commonFiles = new ArrayList<>();
        }
        List<CommonFile> finalCommonFiles = commonFiles;
        List<InspectionTaskDto> dtoList = entityPage.getRecords().stream().map(inspectionTask -> {
            InspectionTaskDto dto = new InspectionTaskDto();
@@ -158,36 +162,10 @@
            dto.setDateStr(inspectionTask.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            // åˆå§‹åŒ–三个附件列表
            dto.setBeforeProduction(new ArrayList<>());
            dto.setAfterProduction(new ArrayList<>());
            dto.setProductionIssues(new ArrayList<>());
            dto.setCommonFileList(finalCommonFiles.stream().filter(commonFile -> commonFile.getType().equals(FileNameType.INSPECTION.getValue())).collect(Collectors.toList()));
            dto.setCommonFileListAfter(finalCommonFiles.stream().filter(commonFile -> commonFile.getType().equals(FileNameType.INSPECTION_PRODUCTION_AFTER.getValue())).collect(Collectors.toList()));
            dto.setCommonFileListBefore(finalCommonFiles.stream().filter(commonFile -> commonFile.getType().equals(FileNameType.INSPECTION_PRODUCTION_BEFORE.getValue())).collect(Collectors.toList()));
            // å¤„理附件分类
            Optional.ofNullable(attachmentsMap.get(inspectionTask.getId()))
                    .orElse(Collections.emptyList())
                    .forEach(attachment -> {
                        StorageBlob blob = blobMap.get(attachment.getStorageBlobId());
                        if (blob != null) {
                            // åˆ›å»ºé™„ä»¶DTO
                            StorageBlobDTO blobDto = createBlobDto(blob);
                            // æ ¹æ®type分类
                            switch ((int) blob.getType().longValue()) {
                                case 0:
                                    dto.getBeforeProduction().add(blobDto);
                                    break;
                                case 1:
                                    dto.getAfterProduction().add(blobDto);
                                    break;
                                case 2:
                                    dto.getProductionIssues().add(blobDto);
                                    break;
                                default:
                                    // å¯é€‰ï¼šè®°å½•未分类类型
                                    break;
                            }
                        }
                    });
            return dto;
        }).collect(Collectors.toList());
@@ -222,7 +200,8 @@
    }
    @Override
    public int addOrEditInspectionTask(InspectionTaskDto inspectionTaskDto) {
    @Transactional(rollbackFor = Exception.class)
    public int addOrEditInspectionTask(InspectionTaskDto inspectionTaskDto) throws IOException {
        InspectionTask inspectionTask = new InspectionTask();
        BeanUtils.copyProperties(inspectionTaskDto, inspectionTask);
        inspectionTask.setRegistrantId(SecurityUtils.getLoginUser().getUserId());
@@ -233,30 +212,20 @@
        } else {
            i = inspectionTaskMapper.updateById(inspectionTask);
        }
        if (inspectionTaskDto.getStorageBlobDTO() != null && !inspectionTaskDto.getStorageBlobDTO().isEmpty()) {
            List<StorageAttachment> attachments = new ArrayList<>();
            for (StorageBlobDTO storageBlobDTO : inspectionTaskDto.getStorageBlobDTO()) {
                StorageAttachment storageAttachment = new StorageAttachment(
                        StorageAttachmentFile,
                        (long) InspectionTasks.ordinal(),
                        inspectionTask.getId()
                );
                storageAttachment.setStorageBlobDTO(storageBlobDTO);
                attachments.add(storageAttachment);
            }
            storageAttachmentService.saveStorageAttachment(attachments, inspectionTask.getId(), InspectionTasks, StorageAttachmentFile);
        }
        commonFileService.migrateTempFilesToFormal(inspectionTask.getId(),inspectionTaskDto.getTempFileIds());
        return i;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int delByIds(Long[] ids) {
        // æ£€æŸ¥å‚æ•°
        if (ids == null || ids.length == 0) {
            return 0;
        }
        commonFileService.deleteByBusinessIds(Arrays.asList(ids),FileNameType.INSPECTION.getValue());
        commonFileService.deleteByBusinessIds(Arrays.asList(ids),FileNameType.INSPECTION_PRODUCTION_BEFORE.getValue());
        commonFileService.deleteByBusinessIds(Arrays.asList(ids),FileNameType.INSPECTION_PRODUCTION_AFTER.getValue());
        return inspectionTaskMapper.deleteBatchIds(Arrays.asList(ids));
    }
src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java
@@ -29,19 +29,19 @@
    private final StockInRecordService stockInRecordService;
    // èŽ·å–å•†å“å…¥åº“æ•°é‡,出库数量,剩余库存
    public Map<String, BigDecimal> getStockQuantity(Long productModelId) {
        // å…¥åº“数量
        BigDecimal sumQuantity = procurementRecordMapper.getSumQuantity(productModelId);
        // å‡ºåº“数量
        BigDecimal outQuantity = procurementRecordOutMapper.getSumQuantity(productModelId);
        // å‰©ä½™åº“å­˜
        BigDecimal stockQuantity = outQuantity.compareTo(sumQuantity) > 0 ? BigDecimal.ZERO : sumQuantity.subtract(outQuantity);
        Map<String, BigDecimal> stockMap = new HashMap<>();
        stockMap.put("inboundNum", sumQuantity);
        stockMap.put("outboundNum", outQuantity);
        stockMap.put("stockQuantity", stockQuantity);
        return stockMap;
    }
//    public Map<String, BigDecimal> getStockQuantity(Long productModelId) {
//        // å…¥åº“数量
//        BigDecimal sumQuantity = procurementRecordMapper.getSumQuantity(productModelId);
//        // å‡ºåº“数量
//        BigDecimal outQuantity = procurementRecordOutMapper.getSumQuantity(productModelId);
//        // å‰©ä½™åº“å­˜
//        BigDecimal stockQuantity = outQuantity.compareTo(sumQuantity) > 0 ? BigDecimal.ZERO : sumQuantity.subtract(outQuantity);
//        Map<String, BigDecimal> stockMap = new HashMap<>();
//        stockMap.put("inboundNum", sumQuantity);
//        stockMap.put("outboundNum", outQuantity);
//        stockMap.put("stockQuantity", stockQuantity);
//        return stockMap;
//    }
    /**
     * ä¸åˆæ ¼å…¥åº“
src/main/java/com/ruoyi/production/controller/ProductWorkOrderController.java
@@ -3,10 +3,14 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.dto.ProductWorkOrderDto;
import com.ruoyi.production.pojo.ProductWorkOrder;
import com.ruoyi.production.service.ProductWorkOrderService;
import com.ruoyi.quality.pojo.QualityInspect;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
@RestController
@AllArgsConstructor
@@ -43,4 +47,14 @@
        return R.ok(productWorkOrderservice.getById(id));
    }
    /**
     * å·¥å•流转卡下载
     * @param response
     * @param productWorkOrder
     */
    @PostMapping("/down")
    public void down(HttpServletResponse response, @RequestBody ProductWorkOrder productWorkOrder) {
        productWorkOrderservice.down(response, productWorkOrder);
    }
}
src/main/java/com/ruoyi/production/controller/ProductWorkOrderFileController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,70 @@
package com.ruoyi.production.controller;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.production.pojo.ProductWorkOrderFile;
import com.ruoyi.production.service.ProductWorkOrderFileService;
import com.ruoyi.quality.pojo.QualityInspectFile;
import com.ruoyi.quality.service.IQualityInspectFileService;
import io.swagger.annotations.Api;
import org.checkerframework.checker.units.qual.A;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
 * <p>
 * ç”Ÿäº§å·¥å•附件表 å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-23 03:28:32
 */
@Api(tags = "生产工单附件表")
@RestController
@RequestMapping("/productWorkOrderFile")
public class ProductWorkOrderFileController {
    @Resource
    private ProductWorkOrderFileService productWorkOrderFileService;
    /**
     * æ–°å¢ž
     * @param productWorkOrderFile
     * @return
     */
    @PostMapping("/add")
    public AjaxResult add(@RequestBody ProductWorkOrderFile productWorkOrderFile) {
        return AjaxResult.success(productWorkOrderFileService.save(productWorkOrderFile));
    }
    /**
     * åˆ é™¤
     * @param ids
     * @return
     */
    @DeleteMapping("/del")
    public AjaxResult delQualityUnqualified(@RequestBody List<Integer> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
        }
        //删除检验附件
        return AjaxResult.success(productWorkOrderFileService.removeBatchByIds(ids));
    }
    /**
     *分页查询
     * @param page
     * @param productWorkOrderFile
     * @return
     */
    @GetMapping("/listPage")
    public AjaxResult listPage(Page page, ProductWorkOrderFile productWorkOrderFile) {
        return AjaxResult.success(productWorkOrderFileService.page(page, Wrappers.<ProductWorkOrderFile>lambdaQuery().eq(ProductWorkOrderFile::getWorkOrderId,productWorkOrderFile.getWorkOrderId())));
    }
}
src/main/java/com/ruoyi/production/dto/ProductWorkOrderDto.java
@@ -2,11 +2,13 @@
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import com.ruoyi.production.pojo.ProductWorkOrder;
import com.ruoyi.production.pojo.ProductWorkOrderFile;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data
@@ -35,4 +37,7 @@
    @ApiModelProperty(value = "完成进度")
    private BigDecimal completionStatus;
    @ApiModelProperty(value = "报废数量")
    private BigDecimal scrapQty;
}
src/main/java/com/ruoyi/production/mapper/ProductWorkOrderFileMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.production.mapper;
import com.ruoyi.production.pojo.ProductWorkOrderFile;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
 * <p>
 * ç”Ÿäº§å·¥å•附件表 Mapper æŽ¥å£
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-23 03:28:32
 */
@Mapper
public interface ProductWorkOrderFileMapper extends BaseMapper<ProductWorkOrderFile> {
}
src/main/java/com/ruoyi/production/mapper/ProductWorkOrderMapper.java
@@ -17,4 +17,5 @@
    IPage<ProductWorkOrderDto> pageProductWorkOrder(Page<ProductWorkOrderDto> page, @Param("c") ProductWorkOrderDto productWorkOrder);
    ProductWorkOrderDto getProductWorkOrderFlowCard(@Param("id") Long id);
}
src/main/java/com/ruoyi/production/pojo/ProductProcessRoute.java
@@ -5,8 +5,10 @@
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
src/main/java/com/ruoyi/production/pojo/ProductWorkOrderFile.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,65 @@
package com.ruoyi.production.pojo;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
/**
 * <p>
 * ç”Ÿäº§å·¥å•附件表
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-23 03:28:32
 */
@Getter
@Setter
@TableName("product_work_order_file")
@ApiModel(value = "ProductWorkOrderFile对象", description = "生产工单附件表")
public class ProductWorkOrderFile implements Serializable {
    private static final long serialVersionUID = 1L;
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    @ApiModelProperty("关联工单id")
    private Integer workOrderId;
    @ApiModelProperty("文件名称")
    private String name;
    @ApiModelProperty("文件路径")
    private String url;
    @ApiModelProperty("文件大小")
    private Integer fileSize;
    @ApiModelProperty("创建时间")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @ApiModelProperty("创建用户")
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;
    @ApiModelProperty("修改时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    @ApiModelProperty("修改用户")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;
    @ApiModelProperty("租户ID")
    @TableField(fill = FieldFill.INSERT)
    private Long tenantId;
}
src/main/java/com/ruoyi/production/pojo/ProductionProductOutput.java
@@ -20,7 +20,6 @@
    @ApiModelProperty(value = "产品id")
    private Long productModelId;
    //合格数量=报工数量-报废数量
    @ApiModelProperty(value = "报工数量")
    private BigDecimal quantity;
src/main/java/com/ruoyi/production/service/ProductWorkOrderFileService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package com.ruoyi.production.service;
import com.ruoyi.production.pojo.ProductWorkOrderFile;
import com.baomidou.mybatisplus.extension.service.IService;
/**
 * <p>
 * ç”Ÿäº§å·¥å•附件表 æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-23 03:28:32
 */
public interface ProductWorkOrderFileService extends IService<ProductWorkOrderFile> {
}
src/main/java/com/ruoyi/production/service/ProductWorkOrderService.java
@@ -6,10 +6,13 @@
import com.ruoyi.production.dto.ProductWorkOrderDto;
import com.ruoyi.production.pojo.ProductWorkOrder;
import javax.servlet.http.HttpServletResponse;
public interface ProductWorkOrderService extends IService<ProductWorkOrder>{
    IPage<ProductWorkOrderDto> listPage(Page<ProductWorkOrderDto> page, ProductWorkOrderDto productWorkOrder);
    int updateProductWorkOrder(ProductWorkOrderDto productWorkOrderDto);
    void down(HttpServletResponse response, ProductWorkOrder productWorkOrder);
}
src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java
@@ -91,7 +91,7 @@
                ProductWorkOrder productWorkOrder = new ProductWorkOrder();
                productWorkOrder.setProductProcessRouteItemId(productProcessRouteItem.getId());
                productWorkOrder.setProductOrderId(productOrder.getId());
                ProductOrder order = productOrderMapper.selectById(productOrder);
                ProductOrder order = productOrderMapper.selectById(productOrder.getId());
                productWorkOrder.setPlanQuantity(order.getQuantity());
                productWorkOrder.setWorkOrderNo(workOrderNoStr);
                productWorkOrder.setStatus(1);
src/main/java/com/ruoyi/production/service/impl/ProductWorkOrderFileServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
package com.ruoyi.production.service.impl;
import com.ruoyi.production.pojo.ProductWorkOrderFile;
import com.ruoyi.production.mapper.ProductWorkOrderFileMapper;
import com.ruoyi.production.service.ProductWorkOrderFileService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
 * <p>
 * ç”Ÿäº§å·¥å•附件表 æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-23 03:28:32
 */
@Service
public class ProductWorkOrderFileServiceImpl extends ServiceImpl<ProductWorkOrderFileMapper, ProductWorkOrderFile> implements ProductWorkOrderFileService {
}
src/main/java/com/ruoyi/production/service/impl/ProductWorkOrderServiceImpl.java
@@ -2,22 +2,49 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.data.PictureRenderData;
import com.deepoove.poi.data.Pictures;
import com.ruoyi.common.utils.HackLoopTableRenderPolicy;
import com.ruoyi.common.utils.MatrixToImageWriter;
import com.ruoyi.production.dto.ProductWorkOrderDto;
import com.ruoyi.production.mapper.ProductWorkOrderFileMapper;
import com.ruoyi.production.mapper.ProductWorkOrderMapper;
import com.ruoyi.production.pojo.ProductWorkOrder;
import com.ruoyi.production.pojo.ProductWorkOrderFile;
import com.ruoyi.production.service.ProductWorkOrderService;
import com.ruoyi.quality.pojo.QualityInspectParam;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
@AllArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class ProductWorkOrderServiceImpl extends ServiceImpl<ProductWorkOrderMapper, ProductWorkOrder> implements ProductWorkOrderService {
    @Autowired
    private ProductWorkOrderMapper productWorkOrdermapper;
    @Autowired
    private ProductWorkOrderFileMapper productWorkOrderFileMapper;
    @Value("${file.temp-dir}")
    private String tempDir;
    @Override
    public IPage<ProductWorkOrderDto> listPage(Page<ProductWorkOrderDto> page, ProductWorkOrderDto productWorkOrder) {
@@ -29,4 +56,61 @@
        return productWorkOrdermapper.updateById(productWorkOrderDto);
    }
    @Override
    public void down(HttpServletResponse response, ProductWorkOrder productWorkOrder) {
        ProductWorkOrderDto productWorkOrderDto = productWorkOrdermapper.getProductWorkOrderFlowCard(productWorkOrder.getId());
        String codePath;
        try {
            codePath = new MatrixToImageWriter().code(productWorkOrderDto.getId().toString(), tempDir);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        /*获取附件图片类型*/
        List<Map<String, Object>> images = new ArrayList<>();
        List<ProductWorkOrderFile> productWorkOrderFiles = productWorkOrderFileMapper.selectList(Wrappers.<ProductWorkOrderFile>lambdaQuery().eq(ProductWorkOrderFile::getWorkOrderId, productWorkOrder.getId()));
        if (CollectionUtils.isNotEmpty(productWorkOrderFiles)) {
            productWorkOrderFiles.forEach(productWorkOrderFile -> {
                Map<String, Object> image = new HashMap<>();
                PictureRenderData pictureRenderData = Pictures.ofLocal( productWorkOrderFile.getUrl()).sizeInCm(17, 20).create();
                image.put("url", pictureRenderData);
                images.add(image);
            });
        }
        InputStream inputStream = this.getClass().getResourceAsStream("/static/work-order-template.docx");
        XWPFTemplate template = XWPFTemplate.compile(inputStream).render(
                new HashMap<String, Object>() {{
                    put("process", productWorkOrderDto.getProcessName());
                    put("workOrderNo", productWorkOrderDto.getWorkOrderNo());
                    put("productOrderNpsNo", productWorkOrderDto.getProductOrderNpsNo());
                    put("productName", productWorkOrderDto.getProductName());
                    put("planQuantity", productWorkOrderDto.getPlanQuantity());
                    put("model", productWorkOrderDto.getModel());
                    put("completeQuantity", productWorkOrderDto.getCompleteQuantity());
                    put("scrapQty", productWorkOrderDto.getScrapQty());
                    put("planStartTime", productWorkOrderDto.getPlanStartTime());
                    put("planEndTime", productWorkOrderDto.getPlanEndTime());
                    put("actualStartTime", productWorkOrderDto.getActualStartTime());
                    put("actualEndTime", productWorkOrderDto.getActualEndTime());
                    put("twoCode", Pictures.ofLocal(codePath).create());
                    put("images", images.isEmpty()?null:images);
                }});
        try {
            response.setContentType("application/msword");
            String fileName = URLEncoder.encode(
                    "流转卡", "UTF-8");
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
            response.setHeader("Content-disposition",
                    "attachment;filename=" + fileName + ".docx");
            OutputStream os = response.getOutputStream();
            template.write(os);
            os.flush();
            os.close();
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("导出失败");
        }
    }
}
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -142,15 +142,7 @@
            productStructureDtos.add(productStructureDto);
        }
        for (ProductStructureDto productStructureDto : productStructureDtos) {
            ProductModel productModel1 = productModelMapper.selectById(productStructureDto.getProductModelId());
            Product product = productMapper.selectById(productModel1.getProductId());
            BigDecimal stockQuantity = stockUtils.getStockQuantity(productModel1.getId()).get("stockQuantity");
            if (!(stockQuantity.compareTo(BigDecimal.ZERO) > 0)) {
                throw new RuntimeException(product.getProductName()+"产品的"+productModel1.getModel() + "的规格库存为0");
            }
            if (stockQuantity.compareTo(productStructureDto.getUnitQuantity().multiply(dto.getQuantity())) < 0) {
                throw new RuntimeException(product.getProductName()+"产品的"+productModel1.getModel() + "的规格库存不足");
            }
            ProductionProductInput productionProductInput = new ProductionProductInput();
            productionProductInput.setProductModelId(productStructureDto.getProductModelId());
            productionProductInput.setQuantity(productStructureDto.getUnitQuantity().multiply(dto.getQuantity()));
@@ -187,7 +179,7 @@
            qualityInspect.setModel(productModel.getModel());
            qualityInspect.setUnit(productModel.getUnit());
            qualityInspect.setQuantity(productQty);
            qualityInspect.setProcess(productProcess.getName());
            qualityInspect.setProcess(process);
            qualityInspect.setInspectState(0);
            qualityInspect.setInspectType(inspectType);
            qualityInspect.setProductMainId(productionProductMain.getId());
@@ -209,7 +201,7 @@
            }
            /*更新工单和生产订单*/
            ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(dto.getWorkOrderId());
            productWorkOrder.setCompleteQuantity(productQty.add(dto.getQuantity()));
            productWorkOrder.setCompleteQuantity(productWorkOrder.getCompleteQuantity().add(productQty));
            if (ObjectUtils.isNull(productWorkOrder.getActualStartTime())) {
                productWorkOrder.setActualStartTime(LocalDate.now());//实际开始时间
            }
@@ -291,7 +283,7 @@
        // åˆ é™¤äº§å‡ºè®°å½•
        productionProductOutputMapper.delete(new LambdaQueryWrapper<ProductionProductOutput>()
                .eq(ProductionProductOutput::getProductMainId, productionProductMain.getId()));
        //删除入库
        //删除投入记录
        productionProductInputMapper.delete(new LambdaQueryWrapper<ProductionProductInput>()
                .eq(ProductionProductInput::getProductMainId, productionProductMain.getId()));
        //删除报废的入库记录
src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java
@@ -189,6 +189,14 @@
    }
    /**
     * æŸ¥è¯¢é‡‡è´­å°è´¦å’Œäº§å“çˆ¶å­åˆ—表
     */
    @GetMapping("/getPurchaseByCode")
    public PurchaseLedgerDto getPurchaseByCode(PurchaseLedgerDto purchaseLedgerDto) {
        return purchaseLedgerService.getPurchaseByCode(purchaseLedgerDto);
    }
    /**
     * åˆ é™¤é‡‡è´­å°è´¦
     */
    @Log(title = "采购台账", businessType = BusinessType.DELETE)
src/main/java/com/ruoyi/purchase/pojo/PurchaseLedger.java
@@ -90,7 +90,7 @@
    /**
     * é™„件材料路径或名称
     */
    @Excel(name = "附件材料路径或名称")
//    @Excel(name = "附件材料路径或名称")
    private String attachmentMaterials;
    /**
@@ -151,6 +151,7 @@
    @ApiModelProperty(value = "付款方式")
    private String paymentMethod;
    @ApiModelProperty("审批状态  1-待审核,2-审批中,3-审批通过,4-审批失败,5表示是模板")
    @Excel(name = "审批状态", readConverterExp = "1=待审核,2=审批中,3=审批通过,4=审批失败")
    private Integer approvalStatus;
    @ApiModelProperty(value = "模板名称")
src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java
@@ -43,4 +43,6 @@
    String getPurchaseNo();
    AjaxResult importData(MultipartFile file);
    PurchaseLedgerDto getPurchaseByCode(PurchaseLedgerDto purchaseLedgerDto);
}
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -50,6 +50,7 @@
import com.ruoyi.sales.pojo.InvoiceRegistrationProduct;
import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.service.impl.CommonFileServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
@@ -116,6 +117,7 @@
    private final StringRedisTemplate redisTemplate;
    private final QualityInspectMapper qualityInspectMapper;
    private final CommonFileServiceImpl commonFileService;
    private final QualityTestStandardBindingMapper qualityTestStandardBindingMapper;
    private final QualityTestStandardParamMapper qualityTestStandardParamMapper;
    private final QualityTestStandardMapper qualityTestStandardMapper;
@@ -163,6 +165,7 @@
        purchaseLedger.setRecorderId(purchaseLedgerDto.getRecorderId());
        purchaseLedger.setRecorderName(sysUser.getNickName());
        purchaseLedger.setPhoneNumber(sysUser.getPhonenumber());
        purchaseLedger.setApprovalStatus(1);
        // 3. æ–°å¢žæˆ–更新主表
        if (purchaseLedger.getId() == null) {
            purchaseLedgerMapper.insert(purchaseLedger);
@@ -461,6 +464,8 @@
        }
        //批量删除原材料检验数据
        qualityInspectMapper.delete(materialInspectLambdaQueryWrapper);
        //删除附件
        commonFileService.deleteByBusinessIds(Arrays.asList(ids), 2);
        // æ‰¹é‡åˆ é™¤é‡‡è´­å°è´¦
        return purchaseLedgerMapper.deleteBatchIds(Arrays.asList(ids));
    }
@@ -638,6 +643,12 @@
            List<SysUser> sysUsers = sysUserMapper.selectList(new LambdaQueryWrapper<SysUser>().in(SysUser::getNickName,
                    salesLedgerImportDtoList.stream().map(PurchaseLedgerImportDto::getRecorderName).collect(Collectors.toList())));
            for (PurchaseLedgerImportDto salesLedgerImportDto : salesLedgerImportDtoList) {
                PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne(new LambdaQueryWrapper<PurchaseLedger>()
                        .eq(PurchaseLedger::getPurchaseContractNumber, salesLedgerImportDto.getPurchaseContractNumber())
                        .last("limit 1"));
                if(purchaseLedger != null){
                    continue;
                }
                PurchaseLedger salesLedger = new PurchaseLedger();
                BeanUtils.copyProperties(salesLedgerImportDto, salesLedger);
                // é€šè¿‡ä¾›åº”商名称查询ID
@@ -724,6 +735,32 @@
        return AjaxResult.success("导入失败");
    }
    @Override
    public PurchaseLedgerDto getPurchaseByCode(PurchaseLedgerDto purchaseLedgerDto) {
        // 1. æŸ¥è¯¢ä¸»è¡¨
        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne(new LambdaQueryWrapper<PurchaseLedger>()
                .eq(PurchaseLedger::getPurchaseContractNumber, purchaseLedgerDto.getPurchaseContractNumber())
                .last("LIMIT 1"));
        if (purchaseLedger == null) {
            throw new BaseException("采购台账不存在");
        }
        // 2. æŸ¥è¯¢å­è¡¨
        LambdaQueryWrapper<SalesLedgerProduct> productWrapper = new LambdaQueryWrapper<>();
        productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId())
                .eq(SalesLedgerProduct::getType, 2);
        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(productWrapper);
        // 4. è½¬æ¢ DTO
        PurchaseLedgerDto resultDto = new PurchaseLedgerDto();
        BeanUtils.copyProperties(purchaseLedger, resultDto);
        if (!products.isEmpty()) {
            resultDto.setHasChildren(true);
            resultDto.setProductData(products);
        }
        return resultDto;
    }
    public void addApproveByPurchase(LoginUser loginUser,PurchaseLedger purchaseLedger) throws Exception {
        ApproveProcessVO approveProcessVO = new ApproveProcessVO();
        approveProcessVO.setApproveType(5);
src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java
@@ -163,8 +163,14 @@
    @Log(title = "销售台账", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, SalesLedgerDto salesLedgerDto) {
        List<SalesLedger> list = salesLedgerService.selectSalesLedgerList(salesLedgerDto);
        Page page = new Page(-1,-1);
        IPage<SalesLedger> salesLedgerIPage = listPage(page, salesLedgerDto);
        ExcelUtil<SalesLedger> util = new ExcelUtil<SalesLedger>(SalesLedger.class);
        if(salesLedgerIPage == null){
            util.exportExcel(response, new ArrayList<>(), "销售台账数据");
            return;
        }
        List<SalesLedger> list = salesLedgerIPage.getRecords();
        util.exportExcel(response, list, "销售台账数据");
    }
src/main/java/com/ruoyi/sales/controller/SalesQuotationController.java
@@ -39,7 +39,7 @@
        SalesQuotationDto afterSalesService = new SalesQuotationDto();
        IPage<SalesQuotationDto> listPage = salesQuotationService.listPage(page, afterSalesService);
        ExcelUtil<SalesQuotationDto> util = new ExcelUtil<SalesQuotationDto>(SalesQuotationDto.class);
        util.exportExcel(response, listPage.getRecords() , "反馈登记");
        util.exportExcel(response, listPage.getRecords() , "销售报价");
    }
src/main/java/com/ruoyi/sales/controller/ShipmentApprovalController.java
@@ -4,6 +4,7 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.math.LongMath;
import com.ruoyi.common.enums.StockQualifiedRecordTypeEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.controller.BaseController;
@@ -14,6 +15,7 @@
import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage;
import com.ruoyi.procurementrecord.service.ProcurementRecordOutService;
import com.ruoyi.procurementrecord.service.ProcurementRecordService;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.sales.mapper.ShipmentApprovalMapper;
import com.ruoyi.sales.mapper.ShippingInfoMapper;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
@@ -47,9 +49,7 @@
    @Autowired
    private ISalesLedgerProductService salesLedgerProductService;
    @Autowired
    private ProcurementRecordOutService procurementRecordOutService;
    @Autowired
    private ProcurementRecordService procurementRecordStorageService;
    private StockUtils stockUtils;
    @GetMapping("/listPage")
    @ApiOperation("发货审批列表")
@@ -99,18 +99,9 @@
//                throw new ServiceException("采购记录不存在,审批回滚");
//            }
            //  ç”Ÿæˆå‡ºåº“记录
            ProcurementRecordOutAdd procurementRecordOutAdd = new ProcurementRecordOutAdd();
//            procurementRecordOutAdd.setId(procurementRecordStorage.getId());
            procurementRecordOutAdd.setId(0);
            procurementRecordOutAdd.setProductModelId(salesLedgerProduct.getProductModelId());
            procurementRecordOutAdd.setSalesLedgerProductId((long) Math.toIntExact(salesLedgerProduct.getId()));
            procurementRecordOutAdd.setType(2);
            procurementRecordOutAdd.setUserId(Math.toIntExact(getUserId()));
            procurementRecordOutAdd.setQuantity(salesLedgerProduct.getQuantity().toPlainString());
            procurementRecordOutAdd.setTime(LocalDate.now().toString());
            procurementRecordOutService.stockout(procurementRecordOutAdd);
            //出库
            stockUtils.addStock(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), req.getId());
        }
        return AjaxResult.success();
src/main/java/com/ruoyi/sales/controller/ShippingInfoController.java
@@ -16,6 +16,7 @@
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.other.service.impl.TempFileServiceImpl;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.sales.dto.ShippingInfoDto;
import com.ruoyi.sales.mapper.ShipmentApprovalMapper;
import com.ruoyi.sales.mapper.ShippingInfoMapper;
@@ -50,19 +51,14 @@
    @Autowired
    private ShippingInfoService shippingInfoService;
    @Autowired
    private ShipmentApprovalMapper shipmentApprovalMapper;
    @Autowired
    private ISalesLedgerProductService salesLedgerProductService;
    @Autowired
    private TempFileServiceImpl tempFileService;
    @Autowired
    private CommonFileServiceImpl commonFileService;
    @Autowired
    private ApproveProcessServiceImpl approveProcessService;
    @Autowired
    private StockUtils stockUtils;
    @GetMapping("/listPage")
@@ -100,20 +96,9 @@
    @Transactional(rollbackFor = Exception.class)
    @Log(title = "发货信息管理", businessType = BusinessType.UPDATE)
    public AjaxResult deductStock(@RequestBody ShippingInfoDto req) throws IOException {
        ShippingInfo byId = shippingInfoService.getById(req.getId());
        if (byId == null) {
            return AjaxResult.error("发货信息不存在");
        }
        byId.setExpressNumber(req.getExpressNumber());
        byId.setExpressCompany(req.getExpressCompany());
        byId.setStatus("已发货");
        byId.setShippingCarNumber(req.getShippingCarNumber());
        boolean update = shippingInfoService.updateById(req);
        // è¿ç§»æ–‡ä»¶
        if(CollectionUtils.isNotEmpty(req.getTempFileIds())){
            tempFileService.migrateTempFilesToFormal(req.getId(), req.getTempFileIds(), FileNameType.SHIP.getValue());
        }
        return update ? AjaxResult.success() : AjaxResult.error();
        return shippingInfoService.deductStock( req) ? AjaxResult.success() : AjaxResult.error();
    }
    @PostMapping("/update")
@@ -134,9 +119,8 @@
    @Transactional(rollbackFor = Exception.class)
    @Log(title = "发货信息管理", businessType = BusinessType.DELETE)
    public AjaxResult delete(@RequestBody List<Long> ids) {
        commonFileService.deleteByBusinessIds(ids, FileNameType.SHIP.getValue());
        boolean delete = shippingInfoService.removeBatchByIds(ids);
        return delete ? AjaxResult.success("删除成功") : AjaxResult.error("删除失败");
        return shippingInfoService.delete(ids) ? AjaxResult.success("删除成功") : AjaxResult.error("删除失败");
    }
    @Autowired
src/main/java/com/ruoyi/sales/pojo/SalesLedger.java
@@ -40,20 +40,6 @@
    @Excel(name = "客户合同号")
    private String customerContractNo;
    /**
     * å‘货车牌号
     */
    @Excel(name = "发货车牌号")
    @TableField(exist = false)
    private String shippingCarNumber;
    /**
     * å‘货日期
     */
    @Excel(name = "发货日期", width = 30, dateFormat = "yyyy-MM-dd")
    @TableField(exist = false)
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date shippingDate;
    /**
     * é¡¹ç›®åç§°
src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
@@ -192,6 +192,14 @@
    @TableField(exist = false)
    private String shippingCarNumber;
    @ApiModelProperty("快递公司")
    @TableField(exist = false)
    private String expressCompany;
    @ApiModelProperty("快递单号")
    @TableField(exist = false)
    private String expressNumber;
    /**
     * å‘货日期
     */
@@ -202,7 +210,7 @@
    @TableField(exist = false)
    @ApiModelProperty(value = "发货状态")
    private String shippingStatus;
    private String shippingStatus = "待发货";
    /**
     * äº§å“çŠ¶æ€
     */
src/main/java/com/ruoyi/sales/pojo/ShippingInfo.java
@@ -37,7 +37,7 @@
    @ApiModelProperty(value = "销售报价产品表id")
    private Long salesLedgerProductId;
    @ApiModelProperty(value = "状态 å¾…审核 å®¡æ ¸ä¸­ ï¼Œå®¡æ ¸æ‹’绝 å®¡æ ¸é€šè¿‡")
    @ApiModelProperty(value = "状态 å¾…审核 å®¡æ ¸ä¸­ ï¼Œå®¡æ ¸æ‹’绝 å®¡æ ¸é€šè¿‡ å·²å‘è´§")
    @Excel(name = "状态")
    private String status;
src/main/java/com/ruoyi/sales/service/ShippingInfoService.java
@@ -3,7 +3,11 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.sales.dto.ShippingInfoDto;
import com.ruoyi.sales.pojo.ShippingInfo;
import java.io.IOException;
import java.util.List;
/**
 * @author :yys
@@ -11,4 +15,8 @@
 */
public interface ShippingInfoService extends IService<ShippingInfo>{
    IPage<ShippingInfo> listPage(Page page, ShippingInfo req);
    boolean deductStock(ShippingInfoDto req) throws IOException;
    boolean delete(List<Long> ids);
}
src/main/java/com/ruoyi/sales/service/impl/MetricStatisticsServiceImpl.java
@@ -7,8 +7,10 @@
import com.ruoyi.sales.dto.StatisticsTableDto;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.mapper.ShippingInfoMapper;
import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.pojo.ShippingInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -31,6 +33,9 @@
    @Autowired
    private SalesLedgerProductMapper salesLedgerProductMapper;
    @Autowired
    private ShippingInfoMapper shippingInfoMapper;
    public AjaxResult total() {
        List<SalesLedger> salesLedgers = salesLedgerMapper.selectList(null);
        if(CollectionUtils.isEmpty(salesLedgers)) return AjaxResult.success(salesLedgers);
@@ -45,9 +50,9 @@
        map.put("shipRate", "0%");
        if(CollectionUtils.isEmpty(salesLedgerProducts)) return AjaxResult.success(map);
        // å‘货数量
        long count = salesLedgerProducts.stream()
                .filter(salesLedgerProduct -> salesLedgerProduct.getApproveStatus().equals(2))
                .count();
        long count = shippingInfoMapper.selectCount(new LambdaQueryWrapper<ShippingInfo>()
                .in(ShippingInfo::getSalesLedgerProductId, salesLedgerProducts.stream().map(SalesLedgerProduct::getId).collect(Collectors.toList()))
                .eq(ShippingInfo::getStatus,"已发货"));
        map.put("shipRate", String.format("%.2f", count * 100.0 / salesLedgerProducts.size()) + "%");
        return AjaxResult.success(map);
    }
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -22,10 +22,14 @@
import com.ruoyi.sales.mapper.InvoiceRegistrationProductMapper;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.mapper.ShippingInfoMapper;
import com.ruoyi.sales.pojo.InvoiceRegistrationProduct;
import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.pojo.ShippingInfo;
import com.ruoyi.sales.service.ISalesLedgerProductService;
import com.ruoyi.stock.mapper.StockInventoryMapper;
import com.ruoyi.stock.pojo.StockInventory;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -74,6 +78,8 @@
    private ProductionProductOutputMapper productionProductOutputMapper;
    private ProductionProductInputMapper productionProductInputMapper;
    private QualityInspectMapper qualityInspectMapper;
    private ShippingInfoMapper shippingInfoMapper;
    private ShippingInfoServiceImpl shippingInfoService;
    private StockUtils stockUtils;
@@ -81,6 +87,8 @@
    @Autowired
    private ProductStructureMapper productStructureMapper;
    @Autowired
    private StockInventoryMapper stockInventoryMapper;
    @Override
    public SalesLedgerProduct selectSalesLedgerProductById(Long id) {
@@ -94,6 +102,20 @@
//                .eq(SalesLedgerProduct::getType, salesLedgerProduct.getType());
        List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectSalesLedgerProductList(salesLedgerProduct);
        if(!CollectionUtils.isEmpty(salesLedgerProducts)){
            salesLedgerProducts.forEach(item -> {
                // å‘货信息
                ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>()
                        .eq(ShippingInfo::getSalesLedgerProductId, item.getId())
                        .orderByDesc(ShippingInfo::getCreateTime)
                        .last("limit 1"));
                if(shippingInfo != null){
                    item.setShippingDate(shippingInfo.getShippingDate());
                    item.setShippingCarNumber(shippingInfo.getShippingCarNumber());
                    item.setShippingStatus(shippingInfo.getStatus());
                    item.setExpressCompany(shippingInfo.getExpressCompany());
                    item.setExpressNumber(shippingInfo.getExpressNumber());
                }
            });
            // å¼€ç¥¨
            InvoiceRegistrationProductDto invoiceRegistrationProductDto = new InvoiceRegistrationProductDto();
            invoiceRegistrationProductDto.setSalesLedgerId(salesLedgerProduct.getSalesLedgerId().intValue());
@@ -117,6 +139,8 @@
                    ledgerProduct.setInvoiceAmount(invoiceAmount);
                    ledgerProduct.setNoInvoiceNum(noInvoiceNum);
                    ledgerProduct.setNoInvoiceAmount(noInvoiceAmount);
                }
            }
@@ -135,6 +159,12 @@
        List<SalesLedgerProduct> deletedProducts = salesLedgerProductMapper.selectBatchIds(Arrays.asList(ids));
        if (deletedProducts.isEmpty()) {
            return 0; // æ²¡æœ‰å¯åˆ é™¤çš„æ•°æ®
        }
        //删除发货信息
        List<ShippingInfo> shippingInfos = shippingInfoMapper.selectList(new LambdaQueryWrapper<ShippingInfo>()
                .in(ShippingInfo::getSalesLedgerProductId, Arrays.asList(ids)));
        if(!CollectionUtils.isEmpty(shippingInfos)){
            shippingInfoService.delete(shippingInfos.stream().map(ShippingInfo::getId).collect(Collectors.toList()));
        }
        // å¯èƒ½å±žäºŽå¤šä¸ªä¸»è¡¨
@@ -465,10 +495,11 @@
        int count = 0;
        StringBuilder stringBuffer = new StringBuilder();
        for (ProductStructureDto productStructureDto : productStructureDtos) {
            BigDecimal stockQuantity = stockUtils.getStockQuantity(productStructureDto.getProductModelId()).get("stockQuantity");
            StockInventory stockInventory = stockInventoryMapper.selectOne(new QueryWrapper<StockInventory>().lambda().eq(StockInventory::getProductModelId, productStructureDto.getProductModelId()));
            //所需数量
            BigDecimal multiply = salesLedgerProduct.getQuantity().multiply(productStructureDto.getUnitQuantity());
            BigDecimal subtract =stockQuantity.subtract(multiply).divide(BigDecimal.ONE, 2, RoundingMode.CEILING);
            BigDecimal subtract =stockInventory.getQualitity().subtract(stockInventory.getLockedQuantity()).subtract(multiply).divide(BigDecimal.ONE, 2, RoundingMode.CEILING);
            if (subtract.compareTo(BigDecimal.ZERO) <= 0) {
                count++;
                stringBuffer.append(productStructureDto.getProductName())
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -96,6 +96,12 @@
    private final ReceiptPaymentMapper receiptPaymentMapper;
    private final ShippingInfoServiceImpl shippingInfoServiceImpl;
    private final CommonFileServiceImpl commonFileService;
    private final ShippingInfoMapper shippingInfoMapper;
    private final InvoiceLedgerMapper invoiceLedgerMapper;
    private final SalesLedgerSchedulingMapper salesLedgerSchedulingMapper;
@@ -369,6 +375,12 @@
            List<SysUser> sysUsers = sysUserMapper.selectList(new LambdaQueryWrapper<SysUser>().in(SysUser::getNickName,
                    salesLedgerImportDtoList.stream().map(SalesLedgerImportDto::getEntryPerson).collect(Collectors.toList())));
            for (SalesLedgerImportDto salesLedgerImportDto : salesLedgerImportDtoList) {
                SalesLedger salesLedger1 = salesLedgerMapper.selectOne(new LambdaQueryWrapper<SalesLedger>()
                        .eq(SalesLedger::getSalesContractNo, salesLedgerImportDto.getSalesContractNo())
                        .last("LIMIT 1"));
                if(salesLedger1 != null){
                    continue;
                }
                SalesLedger salesLedger = new SalesLedger();
                BeanUtils.copyProperties(salesLedgerImportDto, salesLedger);
                salesLedger.setExecutionDate(DateUtils.toLocalDate(salesLedgerImportDto.getExecutionDate()));
@@ -556,6 +568,14 @@
            wrapperTree.in(ReceiptPayment::getInvoiceLedgerId, invoiceLedgerIds);
            receiptPaymentMapper.delete(wrapperTree);
        }
        // åˆ é™¤å‘货台账记录
        List<ShippingInfo> shippingInfos = shippingInfoMapper.selectList(new LambdaQueryWrapper<ShippingInfo>()
                .eq(ShippingInfo::getSalesLedgerId, idList));
        if(CollectionUtils.isNotEmpty(shippingInfos)){
            shippingInfoServiceImpl.delete(shippingInfos.stream().map(ShippingInfo::getId).collect(Collectors.toList()));
        }
        // åˆ é™¤é™„件表
        commonFileService.deleteByBusinessIds(idList, FileNameType.SALE.getValue());
        // åˆ é™¤ç”Ÿäº§ç®¡æŽ§æ•°æ®
        // åˆ é™¤ç”Ÿäº§è®¢å•数据
src/main/java/com/ruoyi/sales/service/impl/SalesQuotationServiceImpl.java
@@ -29,6 +29,7 @@
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@@ -126,8 +127,17 @@
    }
    @Override
    public boolean delete(Long id) {
        SalesQuotation salesQuotation = salesQuotationMapper.selectById(id);
        if(salesQuotation==null) return false;
        salesQuotationMapper.deleteById(id);
        salesQuotationProductMapper.delete(new LambdaQueryWrapper<SalesQuotationProduct>().eq(SalesQuotationProduct::getSalesQuotationId, id));
        // åˆ é™¤æŠ¥ä»·å®¡æ‰¹
        ApproveProcess one = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>()
                .eq(ApproveProcess::getApproveType, 6)
                .eq(ApproveProcess::getApproveReason, salesQuotation.getQuotationNo()));
        if(one != null){
            approveProcessService.delByIds(Collections.singletonList(one.getId()));
        }
        return true;
    }
src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java
@@ -1,14 +1,31 @@
package com.ruoyi.sales.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.approve.pojo.ApproveProcess;
import com.ruoyi.approve.service.impl.ApproveProcessServiceImpl;
import com.ruoyi.common.enums.FileNameType;
import com.ruoyi.common.enums.StockQualifiedRecordTypeEnum;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.other.service.impl.TempFileServiceImpl;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.sales.dto.ShippingInfoDto;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.mapper.ShippingInfoMapper;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.pojo.ShippingInfo;
import com.ruoyi.sales.service.ICommonFileService;
import com.ruoyi.sales.service.ShippingInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
/**
 * @author :yys
@@ -21,10 +38,70 @@
    @Autowired
    private ShippingInfoMapper shippingInfoMapper;
    @Autowired
    private TempFileServiceImpl tempFileService;
    @Autowired
    private SalesLedgerProductMapper salesLedgerProductMapper;
    @Autowired
    private StockUtils stockUtils;
    @Autowired
    private CommonFileServiceImpl commonFileService;
    @Autowired
    private ApproveProcessServiceImpl approveProcessService;
    @Override
    public IPage<ShippingInfo> listPage(Page page, ShippingInfo req) {
        IPage<ShippingInfo> listPage = shippingInfoMapper.listPage(page, req);
        return listPage;
    }
    @Override
    public boolean deductStock(ShippingInfoDto req) throws IOException {
        ShippingInfo byId = this.getById(req.getId());
        if (byId == null) {
            throw new RuntimeException("发货信息不存在");
        }
        byId.setExpressNumber(req.getExpressNumber());
        byId.setExpressCompany(req.getExpressCompany());
        byId.setStatus("已发货");
        byId.setShippingCarNumber(req.getShippingCarNumber());
        boolean update = this.updateById(req);
        //扣减库存
        SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(req.getSalesLedgerProductId());
        stockUtils.substractStock(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), req.getId());
        // è¿ç§»æ–‡ä»¶
        if(CollectionUtils.isNotEmpty(req.getTempFileIds())){
            tempFileService.migrateTempFilesToFormal(req.getId(), req.getTempFileIds(), FileNameType.SHIP.getValue());
        }
        return update ;
    }
    @Override
    public boolean delete(List<Long> ids) {
        List<ShippingInfo> shippingInfos = shippingInfoMapper.selectList(new LambdaQueryWrapper<ShippingInfo>()
                .in(ShippingInfo::getId, ids));
        if(CollectionUtils.isEmpty(shippingInfos)) return false;
        // åˆ é™¤é™„ä»¶
        commonFileService.deleteByBusinessIds(ids, FileNameType.SHIP.getValue());
        // æ‰£å·²å‘货库存
        for (ShippingInfo shippingInfo : shippingInfos) {
            if("已发货".equals(shippingInfo.getStatus())) {
                stockUtils.deleteStockRecord(shippingInfo.getId(), StockQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode());
            }
        }
        // åˆ é™¤å‘货审批
        if(CollectionUtils.isNotEmpty(shippingInfos)){
            for (ShippingInfo shippingInfo : shippingInfos){
                ApproveProcess one = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>()
                        .like(ApproveProcess::getApproveReason, shippingInfo.getShippingNo()));
                if(one != null){
                    approveProcessService.delByIds(Collections.singletonList(one.getId()));
                }
            }
        }
        return this.removeBatchByIds(ids);
    }
}
src/main/java/com/ruoyi/stock/controller/StockInRecordController.java
@@ -6,7 +6,6 @@
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.stock.dto.StockInRecordDto;
import com.ruoyi.stock.dto.StockInventoryDto;
import com.ruoyi.stock.service.StockInRecordService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
src/main/java/com/ruoyi/stock/controller/StockInventoryController.java
@@ -4,7 +4,6 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.enums.StockQualifiedRecordTypeEnum;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.compensationperformance.pojo.CompensationPerformance;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.R;
@@ -62,9 +61,9 @@
    }
    @GetMapping("importStockInventory")
    @PostMapping("importStockInventory")
    @ApiOperation("导入库存")
    public R importStockInventory(MultipartFile  file) {
    public R importStockInventory(MultipartFile file) {
        return stockInventoryService.importStockInventory(file);
    }
@@ -78,7 +77,31 @@
    @PostMapping("/exportStockInventory")
    @ApiOperation("导出库存")
    public void exportStockInventory(HttpServletResponse response,StockInventoryDto stockInventoryDto) {
         stockInventoryService.exportStockInventory(response,stockInventoryDto);
    public void exportStockInventory(HttpServletResponse response, StockInventoryDto stockInventoryDto) {
        stockInventoryService.exportStockInventory(response, stockInventoryDto);
    }
    @GetMapping("stockInventoryPage")
    @ApiOperation("库存报表查询")
    public R stockInventoryPage(Page page, StockInventoryDto stockInventoryDto) {
        return R.ok(stockInventoryService.stockInventoryPage(stockInventoryDto,page));
    }
    @GetMapping("stockInAndOutRecord")
    @ApiOperation("统计各个产品的入库和出库记录")
    public R stockInAndOutRecord(StockInventoryDto stockInventoryDto,Page page) {
        return R.ok(stockInventoryService.stockInAndOutRecord(stockInventoryDto,page));
    }
    @PostMapping("/frozenStock")
    @ApiOperation("冻结库存")
    public R frozenStock(@RequestBody StockInventoryDto stockInventoryDto) {
        return R.ok(stockInventoryService.frozenStock(stockInventoryDto));
    }
    @PostMapping("/thawStock")
    @ApiOperation("解冻库存")
    public R thawStock(@RequestBody StockInventoryDto stockInventoryDto) {
        return R.ok(stockInventoryService.thawStock(stockInventoryDto));
    }
}
src/main/java/com/ruoyi/stock/controller/StockOutRecordController.java
@@ -5,9 +5,7 @@
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.stock.dto.StockInRecordDto;
import com.ruoyi.stock.dto.StockOutRecordDto;
import com.ruoyi.stock.pojo.StockOutRecord;
import com.ruoyi.stock.service.StockOutRecordService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
src/main/java/com/ruoyi/stock/controller/StockUninventoryController.java
@@ -2,9 +2,9 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.enums.StockQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockUnQualifiedRecordTypeEnum;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.stock.dto.StockInventoryDto;
import com.ruoyi.stock.dto.StockUninventoryDto;
import com.ruoyi.stock.service.StockUninventoryService;
import io.swagger.annotations.ApiOperation;
@@ -57,4 +57,17 @@
        stockUninventoryService.exportStockUninventory(response,stockUninventoryDto);
    }
    @PostMapping("/frozenStock")
    @ApiOperation("冻结库存")
    public R frozenStock(@RequestBody StockInventoryDto stockInventoryDto) {
        return R.ok(stockUninventoryService.frozenStock(stockInventoryDto));
    }
    @PostMapping("/thawStock")
    @ApiOperation("解冻库存")
    public R thawStock(@RequestBody StockInventoryDto stockInventoryDto) {
        return R.ok(stockUninventoryService.thawStock(stockInventoryDto));
    }
}
src/main/java/com/ruoyi/stock/dto/StockInRecordDto.java
@@ -1,6 +1,5 @@
package com.ruoyi.stock.dto;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import com.ruoyi.stock.pojo.StockInRecord;
import lombok.Data;
@@ -23,4 +22,7 @@
    private String timeStr;
    private String createBy;
    //现存量
    private String currentStock;
}
src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java
@@ -1,7 +1,12 @@
package com.ruoyi.stock.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.stock.pojo.StockInventory;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.time.LocalDate;
@Data
public class StockInventoryDto extends StockInventory {
@@ -16,4 +21,22 @@
    //入库类型对应的id
    private Long recordId;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private LocalDate reportDate;
    //库存月报查询字段
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private LocalDate startMonth;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private LocalDate endMonth;
    private BigDecimal totalStockIn;
    private BigDecimal totalStockOut;
    private BigDecimal currentStock;
    private BigDecimal  unLockedQuantity;
}
src/main/java/com/ruoyi/stock/dto/StockUninventoryDto.java
@@ -3,6 +3,8 @@
import com.ruoyi.stock.pojo.StockUninventory;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class StockUninventoryDto  extends StockUninventory {
    private String productName;
@@ -15,4 +17,6 @@
    //入库类型对应的id
    private Long recordId;
    private BigDecimal unLockedQuantity;
}
src/main/java/com/ruoyi/stock/execl/StockInventoryExportData.java
@@ -1,14 +1,9 @@
package com.ruoyi.stock.execl;
import com.alibaba.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
public class StockInventoryExportData {
@@ -27,12 +22,18 @@
    @Excel(name = "库存数量")
    private BigDecimal qualitity;
    @Excel(name = "预警数量")
    private BigDecimal warnNum;
    @Excel(name = "冻结数量")
    private BigDecimal lockedQuantity;
    @Excel(name = "备注")
    private String remark;
    @Excel(name = "最新更新时间")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;
//
//    @Excel(name = "最新更新时间")
//    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
//    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
//    private LocalDateTime updateTime;
}
src/main/java/com/ruoyi/stock/execl/StockUnInventoryExportData.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,36 @@
package com.ruoyi.stock.execl;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class StockUnInventoryExportData {
    @Excel(name = "产品名称")
    private String productName;
    @Excel(name = "规格")
    private String model;
    @Excel(name = "单位")
    private String unit;
    @Excel(name = "库存数量")
    private BigDecimal qualitity;
    @Excel(name = "冻结数量")
    private BigDecimal lockedQuantity;
    @Excel(name = "备注")
    private String remark;
//
//    @Excel(name = "最新更新时间")
//    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
//    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
//    private LocalDateTime updateTime;
}
src/main/java/com/ruoyi/stock/mapper/StockInventoryMapper.java
@@ -1,14 +1,16 @@
package com.ruoyi.stock.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.stock.dto.StockInRecordDto;
import com.ruoyi.stock.dto.StockInventoryDto;
import com.ruoyi.stock.execl.StockInventoryExportData;
import com.ruoyi.stock.pojo.StockInventory;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal;
import java.util.List;
/**
@@ -31,4 +33,10 @@
    List<StockInventoryExportData> listStockInventoryExportData(@Param("ew") StockInventoryDto stockInventoryDto);
    IPage<StockInRecordDto> stockInventoryPage(@Param("ew") StockInventoryDto stockInventoryDto, Page page);
    IPage<StockInventoryDto> stockInAndOutRecord(@Param("ew") StockInventoryDto stockInventoryDto, Page page);
    BigDecimal selectTotal();
}
src/main/java/com/ruoyi/stock/mapper/StockUninventoryMapper.java
@@ -1,11 +1,11 @@
package com.ruoyi.stock.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.stock.dto.StockUninventoryDto;
import com.ruoyi.stock.execl.StockInventoryExportData;
import com.ruoyi.stock.execl.StockUnInventoryExportData;
import com.ruoyi.stock.pojo.StockUninventory;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@@ -24,9 +24,9 @@
    IPage<StockUninventoryDto> pageStockUninventory(Page page, @Param("ew") StockUninventoryDto stockUninventoryDto);
    int updateSubtractStockUnInventory(StockUninventoryDto stockUninventoryDto);
    int updateSubtractStockUnInventory(@Param("ew") StockUninventoryDto stockUninventoryDto);
    int updateAddStockUnInventory(StockUninventoryDto stockUninventoryDto);
    int updateAddStockUnInventory(@Param("ew") StockUninventoryDto stockUninventoryDto);
    List<StockInventoryExportData> listStockInventoryExportData(@Param("ew") StockUninventoryDto stockUninventoryDto);
    List<StockUnInventoryExportData> listStockInventoryExportData(@Param("ew") StockUninventoryDto stockUninventoryDto);
}
src/main/java/com/ruoyi/stock/pojo/StockInventory.java
@@ -3,19 +3,17 @@
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.lang.Nullable;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
 * <p>
@@ -61,7 +59,7 @@
    private BigDecimal lockedQuantity;
    @ApiModelProperty("预警数量")
    private Integer warnNum;
    private BigDecimal warnNum;
    @ApiModelProperty("备注")
    private String remark;
src/main/java/com/ruoyi/stock/pojo/StockUninventory.java
@@ -3,13 +3,16 @@
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
 * <p>
@@ -37,11 +40,15 @@
    private BigDecimal qualitity;
    @TableField(fill = FieldFill.INSERT)
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime createTime;
    @ApiModelProperty("更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Integer updateTime;
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime updateTime;
    @ApiModelProperty("版本号")
    private Integer version;
@@ -49,4 +56,7 @@
    @ApiModelProperty("备注")
    private String remark;
    @ApiModelProperty("被订单锁定数量")
    private BigDecimal lockedQuantity;
}
src/main/java/com/ruoyi/stock/service/StockInventoryService.java
@@ -2,10 +2,11 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.stock.dto.StockInRecordDto;
import com.ruoyi.stock.dto.StockInventoryDto;
import com.ruoyi.stock.pojo.StockInventory;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
@@ -29,4 +30,12 @@
    R importStockInventory(MultipartFile file);
    void exportStockInventory(HttpServletResponse response, StockInventoryDto stockInventoryDto);
    IPage<StockInRecordDto> stockInventoryPage(StockInventoryDto stockInventoryDto,Page page);
    IPage<StockInventoryDto> stockInAndOutRecord(StockInventoryDto stockInventoryDto,Page page);
    Boolean frozenStock(StockInventoryDto stockInventoryDto);
    Boolean thawStock(StockInventoryDto stockInventoryDto);
}
src/main/java/com/ruoyi/stock/service/StockUninventoryService.java
@@ -2,9 +2,10 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.stock.dto.StockInventoryDto;
import com.ruoyi.stock.dto.StockUninventoryDto;
import com.ruoyi.stock.pojo.StockUninventory;
import com.baomidou.mybatisplus.extension.service.IService;
import javax.servlet.http.HttpServletResponse;
@@ -25,4 +26,8 @@
    Integer subtractStockUninventory(StockUninventoryDto stockUninventoryDto);
    void exportStockUninventory(HttpServletResponse response, StockUninventoryDto stockUninventoryDto);
    Boolean frozenStock(StockInventoryDto stockInventoryDto);
    Boolean thawStock(StockInventoryDto stockInventoryDto);
}
src/main/java/com/ruoyi/stock/service/impl/StockInRecordServiceImpl.java
@@ -11,12 +11,10 @@
import com.ruoyi.common.utils.OrderUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.staff.pojo.StaffOnJob;
import com.ruoyi.stock.dto.StockInRecordDto;
import com.ruoyi.stock.dto.StockInventoryDto;
import com.ruoyi.stock.dto.StockUninventoryDto;
import com.ruoyi.stock.execl.StockInRecordExportData;
import com.ruoyi.stock.execl.StockInventoryExportData;
import com.ruoyi.stock.mapper.StockInRecordMapper;
import com.ruoyi.stock.mapper.StockInventoryMapper;
import com.ruoyi.stock.mapper.StockUninventoryMapper;
@@ -25,7 +23,6 @@
import com.ruoyi.stock.pojo.StockUninventory;
import com.ruoyi.stock.service.StockInRecordService;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java
@@ -4,7 +4,7 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.account.pojo.BorrowInfo;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.enums.StockQualifiedRecordTypeEnum;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.domain.R;
@@ -14,11 +14,10 @@
import com.ruoyi.stock.dto.StockInventoryDto;
import com.ruoyi.stock.dto.StockOutRecordDto;
import com.ruoyi.stock.execl.StockInventoryExportData;
import com.ruoyi.stock.pojo.StockInventory;
import com.ruoyi.stock.mapper.StockInventoryMapper;
import com.ruoyi.stock.pojo.StockInventory;
import com.ruoyi.stock.service.StockInRecordService;
import com.ruoyi.stock.service.StockInventoryService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.stock.service.StockOutRecordService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
@@ -26,6 +25,7 @@
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
/**
@@ -70,6 +70,8 @@
            newStockInventory.setQualitity(stockInventoryDto.getQualitity());
            newStockInventory.setVersion(1);
            newStockInventory.setRemark(stockInventoryDto.getRemark());
            newStockInventory.setLockedQuantity(stockInventoryDto.getLockedQuantity());
            newStockInventory.setWarnNum(stockInventoryDto.getWarnNum());
            stockInventoryMapper.insert(newStockInventory);
        }else {
             stockInventoryMapper.updateAddStockInventory(stockInventoryDto);
@@ -90,6 +92,9 @@
        stockOutRecordDto.setType("0");
        stockOutRecordService.add(stockOutRecordDto);
        StockInventory oldStockInventory = stockInventoryMapper.selectOne(new QueryWrapper<StockInventory>().lambda().eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId()));
        if (stockInventoryDto.getQualitity().compareTo( oldStockInventory.getQualitity().subtract(oldStockInventory.getLockedQuantity()))>0) {
            throw new RuntimeException("库存不足无法出库");
        }
        if (ObjectUtils.isEmpty(oldStockInventory)) {
            throw new RuntimeException("产品库存不存在");
        }else {
@@ -101,32 +106,59 @@
    @Override
    public R importStockInventory(MultipartFile file) {
        try {
            final StringBuffer[] errorMsg = {new StringBuffer()};
            //查询所有的产品
            List<SalesLedgerProduct> salesLedgerProducts =salesLedgerProductMapper.selectProduct();
            // æŸ¥è¯¢æ‰€æœ‰çš„产品
            List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectProduct();
            ExcelUtil<StockInventoryExportData> util = new ExcelUtil<StockInventoryExportData>(StockInventoryExportData.class);
            List<StockInventoryExportData> list = util.importExcel(file.getInputStream());
            list.stream().forEach(dto -> {
                salesLedgerProducts.stream().forEach(item->{
                    if (item.getProductCategory().equals(dto.getProductName())&&item.getSpecificationModel().equals(dto.getModel())) {
                            //更新库存
            // è®°å½•未找到匹配项的数据
            List<String> unmatchedRecords = new ArrayList<>();
            list.forEach(dto -> {
                boolean matched = false;
                for (SalesLedgerProduct item : salesLedgerProducts) {
                    if (item.getProductCategory().equals(dto.getProductName()) &&
                            item.getSpecificationModel().equals(dto.getModel())) {
                        StockInventoryDto stockInventoryDto = new StockInventoryDto();
                        stockInventoryDto.setRecordId(0L);
                        stockInventoryDto.setRecordType(StockQualifiedRecordTypeEnum.CUSTOMIZATION_STOCK_IN.getCode());
                        stockInventoryDto.setQualitity(dto.getQualitity());
                        stockInventoryDto.setRemark(dto.getRemark());
                        stockInventoryDto.setWarnNum(dto.getWarnNum());
                        if (ObjectUtils.isNotEmpty(dto.getLockedQuantity())&&dto.getLockedQuantity().compareTo(dto.getQualitity())>0) {
                            throw new RuntimeException("冻结数量不能超过本次导入的库存数量");
                        }
                        stockInventoryDto.setLockedQuantity(dto.getLockedQuantity());
                        stockInventoryDto.setProductModelId(item.getProductModelId());
                        this.addstockInventory(stockInventoryDto);                    }else {
                        errorMsg[0] = errorMsg[0].append("产品名称:"+dto.getProductName()+"规格:"+dto.getModel()+"不存在").append("\n");
                        this.addstockInventory(stockInventoryDto);
                        matched = true;
                        break; // æ‰¾åˆ°åŒ¹é…é¡¹åŽè·³å‡ºå¾ªçޝ
                    }
                });
                }
                if (!matched) {
                    // è®°å½•未匹配的数据
                    String unmatchedInfo = String.format("产品名称:%s,规格型号:%s",
                            dto.getProductName(), dto.getModel());
                    unmatchedRecords.add(unmatchedInfo);
                }
            });
            return R.ok(errorMsg[0]);
        }catch (Exception e){
            // æž„建返回信息
            StringBuilder message = new StringBuilder();
            if (!unmatchedRecords.isEmpty()) {
                message.append("以下产品未找到匹配项:\n");
                for (String record : unmatchedRecords) {
                    message.append(record).append("\n");
                }
                throw new RuntimeException(message.toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return R.fail("导入失败:" + e.getMessage());
        }
        return R.fail();
        return R.ok("导入成功");
    }
    @Override
    public void exportStockInventory(HttpServletResponse response, StockInventoryDto stockInventoryDto) {
@@ -135,4 +167,38 @@
        ExcelUtil<StockInventoryExportData> util = new ExcelUtil<>(StockInventoryExportData.class);
        util.exportExcel(response,list, "库存信息");
    }
    @Override
    public IPage<StockInRecordDto> stockInventoryPage(StockInventoryDto stockInventoryDto, Page page) {
        return stockInventoryMapper.stockInventoryPage(stockInventoryDto,page);
    }
    @Override
    public IPage<StockInventoryDto> stockInAndOutRecord(StockInventoryDto stockInventoryDto, Page page) {
        return stockInventoryMapper.stockInAndOutRecord(stockInventoryDto,page);
    }
    @Override
    public Boolean frozenStock(StockInventoryDto stockInventoryDto) {
        StockInventory stockInventory = stockInventoryMapper.selectById(stockInventoryDto.getId());
        if (stockInventory.getQualitity().compareTo(stockInventoryDto.getLockedQuantity())<0) {
            throw new RuntimeException("冻结数量不能超过库存数量");
        }
        if (ObjectUtils.isEmpty(stockInventory.getLockedQuantity())) {
            stockInventory.setLockedQuantity(stockInventoryDto.getLockedQuantity());
        }else {
            stockInventory.setLockedQuantity(stockInventory.getLockedQuantity().add(stockInventoryDto.getLockedQuantity()));
        }
        return this.updateById(stockInventory);
    }
    @Override
    public Boolean thawStock(StockInventoryDto stockInventoryDto) {
        StockInventory stockInventory = stockInventoryMapper.selectById(stockInventoryDto.getId());
        if (stockInventory.getLockedQuantity().compareTo(stockInventoryDto.getLockedQuantity())<0) {
            throw new RuntimeException("解冻数量不能超过冻结数量");
        }
        stockInventory.setLockedQuantity(stockInventory.getLockedQuantity().subtract(stockInventoryDto.getLockedQuantity()));
        return this.updateById(stockInventory);
    }
}
src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java
@@ -14,7 +14,6 @@
import com.ruoyi.stock.dto.StockInventoryDto;
import com.ruoyi.stock.dto.StockOutRecordDto;
import com.ruoyi.stock.dto.StockUninventoryDto;
import com.ruoyi.stock.execl.StockInRecordExportData;
import com.ruoyi.stock.execl.StockOutRecordExportData;
import com.ruoyi.stock.mapper.StockInventoryMapper;
import com.ruoyi.stock.mapper.StockOutRecordMapper;
@@ -25,7 +24,6 @@
import com.ruoyi.stock.pojo.StockUninventory;
import com.ruoyi.stock.service.StockOutRecordService;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
src/main/java/com/ruoyi/stock/service/impl/StockUninventoryServiceImpl.java
@@ -4,18 +4,18 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.stock.dto.StockInRecordDto;
import com.ruoyi.stock.dto.StockInventoryDto;
import com.ruoyi.stock.dto.StockOutRecordDto;
import com.ruoyi.stock.dto.StockUninventoryDto;
import com.ruoyi.stock.execl.StockInventoryExportData;
import com.ruoyi.stock.pojo.StockInventory;
import com.ruoyi.stock.pojo.StockUninventory;
import com.ruoyi.stock.execl.StockUnInventoryExportData;
import com.ruoyi.stock.mapper.StockUninventoryMapper;
import com.ruoyi.stock.pojo.StockUninventory;
import com.ruoyi.stock.service.StockInRecordService;
import com.ruoyi.stock.service.StockOutRecordService;
import com.ruoyi.stock.service.StockUninventoryService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -94,8 +94,32 @@
    @Override
    public void exportStockUninventory(HttpServletResponse response, StockUninventoryDto stockUninventoryDto) {
        List<StockInventoryExportData> list = stockUninventoryMapper.listStockInventoryExportData(stockUninventoryDto);
        ExcelUtil<StockInventoryExportData> util = new ExcelUtil<>(StockInventoryExportData.class);
        List<StockUnInventoryExportData> list = stockUninventoryMapper.listStockInventoryExportData(stockUninventoryDto);
        ExcelUtil<StockUnInventoryExportData> util = new ExcelUtil<>(StockUnInventoryExportData.class);
        util.exportExcel(response,list, "不合格库存信息");
    }
    @Override
    public Boolean frozenStock(StockInventoryDto stockInventoryDto) {
        StockUninventory stockUninventory = stockUninventoryMapper.selectById(stockInventoryDto.getId());
        if (stockUninventory.getQualitity().compareTo(stockInventoryDto.getLockedQuantity())<0) {
            throw new RuntimeException("冻结数量不能超过库存数量");
        }
        if (ObjectUtils.isEmpty(stockUninventory.getLockedQuantity())) {
            stockUninventory.setLockedQuantity(stockInventoryDto.getLockedQuantity());
        }else {
            stockUninventory.setLockedQuantity(stockUninventory.getLockedQuantity().add(stockInventoryDto.getLockedQuantity()));
        }
        return this.updateById(stockUninventory);
    }
    @Override
    public Boolean thawStock(StockInventoryDto stockInventoryDto) {
        StockUninventory stockUninventory = stockUninventoryMapper.selectById(stockInventoryDto.getId());
        if (stockUninventory.getLockedQuantity().compareTo(stockInventoryDto.getLockedQuantity())<0) {
            throw new RuntimeException("解冻数量不能超过冻结数量");
        }
        stockUninventory.setLockedQuantity(stockUninventory.getLockedQuantity().subtract(stockInventoryDto.getLockedQuantity()));
        return this.updateById(stockUninventory);
    }
}
src/main/resources/mapper/production/ProductWorkOrderFileMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.production.mapper.ProductWorkOrderFileMapper">
    <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.production.pojo.ProductWorkOrderFile">
        <id column="id" property="id" />
        <result column="work_order_id" property="workOrderId" />
        <result column="name" property="name" />
        <result column="url" property="url" />
        <result column="file_size" property="fileSize" />
        <result column="create_time" property="createTime" />
        <result column="create_user" property="createUser" />
        <result column="update_time" property="updateTime" />
        <result column="update_user" property="updateUser" />
        <result column="tenant_id" property="tenantId" />
    </resultMap>
</mapper>
src/main/resources/mapper/production/ProductWorkOrderMapper.xml
@@ -34,13 +34,42 @@
        LEFT JOIN product_process pp ON pp.id = ppri.process_id
        LEFT JOIN product_model pm ON pm.id = ppri.product_model_id
        LEFT JOIN product p ON p.id = pm.product_id
        <where>
        where 1=1
            <if test="c.workOrderNo != null and c.workOrderNo != ''">
                pwo.work_order_no like concat('%',#{c.workOrderNo},'%')
               and pwo.work_order_no like concat('%',#{c.workOrderNo},'%')
            </if>
            <if test="c.planStartTime != null and c.planEndTime != null">
                and DATE(pwo.create_time) between #{c.planStartTime} and #{c.planEndTime}
            </if>
        </where>
            <if test="c.productOrderId != null and c.productOrderId != ''">
               and pwo.product_order_id = #{c.productOrderId}
            </if>
    </select>
    <select id="getProductWorkOrderFlowCard" resultType="com.ruoyi.production.dto.ProductWorkOrderDto">
        SELECT
        pwo.*,
        pp.NAME as processName,
        pm.model,
        pm.unit,
        p.product_name AS productName,
        po.nps_no AS productOrderNpsNo,
        ROUND(pwo.complete_quantity / pwo.plan_quantity * 100, 2) AS completionStatus,
        sum(ppo.scrap_qty) scrapQty
        FROM
        product_work_order pwo
        LEFT JOIN product_process_route_item ppri ON ppri.id = pwo.product_process_route_item_id
        LEFT JOIN production_product_main ppm ON ppm.work_order_id = pwo.id
        LEFT JOIN production_product_output ppo ON ppo.product_main_id = ppm.id
        LEFT JOIN product_order po ON po.id = pwo.product_order_id
        LEFT JOIN product_process pp ON pp.id = ppri.process_id
        LEFT JOIN product_model pm ON pm.id = ppri.product_model_id
        LEFT JOIN product p ON p.id = pm.product_id
        WHERE pwo.id = #{id}
        GROUP BY pwo.id, pwo.product_process_route_item_id, pwo.create_time, pwo.update_time, pwo.work_order_no, pwo.plan_start_time, pwo.plan_end_time, pwo.actual_start_time, pwo.actual_end_time, pwo.status, pwo.tenant_id, pwo.plan_quantity, pwo.product_order_id, pwo.complete_quantity,
                 pp.NAME ,
                pm.model,
                pm.unit,
                p.product_name,
                po.nps_no
    </select>
</mapper>
src/main/resources/mapper/sales/SalesLedgerMapper.xml
@@ -56,6 +56,7 @@
        T1.attachment_materials,
        T1.tenant_id,
        T1.contract_amount,
        T1.contract_amount as noInvoiceAmountTotal,
        T1.execution_date,
        T2.nick_name AS entry_person_name,
        T1.payment_method
src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
@@ -7,10 +7,6 @@
    <select id="selectSalesLedgerProductList" resultType="com.ruoyi.sales.pojo.SalesLedgerProduct">
        SELECT
        T1.*,
        t3.shipping_car_number,
        t3.shipping_date,
        t3.status as shippingStatus,
        t3.shipping_date,
        CASE
        WHEN t2.qualitity > T1.quantity THEN 1
        ELSE 0
@@ -18,7 +14,6 @@
        FROM
        sales_ledger_product T1
        LEFT JOIN stock_inventory t2 ON T1.product_model_id = t2.product_model_id
        LEFT JOIN shipping_info t3 ON T1.id = t3.sales_ledger_product_id
        <where>
            1=1
            <if test="salesLedgerProduct.salesLedgerId != null and salesLedgerProduct.salesLedgerId != '' ">
@@ -28,6 +23,7 @@
                AND T1.type = #{salesLedgerProduct.type}
            </if>
        </where>
        ORDER BY T1.register_date DESC
    </select>
    <select id="selectSalesLedgerProductByMainId" resultType="com.ruoyi.sales.pojo.SalesLedgerProduct">
        select slp.*
@@ -158,7 +154,7 @@
        select
            p.product_name as product_category,
            pm.model as specification_model,
            pm.id
            pm.id as product_model_id
        from product_model pm
        left join product p on pm.product_id = p.id
    </select>
src/main/resources/mapper/sales/ShippingInfoMapper.xml
@@ -29,6 +29,13 @@
        <if test="req.shippingCarNumber != null and req.shippingCarNumber != ''">
            AND s.shipping_car_number LIKE CONCAT('%',#{req.shippingCarNumber},'%')
        </if>
        <if test="req.shippingNo != null and req.shippingNo != ''">
            AND s.shipping_no LIKE CONCAT('%',#{req.shippingNo},'%')
        </if>
        <if test="req.expressNumber != null and req.expressNumber != ''">
            AND s.express_number LIKE CONCAT('%',#{req.expressNumber},'%')
        </if>
        order by create_time DESC
    </select>
    <select id="listAll" resultType="com.ruoyi.sales.pojo.ShippingInfo">
        SELECT
src/main/resources/mapper/stock/StockInventoryMapper.xml
@@ -4,14 +4,14 @@
    <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.stock.pojo.StockInventory">
        <result column="id" property="id" />
        <result column="product_model_id" property="productModelId" />
        <result column="qualitity" property="qualitity" />
        <result column="create_time" property="createTime" />
        <result column="update_time" property="updateTime" />
        <result column="version" property="version" />
        <result column="locked_quantity" property="lockedQuantity" />
        <result column="warn_num" property="warnNum" />
        <result column="id" property="id"/>
        <result column="product_model_id" property="productModelId"/>
        <result column="qualitity" property="qualitity"/>
        <result column="create_time" property="createTime"/>
        <result column="update_time" property="updateTime"/>
        <result column="version" property="version"/>
        <result column="locked_quantity" property="lockedQuantity"/>
        <result column="warn_num" property="warnNum"/>
    </resultMap>
    <update id="updateAddStockInventory">
        update stock_inventory
@@ -19,11 +19,17 @@
            <if test="ew.qualitity != null">
                qualitity = qualitity + #{ew.qualitity},
            </if>
           <if test="ew.version != null">
               version = version + 1,
            <if test="ew.version != null">
                version = version + 1,
            </if>
            <if test="ew.remark != null and ew.remark !=''">
                remark = #{ew.remark},
            </if>
            <if test="ew.warnNum != null and ew.warnNum !=''">
                warn_num = #{ew.warnNum},
            </if>
            <if test="ew.lockedQuantity != null and ew.lockedQuantity !=''">
                locked_quantity = locked_quantity + #{ew.lockedQuantity},
            </if>
            update_time = now()
        </set>
@@ -46,13 +52,22 @@
        where product_model_id = #{ew.productModelId} and qualitity >= #{ew.qualitity}
    </update>
    <select id="pagestockInventory" resultType="com.ruoyi.stock.dto.StockInventoryDto">
        select si.*,
               pm.model,
               pm.unit,
               p.product_name
        select si.id,
        si.qualitity,
        COALESCE(si.locked_quantity, 0) as locked_quantity,
        si.product_model_id,
        si.create_time,
        si.update_time,
        COALESCE(si.warn_num, 0) as warn_num,
        si.version,
        (si.qualitity - COALESCE(si.locked_quantity, 0)) as un_locked_quantity,
        pm.model,
        si.remark,
        pm.unit,
        p.product_name
        from stock_inventory si
                 left join product_model pm on si.product_model_id = pm.id
                 left join product p on pm.product_id = p.id
        left join product_model pm on si.product_model_id = pm.id
        left join product p on pm.product_id = p.id
        where 1 = 1
        <if test="ew.productName != null and ew.productName !=''">
            and p.product_name like concat('%',#{ew.productName},'%')
@@ -63,6 +78,8 @@
        pm.model,
        pm.unit,
        p.product_name,
        coalesce(si.warn_num, 0) as warn_num,
        coalesce(si.locked_quantity, 0) as locked_quantity,
        si.remark,
        si.update_time
        from stock_inventory si
@@ -73,5 +90,103 @@
            and p.product_name like concat('%',#{ew.productName},'%')
        </if>
    </select>
    <select id="stockInventoryPage" resultType="com.ruoyi.stock.dto.StockInRecordDto">
        select sir.*,si.qualitity,
        pm.model,
        pm.unit,
        p.product_name
        from
        stock_in_record sir
        left join stock_inventory si on sir.product_model_id = si.product_model_id
        left join product_model pm on sir.product_model_id = pm.id
        left join product p on pm.product_id = p.id
        <where>
            <if test="ew.reportDate != null">
                and sir.create_time >= #{ew.reportDate}
                and sir.create_time &lt; DATE_ADD(#{ew.reportDate}, INTERVAL 1 DAY)
            </if>
            <if test="ew.startMonth != null">
                and sir.create_time &gt;= #{ew.startMonth}
            </if>
            <if test="ew.endMonth != null">
                and sir.create_time &lt;= #{ew.endMonth}
            </if>
        </where>
    </select>
    <select id="stockInAndOutRecord" resultType="com.ruoyi.stock.dto.StockInventoryDto">
        SELECT
        pm.model,
        pm.unit,
        p.product_name,
        MAX(current_inventory) as current_stock,
        SUM(CASE WHEN record_type = 'in' THEN amount ELSE 0 END) as total_stock_in,
        SUM(CASE WHEN record_type = 'out' THEN amount ELSE 0 END) as total_stock_out
        FROM (
        SELECT
        product_model_id,
        SUM(qualitity) as current_inventory,
        0 as amount,
        '' as record_type
        FROM stock_inventory
        GROUP BY product_model_id
        UNION ALL
        SELECT
        product_model_id,
        0 as current_inventory,
        SUM(stock_in_num) as amount,
        'in' as record_type
        FROM stock_in_record
        <where>
            type = 0
            <if test="ew.startMonth != null">
                and stock_in_record.create_time &gt;= #{ew.startMonth}
            </if>
            <if test="ew.endMonth != null">
                and stock_in_record.create_time &lt;= #{ew.endMonth}
            </if>
        </where>
        GROUP BY product_model_id
        UNION ALL
        SELECT
        product_model_id,
        0 as current_inventory,
        SUM(stock_out_num) as amount,
        'out' as record_type
        FROM stock_out_record
        <where>
            type = 0
            <if test="ew.startMonth != null">
                and stock_out_record.create_time &gt;= #{ew.startMonth}
            </if>
            <if test="ew.endMonth != null">
                and stock_out_record.create_time &lt;= #{ew.endMonth}
            </if>
        </where>
        GROUP BY product_model_id
        ) combined_data
        LEFT JOIN product_model pm ON pm.id = combined_data.product_model_id
        LEFT JOIN product p ON p.id = pm.product_id
        <where>
            <if test="ew.productName != null and ew.productName !=''">
                and p.product_name like concat('%',#{ew.productName},'%')
            </if>
            <if test="ew.model != null and ew.model !=''">
                and pm.model like concat('%',#{ew.model},'%')
            </if>
        </where>
        GROUP BY
        pm.model,
        pm.unit,
        p.product_name
    </select>
    <select id="selectTotal" resultType="java.math.BigDecimal">
        select sum(qualitity)
        from stock_inventory
    </select>
</mapper>
src/main/resources/mapper/stock/StockUninventoryMapper.xml
@@ -12,7 +12,7 @@
        <result column="version" property="version" />
    </resultMap>
    <update id="updateSubtractStockUnInventory">
        update stock_inventory
        update stock_uninventory
        <set>
            <if test="ew.qualitity != null">
                qualitity = qualitity - #{ew.qualitity},
@@ -28,7 +28,7 @@
        where product_model_id = #{ew.productModelId} and qualitity >= #{ew.qualitity}
    </update>
    <update id="updateAddStockUnInventory">
        update stock_inventory
        update stock_uninventory
        <set>
            <if test="ew.qualitity != null">
                qualitity = qualitity + #{ew.qualitity},
@@ -44,19 +44,27 @@
        where product_model_id = #{ew.productModelId}
    </update>
    <select id="pageStockUninventory" resultType="com.ruoyi.stock.dto.StockUninventoryDto">
        select su.*,
               pm.model,
               pm.unit,
               p.product_name
        select su.id,
        su.qualitity,
        COALESCE(su.locked_quantity, 0) as locked_quantity,
        su.product_model_id,
        su.create_time,
        su.update_time,
        su.version,
        su.update_time,
        (su.qualitity - COALESCE(su.locked_quantity, 0)) as un_locked_quantity,
        pm.model,
        pm.unit,
        p.product_name
        from stock_uninventory su
                 left join product_model pm on su.product_model_id = pm.id
                 left join product p on pm.product_id = p.id
        left join product_model pm on su.product_model_id = pm.id
        left join product p on pm.product_id = p.id
        where 1 = 1
        <if test="ew.productName != null and ew.productName !=''">
            and p.product_name like concat('%',#{ew.productName},'%')
        </if>
    </select>
    <select id="listStockInventoryExportData" resultType="com.ruoyi.stock.execl.StockInventoryExportData">
    <select id="listStockInventoryExportData" resultType="com.ruoyi.stock.execl.StockUnInventoryExportData">
        select su.*,
        pm.model,
        pm.unit,
src/main/resources/static/work-order-template.docx
Binary files differ
src/main/resources/static/ÏúÊŲ̂Õ˵¼ÈëÄ£°å.xlsx
Binary files differ