1.耗材迁移
2.仓储物流新增字段(毛重,皮重,净重)
3.设备保养多选(多条定时任务)
已添加35个文件
已修改12个文件
2971 ■■■■■ 文件已修改
src/main/java/com/ruoyi/consumables/controller/ConsumablesInRecordController.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/controller/ConsumablesInventoryController.java 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/controller/ConsumablesOutRecordController.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/controller/ConsumablesUnInventoryController.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/dto/ConsumablesInRecordDto.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/dto/ConsumablesInventoryDto.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/dto/ConsumablesOutRecordDto.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/dto/ConsumablesUnInventoryDto.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/execl/ConsumablesInRecordExportData.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/execl/ConsumablesInventoryExportData.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/execl/ConsumablesOutRecordExportData.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/execl/ConsumablesUnInventoryExportData.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/mapper/ConsumablesInRecordMapper.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/mapper/ConsumablesInventoryMapper.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/mapper/ConsumablesOutRecordMapper.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/mapper/ConsumablesUnInventoryMapper.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/pojo/ConsumablesInRecord.java 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/pojo/ConsumablesInventory.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/pojo/ConsumablesOutRecord.java 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/pojo/ConsumablesUnInventory.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/service/ConsumablesInRecordService.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/service/ConsumablesInventoryService.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/service/ConsumablesOutRecordService.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/service/ConsumablesUnInventoryService.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/service/impl/ConsumablesInRecordServiceImpl.java 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/service/impl/ConsumablesInventoryServiceImpl.java 227 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/service/impl/ConsumablesOutRecordServiceImpl.java 116 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/service/impl/ConsumablesUnInventoryServiceImpl.java 125 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/controller/MaintenanceTaskController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/dto/MaintenanceTaskDto.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/service/MaintenanceTaskService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/service/impl/DeviceLedgerServiceImpl.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskJob.java 107 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskServiceImpl.java 76 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/pojo/StockInRecord.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/pojo/StockInventory.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/pojo/StockOutRecord.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/word/ChineseNumberUtil.java 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/word/WeighbridgeDocGenerator.java 268 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/consumables/ConsumablesInRecordMapper.xml 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/consumables/ConsumablesInventoryMapper.xml 307 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/consumables/ConsumablesOutRecordMapper.xml 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/consumables/ConsumablesUninventoryMapper.xml 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/stock/StockInventoryMapper.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/consumables/controller/ConsumablesInRecordController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,51 @@
package com.ruoyi.consumables.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.consumables.dto.ConsumablesInRecordDto;
import com.ruoyi.consumables.service.ConsumablesInRecordService;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.AjaxResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
@RestController
@Api(tags = "耗材入库")
@RequestMapping("/consumablesInRecord")
public class ConsumablesInRecordController {
    @Autowired
    private ConsumablesInRecordService consumablesInRecordService;
    @GetMapping("/listPage")
    @Log(title = "生产入库-入库管理-列表", businessType = BusinessType.OTHER)
    @ApiOperation(value = "入库管理列表")
    public AjaxResult listPage(Page page, ConsumablesInRecordDto ConsumablesInRecordDto) {
        IPage<ConsumablesInRecordDto> result = consumablesInRecordService.listPage(page, ConsumablesInRecordDto);
        return AjaxResult.success(result);
    }
    @DeleteMapping("")
    @Log(title = "入库管理-删除入库", businessType = BusinessType.DELETE)
    public AjaxResult delete(@RequestBody List<Long> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
        }
        return AjaxResult.success(consumablesInRecordService.batchDelete(ids));
    }
    @PostMapping("/exportConsumablesInRecord")
    @ApiOperation("导出入库记录")
    public void exportConsumablesInRecord(HttpServletResponse response, ConsumablesInRecordDto ConsumablesInRecordDto) {
        consumablesInRecordService.exportConsumablesInRecord(response,ConsumablesInRecordDto);
    }
}
src/main/java/com/ruoyi/consumables/controller/ConsumablesInventoryController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,108 @@
package com.ruoyi.consumables.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.consumables.dto.ConsumablesInventoryDto;
import com.ruoyi.consumables.execl.ConsumablesInventoryExportData;
import com.ruoyi.consumables.service.ConsumablesInventoryService;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
/**
 * <p>
 * è€—材库存表 å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-21 04:16:36
 */
@RestController
@RequestMapping("/consumablesInventory")
@Api(tags = "耗材库存表")
public class ConsumablesInventoryController {
    @Autowired
    private ConsumablesInventoryService ConsumablesInventoryService;
    @GetMapping("/pageConsumablesInventory")
    @ApiOperation("分页查询库存")
    public R pageConsumablesInventory(Page page, ConsumablesInventoryDto ConsumablesInventoryDto) {
        IPage<ConsumablesInventoryDto> ConsumablesInventoryDtoIPage = ConsumablesInventoryService.pageConsumablesInventory(page, ConsumablesInventoryDto);
        return R.ok(ConsumablesInventoryDtoIPage);
    }
    @PostMapping("/addConsumablesInventory")
    @ApiOperation("新增库存")
    public R addConsumablesInventory(@RequestBody ConsumablesInventoryDto ConsumablesInventoryDto) {
        ConsumablesInventoryDto.setRecordType(String.valueOf(StockInQualifiedRecordTypeEnum.CUSTOMIZATION_STOCK_IN.getCode()));
        ConsumablesInventoryDto.setRecordId(0L);
        return R.ok(ConsumablesInventoryService.addConsumablesInventory(ConsumablesInventoryDto));
    }
    @PostMapping("/subtractConsumablesInventory")
    @ApiOperation("扣减库存")
    public R subtractConsumablesInventory(@RequestBody ConsumablesInventoryDto ConsumablesInventoryDto) {
        ConsumablesInventoryDto.setRecordType(String.valueOf(StockOutQualifiedRecordTypeEnum.CUSTOMIZATION_STOCK_OUT.getCode()));
        ConsumablesInventoryDto.setRecordId(0L);
        return R.ok(ConsumablesInventoryService.subtractConsumablesInventory(ConsumablesInventoryDto));
    }
    @PostMapping("importConsumablesInventory")
    @ApiOperation("导入库存")
    public R importConsumablesInventory(MultipartFile file) {
        return ConsumablesInventoryService.importConsumablesInventory(file);
    }
    @Log(title = "下载库存导入模板", businessType = BusinessType.EXPORT)
    @PostMapping("/downloadConsumablesInventory")
    public void downloadConsumablesInventory(HttpServletResponse response) {
        List<ConsumablesInventoryExportData> list = new ArrayList<>();
        ExcelUtil<ConsumablesInventoryExportData> util = new ExcelUtil<>(ConsumablesInventoryExportData.class);
        util.exportExcel(response, list, "库存模板");
    }
    @PostMapping("/exportConsumablesInventory")
    @ApiOperation("导出库存")
    public void exportConsumablesInventory(HttpServletResponse response, ConsumablesInventoryDto ConsumablesInventoryDto) {
        ConsumablesInventoryService.exportConsumablesInventory(response, ConsumablesInventoryDto);
    }
    @GetMapping("ConsumablesInventoryPage")
    @ApiOperation("库存报表查询")
    public R ConsumablesInventoryPage(Page page, ConsumablesInventoryDto consumablesInventoryDto) {
        return R.ok(ConsumablesInventoryService.consumablesInventoryPage(consumablesInventoryDto,page));
    }
    @GetMapping("ConsumablesInAndOutRecord")
    @ApiOperation("统计各个产品的入库和出库记录")
    public R ConsumablesInAndOutRecord(ConsumablesInventoryDto consumablesInventoryDto, Page page) {
        return R.ok(ConsumablesInventoryService.consumablesInAndOutRecord(consumablesInventoryDto,page));
    }
    @PostMapping("/frozenConsumables")
    @ApiOperation("冻结库存")
    public R frozenConsumables(@RequestBody ConsumablesInventoryDto ConsumablesInventoryDto) {
        return R.ok(ConsumablesInventoryService.frozenConsumables(ConsumablesInventoryDto));
    }
    @PostMapping("/thawConsumables")
    @ApiOperation("解冻库存")
    public R thawConsumables(@RequestBody ConsumablesInventoryDto ConsumablesInventoryDto) {
        return R.ok(ConsumablesInventoryService.thawConsumables(ConsumablesInventoryDto));
    }
}
src/main/java/com/ruoyi/consumables/controller/ConsumablesOutRecordController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,69 @@
package com.ruoyi.consumables.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.consumables.dto.ConsumablesOutRecordDto;
import com.ruoyi.consumables.service.ConsumablesOutRecordService;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.AjaxResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
 * <p>
 * è€—材出库记录表 å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-21 05:27:04
 */
@Api(tags = "耗材出库")
@RestController
@RequestMapping("/consumablesOutRecord")
public class ConsumablesOutRecordController {
    @Autowired
    private ConsumablesOutRecordService consumablesUnInventoryDto;
    @GetMapping("/listPage")
    @Log(title = "生产出库-出库管理-列表", businessType = BusinessType.OTHER)
    @ApiOperation(value = "出库管理列表")
    public AjaxResult listPage(Page page, ConsumablesOutRecordDto ConsumablesOutRecordDto) {
        IPage<ConsumablesOutRecordDto> result = consumablesUnInventoryDto.listPage(page, ConsumablesOutRecordDto);
        return AjaxResult.success(result);
    }
    @PostMapping("")
    @Log(title = "出库管理-新增出库", businessType = BusinessType.INSERT)
    public AjaxResult add(@RequestBody ConsumablesOutRecordDto ConsumablesOutRecordDto) {
        return AjaxResult.success(consumablesUnInventoryDto.add(ConsumablesOutRecordDto));
    }
    @PutMapping("/{id}")
    @Log(title = "出库管理-更新出库", businessType = BusinessType.UPDATE)
    public AjaxResult update(@PathVariable("id") Long id, @RequestBody ConsumablesOutRecordDto ConsumablesOutRecordDto) {
        return AjaxResult.success(consumablesUnInventoryDto.update(id, ConsumablesOutRecordDto));
    }
    @DeleteMapping("")
    @Log(title = "出库管理-删除出库", businessType = BusinessType.DELETE)
    public AjaxResult delete(@RequestBody List<Long> ids) {
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
        }
        return AjaxResult.success(consumablesUnInventoryDto.batchDelete(ids));
    }
    @PostMapping("/exportConsumablesOutRecord")
    @ApiOperation("导出出库记录")
    public void exportConsumablesOutRecord(HttpServletResponse response, ConsumablesOutRecordDto ConsumablesOutRecordDto) {
        consumablesUnInventoryDto.exportConsumablesOutRecord(response,ConsumablesOutRecordDto);
    }
}
src/main/java/com/ruoyi/consumables/controller/ConsumablesUnInventoryController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,76 @@
package com.ruoyi.consumables.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockOutUnQualifiedRecordTypeEnum;
import com.ruoyi.consumables.dto.ConsumablesInventoryDto;
import com.ruoyi.consumables.dto.ConsumablesUnInventoryDto;
import com.ruoyi.consumables.service.ConsumablesUnInventoryService;
import com.ruoyi.framework.web.domain.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
/**
 * <p>
 * è€—材不合格库存表 å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-22 10:17:45
 */
@Api(tags = "耗材不合格")
@RestController
@RequestMapping("/consumablesUnInventory")
public class ConsumablesUnInventoryController {
    @Autowired
    private ConsumablesUnInventoryService consumablesUnInventoryService;
    @GetMapping("/pageConsumablesUnInventory")
    @ApiOperation("分页查询库存")
    public R pageConsumablesUnInventory(Page page, ConsumablesUnInventoryDto consumablesUnInventoryDto) {
        IPage<ConsumablesUnInventoryDto> ConsumablesUnInventoryDtoIPage = consumablesUnInventoryService.pageConsumablesUnInventory(page, consumablesUnInventoryDto);
        return R.ok(ConsumablesUnInventoryDtoIPage);
    }
    @PostMapping("/addConsumablesUnInventory")
    @ApiOperation("新增库存")
    public R addConsumablesUnInventory(@RequestBody ConsumablesUnInventoryDto consumablesUnInventoryDto) {
        consumablesUnInventoryDto.setRecordType(String.valueOf(StockInUnQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_IN.getCode()));
        consumablesUnInventoryDto.setRecordId(0L);
        return R.ok(consumablesUnInventoryService.addConsumablesUnInventory(consumablesUnInventoryDto));
    }
    @PostMapping("/subtractConsumablesUnInventory")
    @ApiOperation("扣减库存")
    public R subtractConsumablesUnInventory(@RequestBody ConsumablesUnInventoryDto consumablesUnInventoryDto) {
        consumablesUnInventoryDto.setRecordType(String.valueOf(StockOutUnQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_OUT.getCode()));
        consumablesUnInventoryDto.setRecordId(0L);
        return R.ok(consumablesUnInventoryService.subtractConsumablesUnInventory(consumablesUnInventoryDto));
    }
    @PostMapping("/exportConsumablesUnInventory")
    @ApiOperation("导出库存")
    public void exportConsumablesUnInventory(HttpServletResponse response, ConsumablesUnInventoryDto consumablesUnInventoryDto) {
        consumablesUnInventoryService.exportConsumablesUnInventory(response,consumablesUnInventoryDto);
    }
    @PostMapping("/frozenConsumables")
    @ApiOperation("冻结库存")
    public R frozenConsumables(@RequestBody ConsumablesInventoryDto consumablesUnInventoryDto) {
        return R.ok(consumablesUnInventoryService.frozenConsumables(consumablesUnInventoryDto));
    }
    @PostMapping("/thawConsumables")
    @ApiOperation("解冻库存")
    public R thawConsumables(@RequestBody ConsumablesInventoryDto consumablesUnInventoryDto) {
        return R.ok(consumablesUnInventoryService.thawConsumables(consumablesUnInventoryDto));
    }
}
src/main/java/com/ruoyi/consumables/dto/ConsumablesInRecordDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,38 @@
package com.ruoyi.consumables.dto;
import com.ruoyi.consumables.pojo.ConsumablesInRecord;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
@EqualsAndHashCode(callSuper = true)
@Data
public class ConsumablesInRecordDto extends ConsumablesInRecord {
    private static final long serialVersionUID = 1L;
    /**
     * äº§å“åç§°
     */
    private String productName;
    /**
     * äº§å“è§„æ ¼
     */
    private String model;
    /**
     * äº§å“å•位
     */
    private String unit;
    private String timeStr;
    private String createBy;
    //现存量
    private String currentconsumables;
    //现净重
    private BigDecimal currentWeight;
}
src/main/java/com/ruoyi/consumables/dto/ConsumablesInventoryDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,71 @@
package com.ruoyi.consumables.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.consumables.pojo.ConsumablesInventory;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
public class ConsumablesInventoryDto extends ConsumablesInventory {
    private String productName;
    private String model;
    private String unit;
    //入库类型
    private String recordType;
    //入库类型对应的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 totalconsumablesIn;
    private BigDecimal totalconsumablesOut;
    private BigDecimal currentconsumables;
    private BigDecimal  unLockedQuantity;
    private Long parentId;
    @ApiModelProperty("过磅日期")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime weighingDate;
    private String  parentName;
    @ApiModelProperty("净重(总数)")
    private BigDecimal netWeight;
    @ApiModelProperty("车牌号")
    private String licensePlateNo;
    @ApiModelProperty("毛重")
    private BigDecimal grossWeight;
    @ApiModelProperty("皮重")
    private BigDecimal tareWeight;
    @ApiModelProperty("过磅员")
    private String weighingOperator;
    @ApiModelProperty("磅单文件路径")
    private String weighbridgeDocPath;
}
src/main/java/com/ruoyi/consumables/dto/ConsumablesOutRecordDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
package com.ruoyi.consumables.dto;
import com.ruoyi.consumables.pojo.ConsumablesOutRecord;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ConsumablesOutRecordDto extends ConsumablesOutRecord {
    /**
     * äº§å“åç§°
     */
    private String productName;
    /**
     * äº§å“è§„æ ¼
     */
    private String model;
    /**
     * äº§å“å•位
     */
    private String unit;
    private String timeStr;
    private String createBy;
}
src/main/java/com/ruoyi/consumables/dto/ConsumablesUnInventoryDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
package com.ruoyi.consumables.dto;
import com.ruoyi.consumables.pojo.ConsumablesUnInventory;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class ConsumablesUnInventoryDto  extends ConsumablesUnInventory {
    private String productName;
    private String model;
    private String unit;
    //入库类型
    private String recordType;
    //入库类型对应的id
    private Long recordId;
    private BigDecimal unLockedQuantity;
}
src/main/java/com/ruoyi/consumables/execl/ConsumablesInRecordExportData.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,32 @@
package com.ruoyi.consumables.execl;
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.time.LocalDateTime;
@Data
public class ConsumablesInRecordExportData {
    @Excel(name = "入库批次")
    private String inboundBatches;
    @Excel(name = "产品名称")
    private String productName;
    @Excel(name = "规格型号")
    private String model;
    @Excel(name = "单位")
    private String unit;
    @Excel(name = "入库来源")
    private String recordType;
    @Excel(name = "入库数量")
    private String ConsumablesInNum;
    @Excel(name = "入库时间")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
    @Excel(isExport = false)
    private String type;
}
src/main/java/com/ruoyi/consumables/execl/ConsumablesInventoryExportData.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,39 @@
package com.ruoyi.consumables.execl;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class ConsumablesInventoryExportData {
    @Excel(name = "产品名称")
    private String productName;
    @Excel(name = "规格")
    private String model;
    @Excel(name = "单位")
    private String unit;
    @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;
}
src/main/java/com/ruoyi/consumables/execl/ConsumablesOutRecordExportData.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
package com.ruoyi.consumables.execl;
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.time.LocalDateTime;
@Data
public class ConsumablesOutRecordExportData {
    @Excel(name = "出库批次")
    private String outboundBatches;
    @Excel(name = "产品名称")
    private String productName;
    @Excel(name = "规格型号")
    private String model;
    @Excel(name = "单位")
    private String unit;
    @Excel(name = "出库来源")
    private String recordType;
    @Excel(name = "出库数量")
    private String ConsumablesInNum;
    @Excel(name = "出库时间")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
    @Excel(isExport = false)
    private String type;
}
src/main/java/com/ruoyi/consumables/execl/ConsumablesUnInventoryExportData.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,36 @@
package com.ruoyi.consumables.execl;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class ConsumablesUnInventoryExportData {
    @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/consumables/mapper/ConsumablesInRecordMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
package com.ruoyi.consumables.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.consumables.dto.ConsumablesInRecordDto;
import com.ruoyi.consumables.execl.ConsumablesInRecordExportData;
import com.ruoyi.consumables.pojo.ConsumablesInRecord;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ConsumablesInRecordMapper extends BaseMapper<ConsumablesInRecord> {
    IPage<ConsumablesInRecordDto> listPage(Page page, @Param("params") ConsumablesInRecordDto ConsumablesInRecordDto);
    List<ConsumablesInRecordExportData> listConsumablesInRecordExportData(@Param("params") ConsumablesInRecordDto ConsumablesInRecordDto);
}
src/main/java/com/ruoyi/consumables/mapper/ConsumablesInventoryMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,52 @@
package com.ruoyi.consumables.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.consumables.dto.ConsumablesInRecordDto;
import com.ruoyi.consumables.dto.ConsumablesInventoryDto;
import com.ruoyi.consumables.execl.ConsumablesInventoryExportData;
import com.ruoyi.consumables.pojo.ConsumablesInventory;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
 * <p>
 * åº“存表 Mapper æŽ¥å£
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-21 04:16:36
 */
@Mapper
public interface ConsumablesInventoryMapper extends BaseMapper<ConsumablesInventory> {
    IPage<ConsumablesInventoryDto> pageConsumablesInventory(Page page, @Param("ew") ConsumablesInventoryDto ConsumablesInventoryDto);
    int updateAddConsumablesInventory(@Param("ew") ConsumablesInventoryDto ConsumablesInventoryDto);
    int updateSubtractConsumablesInventory(@Param("ew") ConsumablesInventoryDto ConsumablesInventoryDto);
    List<ConsumablesInventoryExportData> listConsumablesInventoryExportData(@Param("ew") ConsumablesInventoryDto ConsumablesInventoryDto);
    IPage<ConsumablesInRecordDto> ConsumablesInventoryPage(@Param("ew") ConsumablesInventoryDto ConsumablesInventoryDto, Page page);
    IPage<ConsumablesInventoryDto> ConsumablesInAndOutRecord(@Param("ew") ConsumablesInventoryDto ConsumablesInventoryDto, Page page);
    BigDecimal selectTotal();
    int selectStorageProductCountByDate(@Param("startDate") LocalDateTime startDate, @Param("endDate") LocalDateTime endDate);
    List<Map<String, Object>> selectDailyConsumablesInCounts(@Param("rootCategoryId") Long rootCategoryId, @Param("startDate") String startDate, @Param("endDate") String endDate);
    List<Map<String, Object>> selectDailyConsumablesOutCounts(@Param("rootCategoryId") Long rootCategoryId, @Param("startDate") String startDate, @Param("endDate") String endDate);
    BigDecimal selectTotalByDate(@Param("now") LocalDate now);
}
src/main/java/com/ruoyi/consumables/mapper/ConsumablesOutRecordMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
package com.ruoyi.consumables.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.consumables.dto.ConsumablesOutRecordDto;
import com.ruoyi.consumables.execl.ConsumablesOutRecordExportData;
import com.ruoyi.consumables.pojo.ConsumablesOutRecord;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
 * <p>
 * å‡ºåº“记录表 Mapper æŽ¥å£
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-21 05:27:04
 */
@Mapper
public interface ConsumablesOutRecordMapper extends BaseMapper<ConsumablesOutRecord> {
    IPage<ConsumablesOutRecordDto> listPage(Page page, @Param("params") ConsumablesOutRecordDto ConsumablesOutRecordDto);
    List<ConsumablesOutRecordExportData> listConsumablesOutRecordExportData(@Param("params") ConsumablesOutRecordDto ConsumablesOutRecordDto);
}
src/main/java/com/ruoyi/consumables/mapper/ConsumablesUnInventoryMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,32 @@
package com.ruoyi.consumables.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.consumables.dto.ConsumablesUnInventoryDto;
import com.ruoyi.consumables.execl.ConsumablesUnInventoryExportData;
import com.ruoyi.consumables.pojo.ConsumablesUnInventory;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
 * <p>
 * ä¸åˆæ ¼åº“存表 Mapper æŽ¥å£
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-22 10:17:45
 */
@Mapper
public interface ConsumablesUnInventoryMapper extends BaseMapper<ConsumablesUnInventory> {
    IPage<ConsumablesUnInventoryDto> pageConsumablesUnInventory(Page page, @Param("ew") ConsumablesUnInventoryDto ConsumablesUnInventoryDto);
    int updateSubtractConsumablesUnInventory(@Param("ew") ConsumablesUnInventoryDto ConsumablesUnInventoryDto);
    int updateAddConsumablesUnInventory(@Param("ew") ConsumablesUnInventoryDto ConsumablesUnInventoryDto);
    List<ConsumablesUnInventoryExportData> listConsumablesInventoryExportData(@Param("ew") ConsumablesUnInventoryDto ConsumablesUnInventoryDto);
}
src/main/java/com/ruoyi/consumables/pojo/ConsumablesInRecord.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,103 @@
package com.ruoyi.consumables.pojo;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
@TableName("consumables_in_record")
@ApiModel("入库管理")
public class ConsumablesInRecord implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * åºå·
     */
    @TableId(type = IdType.AUTO)
    private Long id;
    @ApiModelProperty(value = "入库批次")
    private String inboundBatches;
    @ApiModelProperty(value = "入库数量")
    private BigDecimal consumablesInNum;
    @ApiModelProperty(value = "记录类型  æžšä¸¾")
    private String recordType;
    @ApiModelProperty(value = "记录ID  ")
    private Long recordId;
    @ApiModelProperty(value = "产品规格ID")
    private Long productModelId;
    @ApiModelProperty(value = "备注")
    private String remark;
    @ApiModelProperty(value = "类型  0合格入库 1不合格入库")
    private String type;
    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
    @ApiModelProperty(value = "创建用户")
    @TableField(fill = FieldFill.INSERT)
    private Integer createUser;
    @ApiModelProperty(value = "修改时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;
    @ApiModelProperty(value = "修改用户")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Integer updateUser;
    @ApiModelProperty("过磅日期")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime weighingDate;
    @ApiModelProperty("净重")
    private BigDecimal netWeight;
    /**
     * æ¯›é‡ï¼ˆå•位:吨)
     */
    @ApiModelProperty("毛重")
    private BigDecimal grossWeight;
    /**
     * çš®é‡ï¼ˆå•位:吨)
     */
    @ApiModelProperty("皮重")
    private BigDecimal tareWeight;
    /**
     * è½¦ç‰Œå·
     */
    @ApiModelProperty("车牌号")
    private String licensePlateNo;
    /**
     * è¿‡ç£…员
     */
    @ApiModelProperty("过磅员")
    private String weighingOperator;
    @ApiModelProperty("磅单文件路径")
    private String weighbridgeDocPath;
    @ApiModelProperty("产品id")
    private Long productId;
}
src/main/java/com/ruoyi/consumables/pojo/ConsumablesInventory.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,69 @@
package com.ruoyi.consumables.pojo;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
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 javax.validation.constraints.NotBlank;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
 * <p>
 * åº“存表
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-21 04:16:36
 */
@Getter
@Setter
@TableName("consumables_inventory")
@ApiModel(value = "consumablesInventory对象", description = "库存表")
public class ConsumablesInventory implements Serializable {
    private static final long serialVersionUID = 1L;
    @ApiModelProperty("主键id")
    private Long id;
    @ApiModelProperty("规格id")
    @NotBlank(message = "不能为空")
    private Long productModelId;
    @ApiModelProperty("数量")
    private BigDecimal qualitity;
    @TableField(fill = FieldFill.INSERT)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
    @ApiModelProperty("更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;
    @ApiModelProperty("版本号")
    private Integer version;
    @ApiModelProperty("被订单锁定数量")
    private BigDecimal lockedQuantity;
    @ApiModelProperty("预警数量")
    private BigDecimal warnNum;
    @ApiModelProperty("备注")
    private String remark;
    @ApiModelProperty("产品id")
    private Long productId;
}
src/main/java/com/ruoyi/consumables/pojo/ConsumablesOutRecord.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,97 @@
package com.ruoyi.consumables.pojo;
import com.baomidou.mybatisplus.annotation.*;
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>
 * å‡ºåº“记录表
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-21 05:27:04
 */
@Getter
@Setter
@TableName("consumables_out_record")
@ApiModel(value = "consumablesOutRecord对象", description = "出库记录表")
public class ConsumablesOutRecord implements Serializable {
    private static final long serialVersionUID = 1L;
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    @ApiModelProperty("入库批次")
    private String outboundBatches;
    @ApiModelProperty("入库数量")
    private BigDecimal consumablesOutNum;
    @ApiModelProperty("入库来源id")
    private Long recordId;
    @ApiModelProperty("入库类型")
    private String recordType;
    @ApiModelProperty("产品规格id")
    private Long productModelId;
    @ApiModelProperty("备注")
    private String remark;
    @ApiModelProperty("创建时间")
    @TableField(fill = FieldFill.INSERT)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
    @ApiModelProperty("更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;
    @ApiModelProperty("创建人")
    @TableField(fill = FieldFill.INSERT)
    private Integer createUser;
    @ApiModelProperty("更新人")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Integer updateUser;
    @ApiModelProperty(value = "类型  0合格入库 1不合格入库")
    private String type;
    @ApiModelProperty("过磅日期")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime weighingDate;
    @ApiModelProperty("净重")
    private BigDecimal netWeight;
    @ApiModelProperty("车牌号")
    private String licensePlateNo;
    @ApiModelProperty("毛重")
    private BigDecimal grossWeight;
    @ApiModelProperty("皮重")
    private BigDecimal tareWeight;
    @ApiModelProperty("过磅员")
    private String weighingOperator;
    @ApiModelProperty("产品id")
    private Long productId;
}
src/main/java/com/ruoyi/consumables/pojo/ConsumablesUnInventory.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,62 @@
package com.ruoyi.consumables.pojo;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
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>
 * ä¸åˆæ ¼åº“存表
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-22 10:17:45
 */
@Getter
@Setter
@TableName("consumables_UnInventory")
@ApiModel(value = "consumablesUnInventory对象", description = "不合格库存表")
public class ConsumablesUnInventory implements Serializable {
    private static final long serialVersionUID = 1L;
    @ApiModelProperty("主键id")
    private Long id;
    @ApiModelProperty("规格id")
    private Long productModelId;
    @ApiModelProperty("数量")
    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)
    @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;
    @ApiModelProperty("备注")
    private String remark;
    @ApiModelProperty("被订单锁定数量")
    private BigDecimal lockedQuantity;
}
src/main/java/com/ruoyi/consumables/service/ConsumablesInRecordService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
package com.ruoyi.consumables.service;
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.consumables.dto.ConsumablesInRecordDto;
import com.ruoyi.consumables.pojo.ConsumablesInRecord;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
public interface ConsumablesInRecordService extends IService<ConsumablesInRecord> {
    IPage<ConsumablesInRecordDto> listPage(Page page, ConsumablesInRecordDto consumablesInRecordDto);
    int add(ConsumablesInRecordDto consumablesInRecordDto);
    int update(Long id, ConsumablesInRecordDto consumablesInRecordDto);
    int batchDelete(List<Long> ids);
    void exportConsumablesInRecord(HttpServletResponse response, ConsumablesInRecordDto consumablesInRecordDto);
}
src/main/java/com/ruoyi/consumables/service/ConsumablesInventoryService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,41 @@
package com.ruoyi.consumables.service;
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.consumables.dto.ConsumablesInRecordDto;
import com.ruoyi.consumables.dto.ConsumablesInventoryDto;
import com.ruoyi.consumables.pojo.ConsumablesInventory;
import com.ruoyi.framework.web.domain.R;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
/**
 * <p>
 * åº“存表 æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-21 04:16:36
 */
public interface ConsumablesInventoryService extends IService<ConsumablesInventory> {
    IPage<ConsumablesInventoryDto> pageConsumablesInventory(Page page, ConsumablesInventoryDto consumablesInventoryDto);
    Boolean addConsumablesInventory(ConsumablesInventoryDto consumablesInventoryDto);
    Boolean subtractConsumablesInventory(ConsumablesInventoryDto consumablesInventoryDto);
    R importConsumablesInventory(MultipartFile file);
    void exportConsumablesInventory(HttpServletResponse response, ConsumablesInventoryDto consumablesInventoryDto);
    IPage<ConsumablesInRecordDto> consumablesInventoryPage(ConsumablesInventoryDto consumablesInventoryDto, Page page);
    IPage<ConsumablesInventoryDto> consumablesInAndOutRecord(ConsumablesInventoryDto consumablesInventoryDto, Page page);
    Boolean frozenConsumables(ConsumablesInventoryDto consumablesInventoryDto);
    Boolean thawConsumables(ConsumablesInventoryDto consumablesInventoryDto);
}
src/main/java/com/ruoyi/consumables/service/ConsumablesOutRecordService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
package com.ruoyi.consumables.service;
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.consumables.dto.ConsumablesOutRecordDto;
import com.ruoyi.consumables.pojo.ConsumablesOutRecord;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
 * <p>
 * å‡ºåº“记录表 æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-21 05:27:04
 */
public interface ConsumablesOutRecordService extends IService<ConsumablesOutRecord> {
    IPage<ConsumablesOutRecordDto> listPage(Page page, ConsumablesOutRecordDto ConsumablesOutRecordDto);
    int add(ConsumablesOutRecordDto ConsumablesOutRecordDto);
    int update(Long id, ConsumablesOutRecordDto ConsumablesOutRecordDto);
    int batchDelete(List<Long> ids);
    void exportConsumablesOutRecord(HttpServletResponse response, ConsumablesOutRecordDto ConsumablesOutRecordDto);
}
src/main/java/com/ruoyi/consumables/service/ConsumablesUnInventoryService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,33 @@
package com.ruoyi.consumables.service;
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.consumables.dto.ConsumablesInventoryDto;
import com.ruoyi.consumables.dto.ConsumablesUnInventoryDto;
import com.ruoyi.consumables.pojo.ConsumablesUnInventory;
import javax.servlet.http.HttpServletResponse;
/**
 * <p>
 * ä¸åˆæ ¼åº“存表 æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-22 10:17:45
 */
public interface ConsumablesUnInventoryService extends IService<ConsumablesUnInventory> {
    IPage<ConsumablesUnInventoryDto> pageConsumablesUnInventory(Page page, ConsumablesUnInventoryDto ConsumablesUnInventoryDto);
    Integer addConsumablesUnInventory(ConsumablesUnInventoryDto ConsumablesUnInventoryDto);
    Integer subtractConsumablesUnInventory(ConsumablesUnInventoryDto ConsumablesUnInventoryDto);
    void exportConsumablesUnInventory(HttpServletResponse response, ConsumablesUnInventoryDto ConsumablesUnInventoryDto);
    Boolean frozenConsumables(ConsumablesInventoryDto ConsumablesInventoryDto);
    Boolean thawConsumables(ConsumablesInventoryDto ConsumablesInventoryDto);
}
src/main/java/com/ruoyi/consumables/service/impl/ConsumablesInRecordServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,113 @@
package com.ruoyi.consumables.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.common.enums.StockInUnQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.EnumUtil;
import com.ruoyi.common.utils.OrderUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.consumables.dto.ConsumablesInRecordDto;
import com.ruoyi.consumables.dto.ConsumablesInventoryDto;
import com.ruoyi.consumables.dto.ConsumablesUnInventoryDto;
import com.ruoyi.consumables.execl.ConsumablesInRecordExportData;
import com.ruoyi.consumables.mapper.ConsumablesInRecordMapper;
import com.ruoyi.consumables.mapper.ConsumablesInventoryMapper;
import com.ruoyi.consumables.mapper.ConsumablesUnInventoryMapper;
import com.ruoyi.consumables.pojo.ConsumablesInRecord;
import com.ruoyi.consumables.pojo.ConsumablesInventory;
import com.ruoyi.consumables.pojo.ConsumablesUnInventory;
import com.ruoyi.consumables.service.ConsumablesInRecordService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
@Service
@AllArgsConstructor
public class ConsumablesInRecordServiceImpl extends ServiceImpl<ConsumablesInRecordMapper, ConsumablesInRecord> implements ConsumablesInRecordService {
    private ConsumablesInRecordMapper consumablesInRecordMapper;
    private ConsumablesInventoryMapper consumablesInventoryMapper;
    private ConsumablesUnInventoryMapper consumablesUnInventoryMapper;
    @Override
    public IPage<ConsumablesInRecordDto> listPage(Page page, ConsumablesInRecordDto consumablesInRecordDto) {
        return consumablesInRecordMapper.listPage(page, consumablesInRecordDto);
    }
    // æ–°å¢žå…¥åº“
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int add(ConsumablesInRecordDto consumablesInRecordDto) {
        String no = OrderUtils.countTodayByCreateTime(consumablesInRecordMapper, "RK");
        consumablesInRecordDto.setInboundBatches(no);
        ConsumablesInRecord consumablesInRecord = new ConsumablesInRecord();
        BeanUtils.copyProperties(consumablesInRecordDto, consumablesInRecord);
        return consumablesInRecordMapper.insert(consumablesInRecord);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int update(Long id, ConsumablesInRecordDto consumablesInRecordDto) {
        // åˆ¤æ–­å¯¹è±¡æ˜¯å¦å­˜åœ¨
        ConsumablesInRecord consumablesInRecord = consumablesInRecordMapper.selectById(id);
        if (consumablesInRecord == null){
            throw new BaseException("该入库记录不存在,无法更新!!!");
        }
        String[] ignoreProperties = {"id", "inbound_batches"};//排除id属性
        BeanUtils.copyProperties(consumablesInRecordDto, consumablesInRecord, ignoreProperties);
        return consumablesInRecordMapper.updateById(consumablesInRecord);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchDelete(List<Long> ids) {
        for (Long id : ids) {
            ConsumablesInRecord consumablesInRecord = consumablesInRecordMapper.selectById(id);
            if (consumablesInRecord.getType().equals("0")) {
                ConsumablesInventory consumablesInventory = consumablesInventoryMapper.selectOne(new LambdaQueryWrapper<ConsumablesInventory>().eq(ConsumablesInventory::getProductModelId, consumablesInRecord.getProductModelId()));
                if (consumablesInventory == null) {
                    throw new BaseException("库存记录中没有对应的产品,无法删除!!!");
                }else {
                    ConsumablesInventoryDto consumablesInRecordDto = new ConsumablesInventoryDto();
                    consumablesInRecordDto.setProductModelId(consumablesInventory.getProductModelId());
                    consumablesInRecordDto.setQualitity(consumablesInRecord.getConsumablesInNum());
                    consumablesInventoryMapper.updateSubtractConsumablesInventory(consumablesInRecordDto);
                }
            }else if (consumablesInRecord.getType().equals("1")) {
                ConsumablesUnInventory consumablesUnInventory = consumablesUnInventoryMapper.selectOne(new LambdaQueryWrapper<ConsumablesUnInventory>().eq(ConsumablesUnInventory::getProductModelId, consumablesInRecord.getProductModelId()));
                if (consumablesUnInventory == null) {
                    throw new BaseException("库存记录中没有对应的产品,无法删除!!!");
                }else {
                    ConsumablesUnInventoryDto consumablesUnInventoryDto = new ConsumablesUnInventoryDto();
                    consumablesUnInventoryDto.setProductModelId(consumablesUnInventory.getProductModelId());
                    consumablesUnInventoryDto.setQualitity(consumablesInRecord.getConsumablesInNum());
                    consumablesUnInventoryMapper.updateSubtractConsumablesUnInventory(consumablesUnInventoryDto);
                }
            }
        }
        return consumablesInRecordMapper.deleteBatchIds(ids);
    }
    @Override
    public void exportConsumablesInRecord(HttpServletResponse response, ConsumablesInRecordDto consumablesInRecordDto) {
        List<ConsumablesInRecordExportData> list = consumablesInRecordMapper.listConsumablesInRecordExportData(consumablesInRecordDto);
        for (ConsumablesInRecordExportData consumablesInRecordExportData : list) {
            if (consumablesInRecordExportData.getType().equals("0")) {
                consumablesInRecordExportData.setRecordType(EnumUtil.fromCode(StockOutQualifiedRecordTypeEnum.class, Integer.parseInt(consumablesInRecordExportData.getRecordType())).getValue());
            }else {
                consumablesInRecordExportData.setRecordType(EnumUtil.fromCode(StockInUnQualifiedRecordTypeEnum.class, Integer.parseInt(consumablesInRecordExportData.getRecordType())).getValue());
            }
        }
        ExcelUtil<ConsumablesInRecordExportData> util = new ExcelUtil<>(ConsumablesInRecordExportData.class);
        util.exportExcel(response,list, "入库记录信息");
    }
}
src/main/java/com/ruoyi/consumables/service/impl/ConsumablesInventoryServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,227 @@
package com.ruoyi.consumables.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.enums.StockInQualifiedRecordTypeEnum;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.consumables.dto.ConsumablesInRecordDto;
import com.ruoyi.consumables.dto.ConsumablesInventoryDto;
import com.ruoyi.consumables.dto.ConsumablesOutRecordDto;
import com.ruoyi.consumables.execl.ConsumablesInventoryExportData;
import com.ruoyi.consumables.mapper.ConsumablesInventoryMapper;
import com.ruoyi.consumables.pojo.ConsumablesInventory;
import com.ruoyi.consumables.service.ConsumablesInRecordService;
import com.ruoyi.consumables.service.ConsumablesInventoryService;
import com.ruoyi.consumables.service.ConsumablesOutRecordService;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.stock.word.WeighbridgeDocGenerator;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
 * <p>
 * åº“存表 æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-21 04:16:36
 */
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class ConsumablesInventoryServiceImpl extends ServiceImpl<ConsumablesInventoryMapper, ConsumablesInventory> implements ConsumablesInventoryService {
    private final ConsumablesInventoryMapper ConsumablesInventoryMapper;
    private final ConsumablesInRecordService ConsumablesInRecordService;
    private final ConsumablesOutRecordService ConsumablesOutRecordService;
    private final SalesLedgerProductMapper salesLedgerProductMapper;
    @Override
    public IPage<ConsumablesInventoryDto> pageConsumablesInventory(Page page, ConsumablesInventoryDto ConsumablesInventoryDto) {
        return ConsumablesInventoryMapper.pageConsumablesInventory(page, ConsumablesInventoryDto);
    }
    //入库调用
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addConsumablesInventory(ConsumablesInventoryDto consumablesInventoryDto) {
        //新增入库记录再添加库存
        ConsumablesInRecordDto consumablesInRecordDto = new ConsumablesInRecordDto();
        consumablesInRecordDto.setRecordId(consumablesInventoryDto.getRecordId());
        consumablesInRecordDto.setRecordType(consumablesInventoryDto.getRecordType());
        consumablesInRecordDto.setConsumablesInNum(consumablesInventoryDto.getNetWeight());
        consumablesInRecordDto.setWeighingDate(consumablesInventoryDto.getWeighingDate());
        consumablesInRecordDto.setNetWeight(consumablesInventoryDto.getNetWeight());
        consumablesInRecordDto.setGrossWeight(consumablesInventoryDto.getGrossWeight());
        consumablesInRecordDto.setTareWeight(consumablesInventoryDto.getTareWeight());
        consumablesInRecordDto.setLicensePlateNo(consumablesInventoryDto.getLicensePlateNo());
        consumablesInRecordDto.setWeighingOperator(consumablesInventoryDto.getWeighingOperator());
        consumablesInRecordDto.setProductModelId(consumablesInventoryDto.getProductModelId());
        consumablesInRecordDto.setProductId(consumablesInventoryDto.getProductId());
        consumablesInRecordDto.setType("0");
        ConsumablesInRecordService.add(consumablesInRecordDto);
        //再进行新增库存数量库存
        //先查询库存表中的产品是否存在,不存在新增,存在更新
        ConsumablesInventory oldConsumablesInventory = ConsumablesInventoryMapper.selectOne(new QueryWrapper<ConsumablesInventory>().lambda().eq(ConsumablesInventory::getProductModelId, consumablesInventoryDto.getProductModelId()));
        if (ObjectUtils.isEmpty(oldConsumablesInventory)) {
            ConsumablesInventory newConsumablesInventory = new ConsumablesInventory();
            newConsumablesInventory.setProductModelId(consumablesInventoryDto.getProductModelId());
            newConsumablesInventory.setQualitity(consumablesInventoryDto.getNetWeight());
            newConsumablesInventory.setVersion(1);
            newConsumablesInventory.setRemark(consumablesInventoryDto.getRemark());
            newConsumablesInventory.setLockedQuantity(consumablesInventoryDto.getLockedQuantity());
            newConsumablesInventory.setWarnNum(consumablesInventoryDto.getWarnNum());
            ConsumablesInventoryMapper.insert(newConsumablesInventory);
        } else {
            consumablesInventoryDto.setQualitity(consumablesInventoryDto.getNetWeight());
            ConsumablesInventoryMapper.updateAddConsumablesInventory(consumablesInventoryDto);
        }
        return true;
    }
    //出库调用
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean subtractConsumablesInventory(ConsumablesInventoryDto consumablesInventoryDto) {
        //  æ–°å¢žå‡ºåº“记录
        ConsumablesOutRecordDto consumablesOutRecordDto = new ConsumablesOutRecordDto();
        consumablesOutRecordDto.setRecordId(consumablesInventoryDto.getRecordId());
        consumablesOutRecordDto.setRecordType(consumablesInventoryDto.getRecordType());
        consumablesOutRecordDto.setWeighingDate(consumablesInventoryDto.getWeighingDate());
        consumablesOutRecordDto.setConsumablesOutNum(consumablesInventoryDto.getNetWeight());
        consumablesOutRecordDto.setNetWeight(consumablesInventoryDto.getNetWeight());
        consumablesOutRecordDto.setGrossWeight(consumablesInventoryDto.getGrossWeight());
        consumablesOutRecordDto.setTareWeight(consumablesInventoryDto.getTareWeight());
        consumablesOutRecordDto.setWeighingOperator(consumablesInventoryDto.getWeighingOperator());
        consumablesOutRecordDto.setProductModelId(consumablesInventoryDto.getProductModelId());
        consumablesOutRecordDto.setLicensePlateNo(consumablesInventoryDto.getLicensePlateNo());
        consumablesOutRecordDto.setProductId(consumablesInventoryDto.getProductId());
        consumablesOutRecordDto.setType("0");
        ConsumablesOutRecordService.add(consumablesOutRecordDto);
        ConsumablesInventory oldConsumablesInventory = ConsumablesInventoryMapper.selectOne(new QueryWrapper<ConsumablesInventory>().lambda().eq(ConsumablesInventory::getProductModelId, consumablesInventoryDto.getProductModelId()));
        if (ObjectUtils.isEmpty(oldConsumablesInventory)) {
            throw new RuntimeException("产品库存不存在");
        }
        BigDecimal lockedQty = oldConsumablesInventory.getLockedQuantity();
        if (lockedQty == null) {
            lockedQty = BigDecimal.ZERO;
        }
        if (consumablesInventoryDto.getQualitity().compareTo(oldConsumablesInventory.getQualitity().subtract(lockedQty)) > 0) {
            throw new RuntimeException("库存不足无法出库");
        }
        ConsumablesInventoryMapper.updateSubtractConsumablesInventory(consumablesInventoryDto);
        return true;
    }
    @Override
    public R importConsumablesInventory(MultipartFile file) {
        try {
            // æŸ¥è¯¢æ‰€æœ‰çš„产品
            List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectProduct();
            ExcelUtil<ConsumablesInventoryExportData> util = new ExcelUtil<ConsumablesInventoryExportData>(ConsumablesInventoryExportData.class);
            List<ConsumablesInventoryExportData> list = util.importExcel(file.getInputStream());
            // è®°å½•未找到匹配项的数据
            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())) {
                        ConsumablesInventoryDto ConsumablesInventoryDto = new ConsumablesInventoryDto();
                        ConsumablesInventoryDto.setRecordId(0L);
                        ConsumablesInventoryDto.setRecordType(StockInQualifiedRecordTypeEnum.CUSTOMIZATION_STOCK_IN.getCode());
                        ConsumablesInventoryDto.setQualitity(dto.getQualitity());
                        ConsumablesInventoryDto.setRemark(dto.getRemark());
                        ConsumablesInventoryDto.setWarnNum(dto.getWarnNum());
                        if (ObjectUtils.isNotEmpty(dto.getLockedQuantity()) && dto.getLockedQuantity().compareTo(dto.getQualitity()) > 0) {
                            throw new RuntimeException("冻结数量不能超过本次导入的库存数量");
                        }
                        ConsumablesInventoryDto.setLockedQuantity(dto.getLockedQuantity());
                        ConsumablesInventoryDto.setProductModelId(item.getProductModelId());
                        this.addConsumablesInventory(ConsumablesInventoryDto);
                        matched = true;
                        break; // æ‰¾åˆ°åŒ¹é…é¡¹åŽè·³å‡ºå¾ªçޝ
                    }
                }
                if (!matched) {
                    // è®°å½•未匹配的数据
                    String unmatchedInfo = String.format("产品名称:%s,规格型号:%s",
                            dto.getProductName(), dto.getModel());
                    unmatchedRecords.add(unmatchedInfo);
                }
            });
            // æž„建返回信息
            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.ok("导入成功");
    }
    @Override
    public void exportConsumablesInventory(HttpServletResponse response, ConsumablesInventoryDto ConsumablesInventoryDto) {
        List<ConsumablesInventoryExportData> list = ConsumablesInventoryMapper.listConsumablesInventoryExportData(ConsumablesInventoryDto);
        ExcelUtil<ConsumablesInventoryExportData> util = new ExcelUtil<>(ConsumablesInventoryExportData.class);
        util.exportExcel(response, list, "库存信息");
    }
    @Override
    public IPage<ConsumablesInRecordDto> consumablesInventoryPage(ConsumablesInventoryDto consumablesInventoryDto, Page page) {
        return ConsumablesInventoryMapper.ConsumablesInventoryPage(consumablesInventoryDto, page);
    }
    @Override
    public IPage<ConsumablesInventoryDto> consumablesInAndOutRecord(ConsumablesInventoryDto consumablesInventoryDto, Page page) {
        return ConsumablesInventoryMapper.ConsumablesInAndOutRecord(consumablesInventoryDto, page);
    }
    @Override
    public Boolean frozenConsumables(ConsumablesInventoryDto ConsumablesInventoryDto) {
        ConsumablesInventory ConsumablesInventory = ConsumablesInventoryMapper.selectById(ConsumablesInventoryDto.getId());
        if (ConsumablesInventory.getQualitity().compareTo(ConsumablesInventoryDto.getLockedQuantity()) < 0) {
            throw new RuntimeException("冻结数量不能超过库存数量");
        }
        if (ObjectUtils.isEmpty(ConsumablesInventory.getLockedQuantity())) {
            ConsumablesInventory.setLockedQuantity(ConsumablesInventoryDto.getLockedQuantity());
        } else {
            ConsumablesInventory.setLockedQuantity(ConsumablesInventory.getLockedQuantity().add(ConsumablesInventoryDto.getLockedQuantity()));
        }
        return this.updateById(ConsumablesInventory);
    }
    @Override
    public Boolean thawConsumables(ConsumablesInventoryDto ConsumablesInventoryDto) {
        ConsumablesInventory ConsumablesInventory = ConsumablesInventoryMapper.selectById(ConsumablesInventoryDto.getId());
        if (ConsumablesInventory.getLockedQuantity().compareTo(ConsumablesInventoryDto.getLockedQuantity()) < 0) {
            throw new RuntimeException("解冻数量不能超过冻结数量");
        }
        ConsumablesInventory.setLockedQuantity(ConsumablesInventory.getLockedQuantity().subtract(ConsumablesInventoryDto.getLockedQuantity()));
        return this.updateById(ConsumablesInventory);
    }
}
src/main/java/com/ruoyi/consumables/service/impl/ConsumablesOutRecordServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,116 @@
package com.ruoyi.consumables.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.common.enums.StockInUnQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.EnumUtil;
import com.ruoyi.common.utils.OrderUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.consumables.dto.ConsumablesInventoryDto;
import com.ruoyi.consumables.dto.ConsumablesOutRecordDto;
import com.ruoyi.consumables.dto.ConsumablesUnInventoryDto;
import com.ruoyi.consumables.execl.ConsumablesOutRecordExportData;
import com.ruoyi.consumables.mapper.ConsumablesInventoryMapper;
import com.ruoyi.consumables.mapper.ConsumablesOutRecordMapper;
import com.ruoyi.consumables.mapper.ConsumablesUnInventoryMapper;
import com.ruoyi.consumables.pojo.ConsumablesInRecord;
import com.ruoyi.consumables.pojo.ConsumablesInventory;
import com.ruoyi.consumables.pojo.ConsumablesOutRecord;
import com.ruoyi.consumables.pojo.ConsumablesUnInventory;
import com.ruoyi.consumables.service.ConsumablesOutRecordService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
 * <p>
 * å‡ºåº“记录表 æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-21 05:27:04
 */
@Service
@AllArgsConstructor
public class ConsumablesOutRecordServiceImpl extends ServiceImpl<ConsumablesOutRecordMapper, ConsumablesOutRecord> implements ConsumablesOutRecordService {
    private ConsumablesOutRecordMapper consumablesOutRecordMapper;
    private ConsumablesInventoryMapper consumablesInventoryMapper;
    private ConsumablesUnInventoryMapper consumablesUnInventoryMapper;
    @Override
    public IPage<ConsumablesOutRecordDto> listPage(Page page, ConsumablesOutRecordDto ConsumablesOutRecordDto) {
        return consumablesOutRecordMapper.listPage(page, ConsumablesOutRecordDto);
    }
    @Override
    public int add(ConsumablesOutRecordDto ConsumablesOutRecordDto) {
        String no = OrderUtils.countTodayByCreateTime(consumablesOutRecordMapper, "CK");
        ConsumablesOutRecordDto.setOutboundBatches(no);
        ConsumablesInRecord ConsumablesInRecord = new ConsumablesInRecord();
        BeanUtils.copyProperties(ConsumablesOutRecordDto, ConsumablesInRecord);
        return consumablesOutRecordMapper.insert(ConsumablesOutRecordDto);
    }
    @Override
    public int update(Long id, ConsumablesOutRecordDto ConsumablesOutRecordDto) {
        // åˆ¤æ–­å¯¹è±¡æ˜¯å¦å­˜åœ¨
        ConsumablesOutRecord ConsumablesOutRecord = consumablesOutRecordMapper.selectById(id);
        if (ConsumablesOutRecord == null){
            throw new BaseException("该出库记录不存在,无法更新!!!");
        }
        String[] ignoreProperties = {"id", "outbound_batches"};//排除id属性
        BeanUtils.copyProperties(ConsumablesOutRecordDto, ConsumablesOutRecord, ignoreProperties);
        return consumablesOutRecordMapper.updateById(ConsumablesOutRecord);
    }
    @Override
    public int batchDelete(List<Long> ids) {
        for (Long id : ids) {
            ConsumablesOutRecord consumablesOutRecord = consumablesOutRecordMapper.selectById(id);
            if (consumablesOutRecord.getType().equals("0")) {
                ConsumablesInventory consumablesInventory = consumablesInventoryMapper.selectOne(new LambdaQueryWrapper<ConsumablesInventory>().eq(ConsumablesInventory::getProductModelId, consumablesOutRecord.getProductModelId()));
                if (consumablesInventory == null) {
                    throw new BaseException("库存记录中没有对应的产品,无法删除!!!");
                }else {
                    ConsumablesInventoryDto consumablesInRecordDto = new ConsumablesInventoryDto();
                    consumablesInRecordDto.setProductModelId(consumablesInventory.getProductModelId());
                    consumablesInRecordDto.setQualitity(consumablesOutRecord.getConsumablesOutNum());
                    consumablesInventoryMapper.updateAddConsumablesInventory(consumablesInRecordDto);
                }
            }else if (consumablesOutRecord.getType().equals("1")) {
                ConsumablesUnInventory consumablesUnInventory = consumablesUnInventoryMapper.selectOne(new LambdaQueryWrapper<ConsumablesUnInventory>().eq(ConsumablesUnInventory::getProductModelId, consumablesOutRecord.getProductModelId()));
                if (consumablesUnInventory == null) {
                    throw new BaseException("库存记录中没有对应的产品,无法删除!!!");
                }else {
                    ConsumablesUnInventoryDto consumablesUnInventoryDto = new ConsumablesUnInventoryDto();
                    consumablesUnInventoryDto.setProductModelId(consumablesUnInventory.getProductModelId());
                    consumablesUnInventoryDto.setQualitity(consumablesOutRecord.getConsumablesOutNum());
                    consumablesUnInventoryMapper.updateAddConsumablesUnInventory(consumablesUnInventoryDto);
                }
            }
        }
        return consumablesOutRecordMapper.deleteBatchIds(ids);
    }
    @Override
    public void exportConsumablesOutRecord(HttpServletResponse response, ConsumablesOutRecordDto ConsumablesOutRecordDto) {
        List<ConsumablesOutRecordExportData> list = consumablesOutRecordMapper.listConsumablesOutRecordExportData(ConsumablesOutRecordDto);
        for (ConsumablesOutRecordExportData consumablesInRecordExportData : list) {
            if (consumablesInRecordExportData.getType().equals("0")) {
                consumablesInRecordExportData.setRecordType(EnumUtil.fromCode(StockOutQualifiedRecordTypeEnum.class, Integer.parseInt(consumablesInRecordExportData.getRecordType())).getValue());
            }else {
                consumablesInRecordExportData.setRecordType(EnumUtil.fromCode(StockInUnQualifiedRecordTypeEnum.class, Integer.parseInt(consumablesInRecordExportData.getRecordType())).getValue());
            }
        }
        ExcelUtil<ConsumablesOutRecordExportData> util = new ExcelUtil<>(ConsumablesOutRecordExportData.class);
        util.exportExcel(response,list, "出库记录信息");
    }
}
src/main/java/com/ruoyi/consumables/service/impl/ConsumablesUnInventoryServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,125 @@
package com.ruoyi.consumables.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.consumables.dto.ConsumablesInRecordDto;
import com.ruoyi.consumables.dto.ConsumablesInventoryDto;
import com.ruoyi.consumables.dto.ConsumablesOutRecordDto;
import com.ruoyi.consumables.dto.ConsumablesUnInventoryDto;
import com.ruoyi.consumables.execl.ConsumablesUnInventoryExportData;
import com.ruoyi.consumables.mapper.ConsumablesUnInventoryMapper;
import com.ruoyi.consumables.pojo.ConsumablesUnInventory;
import com.ruoyi.consumables.service.ConsumablesInRecordService;
import com.ruoyi.consumables.service.ConsumablesOutRecordService;
import com.ruoyi.consumables.service.ConsumablesUnInventoryService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
 * <p>
 * ä¸åˆæ ¼åº“存表 æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-22 10:17:45
 */
@Service
@AllArgsConstructor
public class ConsumablesUnInventoryServiceImpl extends ServiceImpl<ConsumablesUnInventoryMapper, ConsumablesUnInventory> implements ConsumablesUnInventoryService {
    private ConsumablesUnInventoryMapper ConsumablesUnInventoryMapper;
    private ConsumablesOutRecordService ConsumablesOutRecordService;
    private ConsumablesInRecordService ConsumablesInRecordService;
    @Override
    public IPage<ConsumablesUnInventoryDto> pageConsumablesUnInventory(Page page, ConsumablesUnInventoryDto ConsumablesUnInventoryDto) {
        return ConsumablesUnInventoryMapper.pageConsumablesUnInventory(page, ConsumablesUnInventoryDto);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer addConsumablesUnInventory(ConsumablesUnInventoryDto ConsumablesUnInventoryDto) {
        //新增入库记录再添加库存
        ConsumablesInRecordDto ConsumablesInRecordDto = new ConsumablesInRecordDto();
        ConsumablesInRecordDto.setRecordId(ConsumablesUnInventoryDto.getRecordId());
        ConsumablesInRecordDto.setRecordType(ConsumablesUnInventoryDto.getRecordType());
        ConsumablesInRecordDto.setConsumablesInNum(ConsumablesUnInventoryDto.getQualitity());
        ConsumablesInRecordDto.setProductModelId(ConsumablesUnInventoryDto.getProductModelId());
        ConsumablesInRecordDto.setType("1");
        ConsumablesInRecordService.add(ConsumablesInRecordDto);
        //再进行新增库存数量库存
        //先查询库存表中的产品是否存在,不存在新增,存在更新
        ConsumablesUnInventory oldConsumablesUnInventory = ConsumablesUnInventoryMapper.selectOne(new QueryWrapper<ConsumablesUnInventory>().lambda().eq(ConsumablesUnInventory::getProductModelId, ConsumablesUnInventoryDto.getProductModelId()));
        if (ObjectUtils.isEmpty(oldConsumablesUnInventory)) {
            ConsumablesUnInventory newConsumablesUnInventory = new ConsumablesUnInventory();
            newConsumablesUnInventory.setProductModelId(ConsumablesUnInventoryDto.getProductModelId());
            newConsumablesUnInventory.setQualitity(ConsumablesUnInventoryDto.getQualitity());
            newConsumablesUnInventory.setVersion(1);
            newConsumablesUnInventory.setRemark(ConsumablesUnInventoryDto.getRemark());
            ConsumablesUnInventoryMapper.insert(newConsumablesUnInventory);
        }else {
            ConsumablesUnInventoryMapper.updateAddConsumablesUnInventory(ConsumablesUnInventoryDto);
        }
        return 1;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer subtractConsumablesUnInventory(ConsumablesUnInventoryDto ConsumablesUnInventoryDto) {
        //  æ–°å¢žå‡ºåº“记录
        ConsumablesOutRecordDto ConsumablesOutRecordDto = new ConsumablesOutRecordDto();
        ConsumablesOutRecordDto.setRecordId(ConsumablesUnInventoryDto.getRecordId());
        ConsumablesOutRecordDto.setRecordType(ConsumablesUnInventoryDto.getRecordType());
        ConsumablesOutRecordDto.setConsumablesOutNum(ConsumablesUnInventoryDto.getQualitity());
        ConsumablesOutRecordDto.setProductModelId(ConsumablesUnInventoryDto.getProductModelId());
        ConsumablesOutRecordDto.setType("1");
        ConsumablesOutRecordService.add(ConsumablesOutRecordDto);
        ConsumablesUnInventory oldConsumablesInventory = ConsumablesUnInventoryMapper.selectOne(new QueryWrapper<ConsumablesUnInventory>().lambda().eq(ConsumablesUnInventory::getProductModelId, ConsumablesUnInventoryDto.getProductModelId()));
        if (ObjectUtils.isEmpty(oldConsumablesInventory)) {
            throw new RuntimeException("产品库存不存在");
        }else {
            ConsumablesUnInventoryMapper.updateSubtractConsumablesUnInventory(ConsumablesUnInventoryDto);
        }
        return 1;
    }
    @Override
    public void exportConsumablesUnInventory(HttpServletResponse response, ConsumablesUnInventoryDto ConsumablesUnInventoryDto) {
        List<ConsumablesUnInventoryExportData> list = ConsumablesUnInventoryMapper.listConsumablesInventoryExportData(ConsumablesUnInventoryDto);
        ExcelUtil<ConsumablesUnInventoryExportData> util = new ExcelUtil<>(ConsumablesUnInventoryExportData.class);
        util.exportExcel(response,list, "不合格库存信息");
    }
    @Override
    public Boolean frozenConsumables(ConsumablesInventoryDto ConsumablesInventoryDto) {
        ConsumablesUnInventory ConsumablesUnInventory = ConsumablesUnInventoryMapper.selectById(ConsumablesInventoryDto.getId());
        if (ConsumablesUnInventory.getQualitity().compareTo(ConsumablesInventoryDto.getLockedQuantity())<0) {
            throw new RuntimeException("冻结数量不能超过库存数量");
        }
        if (ObjectUtils.isEmpty(ConsumablesUnInventory.getLockedQuantity())) {
            ConsumablesUnInventory.setLockedQuantity(ConsumablesInventoryDto.getLockedQuantity());
        }else {
            ConsumablesUnInventory.setLockedQuantity(ConsumablesUnInventory.getLockedQuantity().add(ConsumablesInventoryDto.getLockedQuantity()));
        }
        return this.updateById(ConsumablesUnInventory);
    }
    @Override
    public Boolean thawConsumables(ConsumablesInventoryDto ConsumablesInventoryDto) {
        ConsumablesUnInventory ConsumablesUnInventory = ConsumablesUnInventoryMapper.selectById(ConsumablesInventoryDto.getId());
        if (ConsumablesUnInventory.getLockedQuantity().compareTo(ConsumablesInventoryDto.getLockedQuantity())<0) {
            throw new RuntimeException("解冻数量不能超过冻结数量");
        }
        ConsumablesUnInventory.setLockedQuantity(ConsumablesUnInventory.getLockedQuantity().subtract(ConsumablesInventoryDto.getLockedQuantity()));
        return this.updateById(ConsumablesUnInventory);
    }
}
src/main/java/com/ruoyi/device/controller/MaintenanceTaskController.java
@@ -30,7 +30,7 @@
    @GetMapping("/listPage")
    @ApiOperation(value = "设备保养定时任务列表")
    public AjaxResult listPage(Page page, MaintenanceTask maintenanceTask) {
    public AjaxResult listPage(Page<MaintenanceTask> page, MaintenanceTask maintenanceTask) {
        return maintenanceTaskService.listPage(page,maintenanceTask);
    }
src/main/java/com/ruoyi/device/dto/MaintenanceTaskDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
package com.ruoyi.device.dto;
import com.ruoyi.device.pojo.MaintenanceTask;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data
public class MaintenanceTaskDto extends MaintenanceTask {
    private static final long serialVersionUID = 1L;
    private List<Long> taskIds;
}
src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java
@@ -11,6 +11,7 @@
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
@@ -21,7 +22,7 @@
@Data
@ApiModel
@TableName("maintenance_task")
public class MaintenanceTask {
public class MaintenanceTask implements Serializable {
    private static final long serialVersionUID = 1L;
@@ -34,12 +35,15 @@
    @TableId(type = IdType.AUTO)
    private Long id;
    @ApiModelProperty(value = "设备名称")
    @ApiModelProperty(value = "任务名称")
    @Excel(name = "保养任务名称")
    private String taskName;
    @ApiModelProperty(value = "设备id")
    private Long taskId;
    @ApiModelProperty(value = "多个设备id")
    private String deviceIds;
    @ApiModelProperty(value = "频次")
    @Excel(name = "频次")
@@ -106,4 +110,6 @@
    @TableField(fill = com.baomidou.mybatisplus.annotation.FieldFill.INSERT)
    private Long tenantId;
    @TableField(exist = false)
    private String deviceName;
}
src/main/java/com/ruoyi/device/service/MaintenanceTaskService.java
@@ -12,7 +12,7 @@
 * @date : 2025/12/22 14:56
 */
public interface MaintenanceTaskService extends IService<MaintenanceTask> {
    AjaxResult listPage(Page page, MaintenanceTask maintenanceTask);
    AjaxResult listPage(Page<MaintenanceTask> page, MaintenanceTask maintenanceTask);
    AjaxResult add(MaintenanceTask maintenanceTask);
src/main/java/com/ruoyi/device/service/impl/DeviceLedgerServiceImpl.java
@@ -15,7 +15,6 @@
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysUserMapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -28,7 +27,6 @@
import java.util.List;
@Service
@AllArgsConstructor
@Slf4j
public class DeviceLedgerServiceImpl  extends ServiceImpl<DeviceLedgerMapper, DeviceLedger> implements IDeviceLedgerService {
src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskJob.java
@@ -1,5 +1,10 @@
package com.ruoyi.device.service.impl;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.device.mapper.DeviceLedgerMapper;
import com.ruoyi.device.pojo.DeviceLedger;
import com.ruoyi.device.pojo.DeviceMaintenance;
import com.ruoyi.device.pojo.MaintenanceTask;
import org.quartz.*;
@@ -13,9 +18,9 @@
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.YearMonth;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@Component
@DisallowConcurrentExecution // ç¦æ­¢å¹¶å‘执行同一个Job
@@ -27,6 +32,9 @@
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private DeviceLedgerMapper deviceLedgerMapper;
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
@@ -48,9 +56,8 @@
                throw new JobExecutionException("MaintenanceTaskJob找不到定时任务: " + taskId);
            }
            // 2. åˆ›å»ºå¹¶ä¿å­˜å·¡æ£€ä»»åŠ¡è®°å½• - è¿™å°±æ˜¯æ‚¨æä¾›çš„代码应该放的位置
            DeviceMaintenance deviceMaintenance = createInspectionTask(timingTask);
            deviceMaintenanceService.save(deviceMaintenance);
            // 2. åˆ›å»ºå¹¶ä¿å­˜å·¡æ£€ä»»åŠ¡è®°å½•
            createInspectionTask(timingTask);
            // 3. æ›´æ–°å®šæ—¶ä»»åŠ¡çš„æ‰§è¡Œæ—¶é—´
            if (!tasks.isEmpty()) {
@@ -83,25 +90,87 @@
        }
    }
    // è¿™å°±æ˜¯æ‚¨æä¾›çš„代码封装成的方法
    private DeviceMaintenance createInspectionTask(MaintenanceTask timingTask) {
    // å®žä½“类封装
    private void createInspectionTask(MaintenanceTask timingTask) {
        // 1. å‚数校验
        if (timingTask == null || StringUtils.isEmpty(timingTask.getDeviceIds())) {
            return;
        }
        // 2. è§£æžè®¾å¤‡ID列表
        List<Long> deviceIds;
        try {
            deviceIds = JSON.parseArray(timingTask.getDeviceIds(), Long.class);
        } catch (Exception e) {
            throw new RuntimeException("设备ID格式错误");
        }
        if (CollectionUtils.isEmpty(deviceIds)) {
            return;
        }
        // 3. æ‰¹é‡æŸ¥è¯¢è®¾å¤‡ä¿¡æ¯
        List<DeviceLedger> deviceLedgers = deviceLedgerMapper.selectBatchIds(deviceIds);
        if (CollectionUtils.isEmpty(deviceLedgers)) {
            return;
        }
        // 4. è½¬æ¢ä¸ºMap
        Map<Long, DeviceLedger> deviceLedgerMap = deviceLedgers.stream()
                .collect(Collectors.toMap(DeviceLedger::getId, Function.identity()));
        // 5. æ‰¹é‡æž„建巡检任务
        List<DeviceMaintenance> inspectionTaskList = new ArrayList<>();
        LocalDateTime now = LocalDateTime.now();
        Integer createUser = null;
        if (timingTask.getRegistrantId() != null) {
            try {
                createUser = Math.toIntExact(timingTask.getRegistrantId());
            } catch (ArithmeticException e) {
                throw new RuntimeException("用户ID超出有效范围");
            }
        }
        for (Long deviceId : deviceIds) {
            DeviceLedger deviceLedger = deviceLedgerMap.get(deviceId);
            if (deviceLedger == null) {
                continue;
            }
        DeviceMaintenance inspectionTask = new DeviceMaintenance();
        // å¤åˆ¶åŸºæœ¬å±žæ€§
        inspectionTask.setDeviceName(timingTask.getTaskName());
            // è®¾ç½®è®¾å¤‡ç›¸å…³ä¿¡æ¯
            inspectionTask.setDeviceLedgerId(deviceId);
            inspectionTask.setDeviceName(deviceLedger.getDeviceName());
            inspectionTask.setDeviceModel(deviceLedger.getDeviceModel());
            // è®¾ç½®ä»»åŠ¡ç›¸å…³ä¿¡æ¯
        inspectionTask.setMaintenanceTaskId(timingTask.getId());
        inspectionTask.setDeviceLedgerId(timingTask.getTaskId());
        inspectionTask.setMaintenancePlanTime(LocalDateTime.now());
            inspectionTask.setMaintenancePlanTime(now);
        inspectionTask.setFrequencyType(timingTask.getFrequencyType());
        inspectionTask.setFrequencyDetail(timingTask.getFrequencyDetail());
        inspectionTask.setTenantId(timingTask.getTenantId());
            // è®¾ç½®çŠ¶æ€å’Œæ—¶é—´
        inspectionTask.setStatus(0);
        inspectionTask.setDeviceModel(timingTask.getDeviceModel());
        inspectionTask.setCreateUser(Integer.parseInt(timingTask.getRegistrantId().toString()));
        inspectionTask.setUpdateTime(LocalDateTime.now());
        inspectionTask.setCreateTime(LocalDateTime.now());
        inspectionTask.setUpdateUser(Integer.parseInt(timingTask.getRegistrantId().toString()));
        return inspectionTask;
            inspectionTask.setCreateTime(now);
            inspectionTask.setUpdateTime(now);
            // è®¾ç½®ç”¨æˆ·ä¿¡æ¯
            inspectionTask.setTenantId(timingTask.getTenantId());
            inspectionTask.setCreateUser(createUser);
            inspectionTask.setUpdateUser(createUser);
            inspectionTaskList.add(inspectionTask);
        }
        if (!inspectionTaskList.isEmpty()) {
            try {
                deviceMaintenanceService.saveBatch(inspectionTaskList);
            } catch (Exception e) {
                throw new RuntimeException("创建巡检任务失败");
            }
        }
    }
src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskServiceImpl.java
@@ -1,9 +1,15 @@
package com.ruoyi.device.service.impl;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.device.mapper.DeviceLedgerMapper;
import com.ruoyi.device.mapper.MaintenanceTaskMapper;
import com.ruoyi.device.pojo.DeviceLedger;
import com.ruoyi.device.pojo.MaintenanceTask;
import com.ruoyi.device.service.MaintenanceTaskService;
import com.ruoyi.framework.web.domain.AjaxResult;
@@ -17,6 +23,7 @@
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
/**
 * @author :yys
@@ -38,36 +45,87 @@
    @Autowired
    private MaintenanceTaskScheduler maintenanceTaskScheduler;
    @Autowired
    private DeviceLedgerMapper deviceLedgerMapper;
    @Override
    public AjaxResult listPage(Page page, MaintenanceTask maintenanceTask) {
        Page<MaintenanceTask> taskPage = maintenanceTaskMapper.selectPage(page, null);
        // 2. å¦‚果没有数据,直接返回空分页
    public AjaxResult listPage(Page<MaintenanceTask> page, MaintenanceTask maintenanceTask) {
        // æŸ¥è¯¢
        LambdaQueryWrapper<MaintenanceTask> queryWrapper = new LambdaQueryWrapper<>();
        if (maintenanceTask.getTaskName() != null) {
            queryWrapper.like(MaintenanceTask::getTaskName, maintenanceTask.getTaskName());
        }
        Page<MaintenanceTask> taskPage = maintenanceTaskMapper.selectPage(page, queryWrapper);
        if (taskPage.getRecords().isEmpty()) {
            return AjaxResult.success(taskPage);
        }
        // 3. æ”¶é›†æ‰€æœ‰éœ€è¦æŸ¥è¯¢çš„用户ID
        //收集所有需要查询的ID
        Set<Long> userIds = new HashSet<>();
        Set<Long> allDeviceIds = new HashSet<>();
        //设备ID列表
        Map<Long, List<Long>> taskDeviceIdMap = new HashMap<>();
        // éåŽ†ä»»åŠ¡ï¼Œæ”¶é›†ç™»è®°äººID和设备ID
        for (MaintenanceTask task : taskPage.getRecords()) {
        // æ”¶é›†ç™»è®°äººID
        taskPage.getRecords().forEach(task -> {
            if (task.getRegistrantId() != null) {
                userIds.add(task.getRegistrantId());
            }
        });
            // æ”¶é›†è®¾å¤‡ID并解析
            if (StringUtils.isNotEmpty(task.getDeviceIds())) {
                try {
                    List<Long> deviceIds = JSON.parseArray(task.getDeviceIds(), Long.class);
                    if (CollectionUtils.isNotEmpty(deviceIds)) {
                        allDeviceIds.addAll(deviceIds);
                        taskDeviceIdMap.put(task.getId(), deviceIds);
                    }
                } catch (Exception e) {
                    log.error("解析设备ID列表失败: taskId={}, deviceIds={}", task.getId(), task.getDeviceIds(), e);
                }
            }
        }
        // 4. æ‰¹é‡æŸ¥è¯¢ç”¨æˆ·ä¿¡æ¯
        Map<Long, String> userNickNameMap = new HashMap<>();
        if (!userIds.isEmpty()) {
            List<SysUser> users = sysUserMapper.selectUserByIds((new ArrayList<>(userIds)));
            List<SysUser> users = sysUserMapper.selectUserByIds(new ArrayList<>(userIds));
            if (CollectionUtils.isNotEmpty(users)) {
            users.forEach(user -> userNickNameMap.put(user.getUserId(), user.getNickName()));
        }
        taskPage.getRecords().forEach(task -> {
        }
        // 5. æ‰¹é‡æŸ¥è¯¢è®¾å¤‡ä¿¡æ¯
        Map<Long, String> deviceNameMap = new HashMap<>();
        if (!allDeviceIds.isEmpty()) {
            List<DeviceLedger> devices = deviceLedgerMapper.selectBatchIds(new ArrayList<>(allDeviceIds));
            if (CollectionUtils.isNotEmpty(devices)) {
                devices.forEach(device -> deviceNameMap.put(device.getId(), device.getDeviceName()));
            }
        }
        // 6. è®¾ç½®è¿”回结果
        for (MaintenanceTask task : taskPage.getRecords()) {
            // è®¾ç½®ç™»è®°äººæ˜µç§°
            if (task.getRegistrantId() != null) {
                task.setRegistrant(userNickNameMap.getOrDefault(task.getRegistrantId(), "未知用户"));
            }
        });
            // è®¾ç½®è®¾å¤‡åç§°
            List<Long> deviceIds = taskDeviceIdMap.get(task.getId());
            if (CollectionUtils.isNotEmpty(deviceIds)) {
                List<String> deviceNames = deviceIds.stream()
                        .map(id -> deviceNameMap.getOrDefault(id, "未知设备"))
                        .collect(Collectors.toList());
                task.setDeviceName(String.join(", ", deviceNames));
            } else {
                task.setDeviceName("无设备");
            }
        }
        return AjaxResult.success(taskPage);
    }
src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java
@@ -56,4 +56,16 @@
    @ApiModelProperty("车牌号")
    private String licensePlateNo;
    @ApiModelProperty("毛重")
    private BigDecimal grossWeight;
    @ApiModelProperty("皮重")
    private BigDecimal tareWeight;
    @ApiModelProperty("过磅员")
    private String weighingOperator;
    @ApiModelProperty("磅单文件路径")
    private String weighbridgeDocPath;
}
src/main/java/com/ruoyi/stock/pojo/StockInRecord.java
@@ -70,4 +70,33 @@
    @ApiModelProperty("净重")
    private BigDecimal netWeight;
    /**
     * æ¯›é‡ï¼ˆå•位:吨)
     */
    @ApiModelProperty("毛重")
    private BigDecimal grossWeight;
    /**
     * çš®é‡ï¼ˆå•位:吨)
     */
    @ApiModelProperty("皮重")
    private BigDecimal tareWeight;
    /**
     * è½¦ç‰Œå·
     */
    @ApiModelProperty("车牌号")
    private String licensePlateNo;
    /**
     * è¿‡ç£…员
     */
    @ApiModelProperty("过磅员")
    private String weighingOperator;
    @ApiModelProperty("磅单文件路径")
    private String weighbridgeDocPath;
    @ApiModelProperty("产品id")
    private Long productId;
}
src/main/java/com/ruoyi/stock/pojo/StockInventory.java
@@ -63,4 +63,7 @@
    @ApiModelProperty("备注")
    private String remark;
    @ApiModelProperty("产品id")
    private Long productId;
}
src/main/java/com/ruoyi/stock/pojo/StockOutRecord.java
@@ -82,4 +82,16 @@
    @ApiModelProperty("车牌号")
    private String licensePlateNo;
    @ApiModelProperty("毛重")
    private BigDecimal grossWeight;
    @ApiModelProperty("皮重")
    private BigDecimal tareWeight;
    @ApiModelProperty("过磅员")
    private String weighingOperator;
    @ApiModelProperty("产品id")
    private Long productId;
}
src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java
@@ -19,7 +19,9 @@
import com.ruoyi.stock.service.StockInRecordService;
import com.ruoyi.stock.service.StockInventoryService;
import com.ruoyi.stock.service.StockOutRecordService;
import lombok.AllArgsConstructor;
import com.ruoyi.stock.word.WeighbridgeDocGenerator;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
@@ -38,13 +40,15 @@
 * @since 2026-01-21 04:16:36
 */
@Service
@AllArgsConstructor
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class StockInventoryServiceImpl extends ServiceImpl<StockInventoryMapper, StockInventory> implements StockInventoryService {
    private  StockInventoryMapper stockInventoryMapper;
    private StockInRecordService stockInRecordService;
    private StockOutRecordService stockOutRecordService;
    private SalesLedgerProductMapper salesLedgerProductMapper;
    private final StockInventoryMapper stockInventoryMapper;
    private final StockInRecordService stockInRecordService;
    private final StockOutRecordService stockOutRecordService;
    private final SalesLedgerProductMapper salesLedgerProductMapper;
    private final WeighbridgeDocGenerator weighbridgeDocGenerator;
    @Override
    public IPage<StockInventoryDto> pagestockInventory(Page page, StockInventoryDto stockInventoryDto) {
        return stockInventoryMapper.pagestockInventory(page, stockInventoryDto);
@@ -58,11 +62,19 @@
        StockInRecordDto stockInRecordDto = new StockInRecordDto();
        stockInRecordDto.setRecordId(stockInventoryDto.getRecordId());
        stockInRecordDto.setRecordType(stockInventoryDto.getRecordType());
        stockInRecordDto.setStockInNum(stockInventoryDto.getQualitity());
        stockInRecordDto.setStockInNum(stockInventoryDto.getNetWeight());
        stockInRecordDto.setWeighingDate(stockInventoryDto.getWeighingDate());
        stockInRecordDto.setNetWeight(stockInventoryDto.getNetWeight());
        stockInRecordDto.setGrossWeight(stockInventoryDto.getGrossWeight());
        stockInRecordDto.setTareWeight(stockInventoryDto.getTareWeight());
        stockInRecordDto.setLicensePlateNo(stockInventoryDto.getLicensePlateNo());
        stockInRecordDto.setWeighingOperator(stockInventoryDto.getWeighingOperator());
        stockInRecordDto.setProductModelId(stockInventoryDto.getProductModelId());
        stockInRecordDto.setProductId(stockInventoryDto.getProductId());
        stockInRecordDto.setType("0");
        //生成磅单
        String absoluteDocPath = weighbridgeDocGenerator.generateWeighbridgeDoc(stockInRecordDto);
        stockInRecordDto.setWeighbridgeDocPath(absoluteDocPath);
        stockInRecordService.add(stockInRecordDto);
        //再进行新增库存数量库存
        //先查询库存表中的产品是否存在,不存在新增,存在更新
@@ -70,13 +82,14 @@
        if (ObjectUtils.isEmpty(oldStockInventory)) {
            StockInventory newStockInventory = new StockInventory();
            newStockInventory.setProductModelId(stockInventoryDto.getProductModelId());
            newStockInventory.setQualitity(stockInventoryDto.getQualitity());
            newStockInventory.setQualitity(stockInventoryDto.getNetWeight());
            newStockInventory.setVersion(1);
            newStockInventory.setRemark(stockInventoryDto.getRemark());
            newStockInventory.setLockedQuantity(stockInventoryDto.getLockedQuantity());
            newStockInventory.setWarnNum(stockInventoryDto.getWarnNum());
            stockInventoryMapper.insert(newStockInventory);
        }else {
            stockInventoryDto.setQualitity(stockInventoryDto.getNetWeight());
             stockInventoryMapper.updateAddStockInventory(stockInventoryDto);
        }
        return true;
@@ -91,10 +104,14 @@
        stockOutRecordDto.setRecordId(stockInventoryDto.getRecordId());
        stockOutRecordDto.setRecordType(stockInventoryDto.getRecordType());
        stockInventoryDto.setWeighingDate(stockInventoryDto.getWeighingDate());
        stockOutRecordDto.setStockOutNum(stockInventoryDto.getQualitity());
        stockOutRecordDto.setStockOutNum(stockInventoryDto.getNetWeight());
        stockOutRecordDto.setNetWeight(stockInventoryDto.getNetWeight());
        stockOutRecordDto.setGrossWeight(stockInventoryDto.getGrossWeight());
        stockOutRecordDto.setTareWeight(stockInventoryDto.getTareWeight());
        stockOutRecordDto.setWeighingOperator(stockInventoryDto.getWeighingOperator());
        stockOutRecordDto.setProductModelId(stockInventoryDto.getProductModelId());
        stockOutRecordDto.setLicensePlateNo(stockInventoryDto.getLicensePlateNo());
        stockOutRecordDto.setProductId(stockInventoryDto.getProductId());
        stockOutRecordDto.setType("0");
        stockOutRecordService.add(stockOutRecordDto);
        StockInventory oldStockInventory = stockInventoryMapper.selectOne(new QueryWrapper<StockInventory>().lambda().eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId()));
src/main/java/com/ruoyi/stock/word/ChineseNumberUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,101 @@
package com.ruoyi.stock.word;
import java.math.BigDecimal;
/**
 * é‡‘额数字转大写工具类
 */
public class ChineseNumberUtil {
    private static final String[] CN_UPPER_NUMBER = {"零", "壹", "è´°", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
    private static final String[] CN_UPPER_UNIT = {"", "拾", "ä½°", "仟", "万", "拾", "ä½°", "仟", "亿", "拾", "ä½°", "仟"};
    private static final String CN_DOLLAR = "";
    private static final String CN_TEN_CENT = "点";
    private static final String CN_CENT = "";
    private static final String CN_INTEGER = "整";
    /**
     * å°†æ•°å­—转换为大写金额
     * @param number æ•°å­—(单位:吨)
     * @return å¤§å†™é‡‘额字符串
     */
    public static String numberToChinese(BigDecimal number) {
        if (number == null) {
            return "零";
        }
        // å¤„理负数
        boolean isNegative = false;
        if (number.compareTo(BigDecimal.ZERO) < 0) {
            isNegative = true;
            number = number.abs();
        }
        StringBuilder result = new StringBuilder();
        // åˆ†ç¦»æ•´æ•°å’Œå°æ•°éƒ¨åˆ†
        String[] parts = number.toString().split("\\.");
        String integerPart = parts[0];
        String decimalPart = parts.length > 1 ? parts[1] : "";
        // è½¬æ¢æ•´æ•°éƒ¨åˆ†
        if (!"0".equals(integerPart)) {
            result.append(convertIntegerPart(integerPart));
        } else {
            result.append("零");
        }
        // è½¬æ¢å°æ•°éƒ¨åˆ†
        if (decimalPart.length() > 0 && !"00".equals(decimalPart) && !"0".equals(decimalPart)) {
            result.append(CN_TEN_CENT);
            char[] decimals = decimalPart.toCharArray();
            for (int i = 0; i < decimals.length; i++) {
                if (decimals[i] != '0') {
                    result.append(CN_UPPER_NUMBER[Integer.parseInt(String.valueOf(decimals[i]))]);
                } else {
                    if (i < decimals.length - 1 && decimals[i + 1] != '0') {
                        result.append(CN_UPPER_NUMBER[0]);
                    }
                }
            }
        }
        return isNegative ? "负" + result.toString() : result.toString();
    }
    /**
     * è½¬æ¢æ•´æ•°éƒ¨åˆ†
     */
    private static String convertIntegerPart(String integerPart) {
        StringBuilder result = new StringBuilder();
        int length = integerPart.length();
        for (int i = 0; i < length; i++) {
            int digit = Integer.parseInt(String.valueOf(integerPart.charAt(i)));
            int unitIndex = length - i - 1;
            if (digit != 0) {
                result.append(CN_UPPER_NUMBER[digit]).append(CN_UPPER_UNIT[unitIndex]);
            } else {
                // å¤„理连续的零
                if (i > 0 && integerPart.charAt(i - 1) != '0') {
                    result.append(CN_UPPER_NUMBER[0]);
                }
                // å¤„理万位和亿位
                if (unitIndex == 4 || unitIndex == 8) {
                    if (result.length() > 0 && !result.toString().endsWith(CN_UPPER_NUMBER[0])) {
                        result.append(CN_UPPER_UNIT[unitIndex]);
                    }
                }
            }
        }
        String resultStr = result.toString();
        // åŽ»é™¤æœ«å°¾çš„é›¶
        while (resultStr.endsWith(CN_UPPER_NUMBER[0])) {
            resultStr = resultStr.substring(0, resultStr.length() - 1);
        }
        return resultStr;
    }
}
src/main/java/com/ruoyi/stock/word/WeighbridgeDocGenerator.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,268 @@
package com.ruoyi.stock.word;
import com.ruoyi.basic.pojo.Product;
import com.ruoyi.basic.service.IProductService;
import com.ruoyi.stock.dto.StockInRecordDto;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.xwpf.usermodel.XWPFTable.XWPFBorderType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
 * ç£…单Word文档生成器
 */
@Component
public class WeighbridgeDocGenerator {
    @Value("${file.upload-dir}")
    private String uploadDir;
    @Autowired
    private IProductService productService;
    /**
     * ç”Ÿæˆç£…单Word文档
     * @param dto å…¥åº“记录DTO
     * @return æ–‡ä»¶ä¿å­˜çš„绝对路径,生成失败返回null
     */
    public String generateWeighbridgeDoc(StockInRecordDto dto) {
        // å‚数校验
        if (dto == null) {
            return null;
        }
        FileOutputStream out = null;
        XWPFDocument document = null;
        try {
            // åˆ›å»ºæ–°æ–‡æ¡£
            document = new XWPFDocument();
            // æž„建文档内容
            buildDocumentContent(document, dto);
            // æž„建文件保存路径(绝对路径)
            String absolutePath = buildAbsoluteFilePath(dto);
            File file = new File(absolutePath);
            // ç¡®ä¿ç›®å½•存在
            file.getParentFile().mkdirs();
            // å†™å…¥æ–‡ä»¶
            out = new FileOutputStream(file);
            document.write(out);
            out.flush();
            // è¿”回绝对路径(用于数据库存储)
            return absolutePath;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            // å…³é—­èµ„源
            try {
                if (out != null) {
                    out.close();
                }
                if (document != null) {
                    document.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * æž„建文档内容
     */
    private void buildDocumentContent(XWPFDocument document, StockInRecordDto dto) {
        // 1. æ·»åŠ æ ‡é¢˜ "磅码单" - ä½¿ç”¨é»‘体
        XWPFParagraph titlePara = document.createParagraph();
        titlePara.setAlignment(ParagraphAlignment.CENTER);
        titlePara.setSpacingAfter(200);
        XWPFRun titleRun = titlePara.createRun();
        titleRun.setText("磅码单");
        titleRun.setBold(true);
        titleRun.setFontSize(28);
        titleRun.setFontFamily("黑体");
        // 2. ç©ºä¸€è¡Œ
        document.createParagraph();
        // 3. å¤´éƒ¨ä¿¡æ¯ï¼ˆå¹´æœˆæ—¥å’Œè®¡é‡å•位合并在一行)- ä½¿ç”¨å®‹ä½“
        XWPFParagraph headerPara = document.createParagraph();
        headerPara.setSpacingAfter(200);
        XWPFRun headerRun = headerPara.createRun();
        // æ ¼å¼åŒ–日期为 yyyy-MM-dd
        String weighDate = "";
        if (dto.getWeighingDate() != null) {
            try {
                // å‡è®¾ weighingDate æ˜¯ LocalDateTime ç±»åž‹
                weighDate = dto.getWeighingDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            } catch (Exception e) {
                // å¦‚果是字符串类型,尝试转换
                weighDate = dto.getWeighingDate().toString();
                if (weighDate.length() > 10) {
                    weighDate = weighDate.substring(0, 10);
                }
            }
        }
        headerRun.setText("年月日:" + weighDate + "    è®¡é‡å•位:(吨)");
        headerRun.setFontSize(12);
        headerRun.setFontFamily("宋体");
        // 4. åˆ›å»ºä¸»è¡¨æ ¼ - 4行6列(表头1行+数据1行+合计1行+空行1行)
        XWPFTable table = document.createTable(4, 6);
        // è®¾ç½®è¡¨æ ¼å®½åº¦
        table.setWidth("100%");
        // è®¾ç½®è¡¨æ ¼è¾¹æ¡†åŠ ç²—ï¼ˆè¾¹æ¡†å®½åº¦è®¾ä¸º2)
        table.setInsideHBorder(XWPFBorderType.SINGLE, 2, 0, "000000");
        table.setInsideVBorder(XWPFBorderType.SINGLE, 2, 0, "000000");
        table.setTopBorder(XWPFBorderType.SINGLE, 2, 0, "000000");
        table.setBottomBorder(XWPFBorderType.SINGLE, 2, 0, "000000");
        table.setLeftBorder(XWPFBorderType.SINGLE, 2, 0, "000000");
        table.setRightBorder(XWPFBorderType.SINGLE, 2, 0, "000000");
        // è®¾ç½®è¡Œé«˜
        table.getRow(0).setHeight(400);
        table.getRow(1).setHeight(400);
        table.getRow(2).setHeight(400);
        table.getRow(3).setHeight(400);
        // è®¾ç½®è¡¨å¤´ - ä½¿ç”¨é»‘体加粗
        String[] headers = {"车号", "品名", "毛重", "皮重", "净重", "备注"};
        XWPFTableRow headerRow = table.getRow(0);
        for (int i = 0; i < headers.length; i++) {
            XWPFTableCell cell = headerRow.getCell(i);
            cell.setText(headers[i]);
            cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
            XWPFParagraph cellPara = cell.getParagraphs().get(0);
            cellPara.setAlignment(ParagraphAlignment.CENTER);
            XWPFRun cellRun = cellPara.getRuns().get(0);
            cellRun.setBold(true);
            cellRun.setFontSize(12);
            cellRun.setFontFamily("黑体");
        }
        // è®¾ç½®æ•°æ®è¡Œ - ä½¿ç”¨å®‹ä½“
        XWPFTableRow dataRow = table.getRow(1);
        String netWeight = dto.getNetWeight() != null ? dto.getNetWeight().toString() : "";
        String grossWeight = dto.getGrossWeight() != null ? dto.getGrossWeight().toString() : "";
        String tareWeight = dto.getTareWeight() != null ? dto.getTareWeight().toString() : "";
        String[] data = {
                dto.getLicensePlateNo() != null ? dto.getLicensePlateNo() : "",
                getProductModelName(dto.getProductId()),
                grossWeight + "t",
                tareWeight + "t",
                netWeight + "t",
                dto.getRemark() != null ? dto.getRemark() : ""
        };
        for (int i = 0; i < data.length; i++) {
            XWPFTableCell cell = dataRow.getCell(i);
            cell.setText(data[i]);
            cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
            XWPFParagraph cellPara = cell.getParagraphs().get(0);
            cellPara.setAlignment(ParagraphAlignment.CENTER);
            XWPFRun cellRun = cellPara.getRuns().get(0);
            cellRun.setFontSize(12);
            cellRun.setFontFamily("宋体");
        }
        // åˆè®¡è¡Œ - ç¬¬3行
        XWPFTableRow totalRow = table.getRow(2);
        // ç¬¬1列显示"合计(大写)"
        XWPFTableCell totalLabelCell = totalRow.getCell(0);
        totalLabelCell.setText("合计(大写)");
        totalLabelCell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
        XWPFParagraph totalLabelPara = totalLabelCell.getParagraphs().get(0);
        totalLabelPara.setAlignment(ParagraphAlignment.CENTER);
        XWPFRun totalLabelRun = totalLabelPara.getRuns().get(0);
        totalLabelRun.setBold(true);
        totalLabelRun.setFontSize(12);
        totalLabelRun.setFontFamily("宋体");
        XWPFTableCell contentCell = totalRow.getCell(1);
        String netWeightChinese = ChineseNumberUtil.numberToChinese(
                dto.getNetWeight() != null ? dto.getNetWeight() : BigDecimal.ZERO
        );
        contentCell.setText(netWeightChinese + "吨");
        contentCell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
        XWPFParagraph contentPara = contentCell.getParagraphs().get(0);
        contentPara.setAlignment(ParagraphAlignment.LEFT);
        XWPFRun contentRun = contentPara.getRuns().get(0);
        contentRun.setFontSize(12);
        contentRun.setFontFamily("宋体");
        // åˆå¹¶ç¬¬3-6列到第2列
        for (int i = 2; i < 6; i++) {
            XWPFTableCell cell = totalRow.getCell(i);
            // è®¾ç½®è¿™äº›å•元格为合并状态(继承自第2列)
            cell.getCTTc().addNewTcPr().addNewHMerge().setVal(org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge.CONTINUE);
        }
        // 6. åˆ›å»ºè¿‡ç£…员行(单独一行,左对齐)
        XWPFParagraph operatorPara = document.createParagraph();
        operatorPara.setSpacingAfter(100);
        operatorPara.setAlignment(ParagraphAlignment.LEFT);
        XWPFRun operatorRun = operatorPara.createRun();
        String operator = dto.getWeighingOperator() != null ? dto.getWeighingOperator() : "";
        operatorRun.setText("过磅员:" + operator);
        operatorRun.setFontSize(8);
        operatorRun.setFontFamily("宋体");
    }
    /**
     * æž„建文件保存的绝对路径
     */
    private String buildAbsoluteFilePath(StockInRecordDto dto) {
        LocalDateTime now = LocalDateTime.now();
        String year = String.valueOf(now.getYear());
        String month = String.format("%02d", now.getMonthValue());
        String day = String.format("%02d", now.getDayOfMonth());
        // æ–‡ä»¶åæ ¼å¼ï¼šç£…单_车牌号_年月日时分秒.docx
        String fileName = String.format("磅单_%s_%s.docx",
                dto.getLicensePlateNo() != null ? dto.getLicensePlateNo() : "未知车牌",
                now.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
        return uploadDir + File.separator + year + File.separator + month + File.separator + day + File.separator + fileName;
    }
    /**
     * èŽ·å–äº§å“åž‹å·åç§°
     */
    private String getProductModelName(Long productModelId) {
        if (productModelId == null) {
            return "未知产品";
        }
        try {
            Product product = productService.getById(productModelId);
            return product != null ? product.getProductName() : "未知产品";
        } catch (Exception e) {
            e.printStackTrace();
            return "未知产品";
        }
    }
}
src/main/resources/mapper/consumables/ConsumablesInRecordMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,59 @@
<?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.consumables.mapper.ConsumablesInRecordMapper">
    <select id="listPage" resultType="com.ruoyi.consumables.dto.ConsumablesInRecordDto">
        SELECT
        sir.*,
        p.product_name as product_name,
        pm.model,
        pm.unit,
        u.nick_name as createBy
        FROM consumables_in_record as sir
        LEFT JOIN product_model as pm on sir.product_model_id = pm.id
        LEFT JOIN product as p on pm.product_id = p.id
        LEFT JOIN sys_user as u on sir.create_user = u.user_id
        <where>
            <if test="params.timeStr != null and params.timeStr != ''">
                and sir.create_time like concat('%',#{params.timeStr},'%')
            </if>
            <if test="params.productName != null and params.productName != ''">
                and p.product_name like concat('%',#{params.productName},'%')
            </if>
            <if test="params.type != null and params.type != ''">
                and sir.type = #{params.type}
            </if>
            <if test="params.recordType != null and params.recordType != ''">
                and sir.record_type = #{params.recordType}
            </if>
        </where>
        order by sir.id desc
    </select>
    <select id="listConsumablesInRecordExportData" resultType="com.ruoyi.consumables.execl.ConsumablesInRecordExportData">
        SELECT
        sir.*,
        p.product_name as product_name,
        pm.model,
        pm.unit,
        u.nick_name as createBy
        FROM consumables_in_record as sir
        LEFT JOIN product_model as pm on sir.product_model_id = pm.id
        LEFT JOIN product as p on pm.product_id = p.id
        LEFT JOIN sys_user as u on sir.create_user = u.user_id
        <where>
            <if test="params.timeStr != null and params.timeStr != ''">
                and sir.create_time like concat('%',#{params.timeStr},'%')
            </if>
            <if test="params.productName != null and params.productName != ''">
                and p.product_name like concat('%',#{params.productName},'%')
            </if>
            <if test="params.type != null and params.type != ''">
                and sir.type = #{params.type}
            </if>
            <if test="params.recordType != null and params.recordType != ''">
                and sir.record_type = #{params.recordType}
            </if>
        </where>
        order by sir.id desc
    </select>
</mapper>
src/main/resources/mapper/consumables/ConsumablesInventoryMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,307 @@
<?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.consumables.mapper.ConsumablesInventoryMapper">
    <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.consumables.pojo.ConsumablesInventory">
        <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="updateAddConsumablesInventory">
        update Consumables_inventory
        <set>
            <if test="ew.qualitity != null">
                qualitity = qualitity + #{ew.qualitity},
            </if>
            <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>
        where product_model_id = #{ew.productModelId}
    </update>
    <update id="updateSubtractConsumablesInventory">
        update Consumables_inventory
        <set>
            <if test="ew.netWeight != null">
                qualitity = qualitity - #{ew.netWeight},
            </if>
            <if test="ew.version != null">
                version = version + 1,
            </if>
            <if test="ew.remark != null and ew.remark !=''">
                remark = #{ew.remark},
            </if>
            update_time = now()
        </set>
        where product_model_id = #{ew.productModelId} and qualitity >= #{ew.qualitity}
    </update>
    <select id="pageConsumablesInventory" resultType="com.ruoyi.consumables.dto.ConsumablesInventoryDto">
        select
        si.id,
        -- å½“前净重 = å…¥åº“净重 - å‡ºåº“净重
        (COALESCE(sir.total_net_weight,0) - COALESCE(sor.total_net_weight,0)) as net_weight,
        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,
        p1.product_name as parent_name,
        p1.id as parent_id
        from Consumables_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 p1 on p.parent_id = p1.id
        -- å…¥åº“净重
        left join (
        select
        product_model_id,
        sum(net_weight) as total_net_weight
        from Consumables_in_record
        group by product_model_id
        ) sir on si.product_model_id = sir.product_model_id
        -- å‡ºåº“净重
        left join (
        select
        product_model_id,
        sum(net_weight) as total_net_weight
        from Consumables_out_record
        group by product_model_id
        ) sor on si.product_model_id = sor.product_model_id
        <where>
            1=1
            <if test="ew.parentId != null and ew.parentId !=''">
                and p.parent_id = #{ew.parentId}
            </if>
            <if test="ew.productName != null and ew.productName !=''">
                and p.product_name like concat('%',#{ew.productName},'%')
            </if>
        </where>
    </select>
    <select id="listConsumablesInventoryExportData" resultType="com.ruoyi.consumables.execl.ConsumablesInventoryExportData">
        select si.qualitity,
        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 Consumables_inventory si
        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},'%')
        </if>
    </select>
    <select id="ConsumablesInventoryPage" resultType="com.ruoyi.consumables.dto.ConsumablesInRecordDto">
        select
        sir.*,
        si.qualitity as current_Consumables,
        pm.model,
        pm.unit,
        p.product_name,
        su.nick_name as create_by,
        -- å½“前净重 = å…¥åº“净重 - å‡ºåº“净重
        IFNULL(inWeight.total_in_weight,0) - IFNULL(outWeight.total_out_weight,0) as current_weight
        from Consumables_in_record sir
        left join Consumables_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
        left join sys_user su
        on sir.create_user = su.user_id
        -- å…¥åº“净重统计
        left join (
        select
        product_model_id,
        sum(net_weight) as total_in_weight
        from Consumables_in_record
        group by product_model_id
        ) inWeight
        on sir.product_model_id = inWeight.product_model_id
        -- å‡ºåº“净重统计
        left join (
        select
        product_model_id,
        sum(net_weight) as total_out_weight
        from Consumables_out_record
        group by product_model_id
        ) outWeight
        on sir.product_model_id = outWeight.product_model_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="ConsumablesInAndOutRecord" resultType="com.ruoyi.consumables.dto.ConsumablesInventoryDto">
        SELECT
        pm.model,
        pm.unit,
        p.product_name,
        MAX(current_inventory) as current_Consumables,
        SUM(CASE WHEN record_type = 'in' THEN amount ELSE 0 END) as total_Consumables_in,
        SUM(CASE WHEN record_type = 'out' THEN amount ELSE 0 END) as total_Consumables_out
        FROM (
        SELECT
        product_model_id,
        SUM(qualitity) as current_inventory,
        0 as amount,
        '' as record_type
        FROM Consumables_inventory
        GROUP BY product_model_id
        UNION ALL
        SELECT
        product_model_id,
        0 as current_inventory,
        SUM(Consumables_in_num) as amount,
        'in' as record_type
        FROM Consumables_in_record
        <where>
            type = 0
            <if test="ew.startMonth != null">
                and Consumables_in_record.create_time &gt;= #{ew.startMonth}
            </if>
            <if test="ew.endMonth != null">
                and Consumables_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(Consumables_out_num) as amount,
        'out' as record_type
        FROM Consumables_out_record
        <where>
            type = 0
            <if test="ew.startMonth != null">
                and Consumables_out_record.create_time &gt;= #{ew.startMonth}
            </if>
            <if test="ew.endMonth != null">
                and Consumables_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 ifnull(sum(qualitity), 0)
        from consumables_inventory
    </select>
    <select id="selectTotalByDate" resultType="java.math.BigDecimal">
        select IFNULL(sum(qualitity), 0)
        from consumables_inventory
        where create_time &gt;= #{now}
          and create_time &lt; DATE_ADD(#{now}, INTERVAL 1 DAY)
    </select>
    <select id="selectStorageProductCountByDate" resultType="int">
        SELECT SUM(total_count)
        FROM (SELECT COUNT(*) as total_count
              FROM consumables_inventory
              WHERE create_time &gt;= #{startDate}
                AND create_time &lt;= #{endDate}
              UNION ALL
              SELECT COUNT(*) as total_count
              FROM consumables_uninventory
              WHERE create_time &gt;= #{startDate}
                AND create_time &lt;= #{endDate}) AS combined_counts
    </select>
    <select id="selectDailyConsumablesInCounts" resultType="java.util.Map">
        SELECT DATE(sir.create_time) AS date,
               SUM(sir.Consumables_in_num) AS count
        FROM consumables_in_record sir
                 JOIN product_model pm ON sir.product_model_id = pm.id
                 JOIN product p ON pm.product_id = p.id
        WHERE (p.parent_id = #{rootCategoryId} OR p.id = #{rootCategoryId})
          AND sir.create_time &gt;= #{startDate}
          AND sir.create_time &lt;= #{endDate}
        GROUP BY DATE(sir.create_time)
        ORDER BY DATE(sir.create_time) ASC
    </select>
    <select id="selectDailyConsumablesOutCounts" resultType="java.util.Map">
        SELECT DATE(sor.create_time)  AS date,
               SUM(sor.Consumables_out_num) AS count
        FROM consumables_out_record sor
                 JOIN product_model pm ON sor.product_model_id = pm.id
                 JOIN product p ON pm.product_id = p.id
        WHERE (p.parent_id = #{rootCategoryId} OR p.id = #{rootCategoryId})
          AND sor.create_time &gt;= #{startDate}
          AND sor.create_time &lt;= #{endDate}
        GROUP BY DATE(sor.create_time)
        ORDER BY DATE(sor.create_time) ASC
    </select>
</mapper>
src/main/resources/mapper/consumables/ConsumablesOutRecordMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,76 @@
<?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.consumables.mapper.ConsumablesOutRecordMapper">
    <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.consumables.pojo.ConsumablesOutRecord">
        <id column="id" property="id" />
        <result column="outbound_batches" property="outboundBatches" />
        <result column="Consumables_out_num" property="consumablesOutNum" />
        <result column="record_id" property="recordId" />
        <result column="record_type" property="recordType" />
        <result column="product_model_id" property="productModelId" />
        <result column="remark" property="remark" />
        <result column="create_time" property="createTime" />
        <result column="update_time" property="updateTime" />
        <result column="create_user" property="createUser" />
        <result column="update_user" property="updateUser" />
        <result column="license_plate_no" property="licensePlateNo" />
    </resultMap>
    <select id="listPage" resultType="com.ruoyi.consumables.dto.ConsumablesOutRecordDto">
        SELECT
        sor.*,
        p.product_name as productName,
        pm.model,
        pm.unit,
        u.nick_name as createBy
        FROM Consumables_out_record as sor
        LEFT JOIN product_model as pm on sor.product_model_id = pm.id
        LEFT JOIN product as p on pm.product_id = p.id
        LEFT JOIN sys_user as u on sor.create_user = u.user_id
        <where>
            <if test="params.timeStr != null and params.timeStr != ''">
                and sor.create_time like concat('%',#{params.timeStr},'%')
            </if>
            <if test="params.productName != null and params.productName != ''">
                and p.product_name like concat('%',#{params.productName},'%')
            </if>
            <if test="params.type != null and params.type != ''">
                and sor.type = #{params.type}
            </if>
            <if test="params.recordType != null and params.recordType != ''">
                and sor.record_type = #{params.recordType}
            </if>
        </where>
        order by sor.id desc
    </select>
    <select id="listConsumablesOutRecordExportData" resultType="com.ruoyi.consumables.execl.ConsumablesOutRecordExportData">
        SELECT
        sor.*,
        p.product_name as productName,
        pm.model,
        pm.unit,
        u.nick_name as createBy
        FROM Consumables_out_record as sor
        LEFT JOIN product_model as pm on sor.product_model_id = pm.id
        LEFT JOIN product as p on pm.product_id = p.id
        LEFT JOIN sys_user as u on sor.create_user = u.user_id
        <where>
            <if test="params.timeStr != null and params.timeStr != ''">
                and sor.create_time like concat('%',#{params.timeStr},'%')
            </if>
            <if test="params.productName != null and params.productName != ''">
                and p.product_name like concat('%',#{params.productName},'%')
            </if>
            <if test="params.type != null and params.type != ''">
                and sor.type = #{params.type}
            </if>
            <if test="params.recordType != null and params.recordType != ''">
                and sor.record_type = #{params.recordType}
            </if>
        </where>
        order by sor.id desc
    </select>
</mapper>
src/main/resources/mapper/consumables/ConsumablesUninventoryMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,81 @@
<?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.consumables.mapper.ConsumablesUnInventoryMapper">
    <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.consumables.pojo.ConsumablesUnInventory">
        <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" />
    </resultMap>
    <update id="updateSubtractConsumablesUnInventory">
        update consumables_uninventory
        <set>
            <if test="ew.qualitity != null">
                qualitity = qualitity - #{ew.qualitity},
            </if>
            <if test="ew.version != null">
                version = version + 1,
            </if>
            <if test="ew.remark != null and ew.remark !=''">
                remark = #{ew.remark},
            </if>
            update_time = now()
        </set>
        where product_model_id = #{ew.productModelId} and qualitity >= #{ew.qualitity}
    </update>
    <update id="updateAddConsumablesUnInventory">
        update consumables_uninventory
        <set>
            <if test="ew.qualitity != null">
                qualitity = qualitity + #{ew.qualitity},
            </if>
            <if test="ew.version != null">
                version = version + 1,
            </if>
            <if test="ew.remark != null and ew.remark !=''">
                remark = #{ew.remark},
            </if>
            update_time = now()
        </set>
        where product_model_id = #{ew.productModelId}
    </update>
    <select id="pageConsumablesUninventory" resultType="com.ruoyi.consumables.dto.ConsumablesUnInventoryDto">
        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 consumables_uninventory su
        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="listConsumablesInventoryExportData" resultType="com.ruoyi.consumables.execl.ConsumablesUnInventoryExportData">
        select su.*,
        pm.model,
        pm.unit,
        p.product_name
        from consumables_uninventory su
        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>
</mapper>
src/main/resources/mapper/stock/StockInventoryMapper.xml
@@ -39,8 +39,8 @@
    <update id="updateSubtractStockInventory">
        update stock_inventory
        <set>
            <if test="ew.qualitity != null">
                qualitity = qualitity - #{ew.qualitity},
            <if test="ew.netWeight != null">
                qualitity = qualitity - #{ew.netWeight},
            </if>
            <if test="ew.version != null">
                version = version + 1,