From 5d314130e6f21bd265388b5210808baeba5f2d0c Mon Sep 17 00:00:00 2001
From: gongchunyi <deslre0381@gmail.com>
Date: 星期一, 23 三月 2026 17:57:14 +0800
Subject: [PATCH] feat: 生产报工的工序参数/BOM消耗产品查询返回、新增报工、分页查询

---
 src/main/java/com/ruoyi/production/service/impl/ProductionRecordServiceImpl.java |  348 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 348 insertions(+), 0 deletions(-)

diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionRecordServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionRecordServiceImpl.java
new file mode 100644
index 0000000..45d43d1
--- /dev/null
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionRecordServiceImpl.java
@@ -0,0 +1,348 @@
+package com.ruoyi.production.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.other.mapper.TempFileMapper;
+import com.ruoyi.other.pojo.TempFile;
+import com.ruoyi.production.dto.ProductionProductRouteItemDto;
+import com.ruoyi.production.dto.ProductionProductRouteItemParamDto;
+import com.ruoyi.production.dto.ProductionRecordDto;
+import com.ruoyi.production.enums.ProductOrderStatusEnum;
+import com.ruoyi.production.pojo.*;
+import com.ruoyi.production.service.*;
+import com.ruoyi.production.vo.ProductionOrderRouteItemParamVo;
+import com.ruoyi.production.vo.ProductionOrderRouteItemVo;
+import com.ruoyi.production.vo.ProductionOrderStructureVo;
+import com.ruoyi.production.vo.ProductionRecordVo;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.FilenameUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+/**
+ * <br>
+ * 鐢熶骇鎶ュ伐璁板綍Service瀹炵幇绫�
+ * </br>
+ *
+ * @author deslrey
+ * @version 1.0
+ * @since 2026/03/23 10:23
+ */
+@Slf4j
+@Service
+public class ProductionRecordServiceImpl implements ProductionRecordService {
+
+    @Value("${file.upload-dir}")
+    private String uploadDir;
+
+    @Autowired
+    private ProductionProductMainService productionProductMainService;
+
+    @Autowired
+    private ProductionProductInputService productionProductInputService;
+
+    @Autowired
+    private ProductionProductOutputService productionProductOutputService;
+
+    @Autowired
+    private IProductionProductRouteItemService productionProductRouteItemService;
+
+    @Autowired
+    private IProductionProductRouteItemParamService productionProductRouteItemParamService;
+
+    @Autowired
+    private IProductionProductRouteItemFileService productionProductRouteItemFileService;
+
+    @Autowired
+    private ProductOrderService productOrderService;
+
+    @Autowired
+    private IProductionOrderRouteItemService productionOrderRouteItemService;
+
+    @Autowired
+    private IProductionOrderRouteItemParamService productionOrderRouteItemParamService;
+
+    @Autowired
+    private IProductionOrderStructureService productionOrderStructureService;
+
+    @Autowired
+    private ProductProcessService productProcessService;
+
+    @Autowired
+    private ProductMaterialSkuService productMaterialSkuService;
+
+    @Autowired
+    private ProductMaterialService productMaterialService;
+
+    @Autowired
+    private TempFileMapper tempFileMapper;
+
+    @Override
+    public ProductionRecordVo productRouteItem(Long productOrderId) {
+        if (productOrderId == null) {
+            throw new ServiceException("璇烽�夋嫨鐢熶骇璁㈠崟鍐嶆柊澧炴姤宸�");
+        }
+
+        //  鏌ヨ鍑虹敓浜ц鍗曠粦瀹氱殑宸ヨ壓璺嚎
+        ProductOrder productOrder = productOrderService.getById(productOrderId);
+        if (productOrder == null) {
+            throw new ServiceException("鏈煡璇㈠埌璇ョ敓浜ц鍗曠殑淇℃伅");
+        }
+        //  閫氳繃宸ヨ壓璺嚎鏌ヨ鍑虹粦瀹氱殑宸ュ簭鍙婂弬鏁�
+        List<ProductionOrderRouteItem> productionOrderRouteItemList = productionOrderRouteItemService.list(new LambdaQueryWrapper<ProductionOrderRouteItem>()
+                .eq(ProductionOrderRouteItem::getOrderId, productOrderId)
+                .eq(ProductionOrderRouteItem::getRouteId, productOrder.getRouteId()));
+
+        if (productionOrderRouteItemList == null || productionOrderRouteItemList.isEmpty()) {
+            throw new ServiceException("璇ョ敓浜ц鍗曠粦瀹氱殑宸ヨ壓璺嚎鏃犲伐搴�");
+        }
+
+        ProductionRecordVo productionRecordVo = new ProductionRecordVo();
+        productionRecordVo.setProductOrderId(productOrderId);
+        productionRecordVo.setProductRouteId(productOrder.getRouteId());
+
+        List<ProductionOrderRouteItemVo> productionOrderRouteItemVoList = new ArrayList<>();
+
+        //  鏍规嵁缁戝畾鐨勫伐搴忔煡璇㈠嚭宸ュ簭鍙傛暟鍙夿OM闇�瑕佹秷鑰楃殑浜у搧
+        for (ProductionOrderRouteItem orderRouteItem : productionOrderRouteItemList) {
+            ProductionOrderRouteItemVo productionOrderRouteItemVo = new ProductionOrderRouteItemVo();
+            productionOrderRouteItemVo.setProcessId(orderRouteItem.getProcessId());
+
+            if (orderRouteItem.getProcessId() != null) {
+                ProductProcess process = productProcessService.getById(orderRouteItem.getProcessId());
+                if (process != null) {
+                    productionOrderRouteItemVo.setProcessName(process.getName());
+                }
+            }
+
+            List<ProductionOrderRouteItemParam> orderRouteItemParamList = productionOrderRouteItemParamService.list(new LambdaQueryWrapper<ProductionOrderRouteItemParam>()
+                    .eq(ProductionOrderRouteItemParam::getOrderId, productOrderId)
+                    .eq(ProductionOrderRouteItemParam::getRouteItemId, orderRouteItem.getId()));
+
+            if (orderRouteItemParamList != null && !orderRouteItemParamList.isEmpty()) {
+                List<ProductionOrderRouteItemParamVo> paraVoList = orderRouteItemParamList.stream().map(param -> {
+                    ProductionOrderRouteItemParamVo paraVo = new ProductionOrderRouteItemParamVo();
+                    BeanUtils.copyProperties(param, paraVo);
+                    paraVo.setParamFormat(DateUtils.toUpperCasePattern(paraVo.getParamFormat()));
+                    return paraVo;
+                }).collect(Collectors.toList());
+                productionOrderRouteItemVo.setOrderRouteItemParaVos(paraVoList);
+            }
+
+            List<ProductionOrderStructure> orderStructureList = productionOrderStructureService.list(new LambdaQueryWrapper<ProductionOrderStructure>()
+                    .eq(ProductionOrderStructure::getOrderId, productOrderId)
+                    .eq(ProductionOrderStructure::getProcessId, orderRouteItem.getProcessId()));
+
+            if (orderStructureList != null && !orderStructureList.isEmpty()) {
+                List<ProductionOrderStructureVo> structureVoList = orderStructureList.stream().map(struct -> {
+                    ProductionOrderStructureVo structureVo = new ProductionOrderStructureVo();
+                    BeanUtils.copyProperties(struct, structureVo);
+                    //  鏌ヨ鍑轰骇鍝佺殑鍚嶇О/妯″瀷
+                    ProductMaterialSku productMaterialSku = productMaterialSkuService.getById(structureVo.getProductModelId());
+                    ProductMaterial productMaterial = productMaterialService.getById(productMaterialSku.getProductId());
+                    structureVo.setProductName(productMaterial.getProductName());
+                    structureVo.setModel(productMaterialSku.getModel());
+                    return structureVo;
+                }).collect(Collectors.toList());
+                productionOrderRouteItemVo.setOrderStructureVos(structureVoList);
+            }
+
+            //  姣忎竴涓伐搴忕殑鍙傛暟銆丅OM娑堣�椾骇鍝�
+            productionOrderRouteItemVoList.add(productionOrderRouteItemVo);
+        }
+
+        productionRecordVo.setProductionOrderRouteItemVos(productionOrderRouteItemVoList);
+        return productionRecordVo;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void addProductionRecordService(ProductionRecordDto dto) {
+        if (dto == null) {
+            throw new ServiceException("鎶ュ伐澶辫触,鏁版嵁涓嶈兘涓虹┖");
+        }
+        if (dto.getProductOrderId() == null) {
+            throw new ServiceException("鎶ュ伐澶辫触,鐢熶骇璁㈠崟ID涓嶈兘涓虹┖");
+        }
+        if (dto.getProductId() == null) {
+            throw new ServiceException("鎶ュ伐澶辫触,浜у搧淇℃伅涓嶈兘涓虹┖");
+        }
+        if (StringUtils.isEmpty(dto.getPostName()) || StringUtils.isEmpty(dto.getSchedule())) {
+            throw new ServiceException("鎶ュ伐澶辫触,宀椾綅浜哄憳/鐝淇℃伅涓嶈兘涓虹┖");
+        }
+
+        //  鏇存柊鐢熶骇璁㈠崟鏁版嵁
+        ProductOrder productOrder = productOrderService.getById(dto.getProductOrderId());
+        if (productOrder == null) {
+            throw new ServiceException("鎶ュ伐澶辫触,鐢熶骇璁㈠崟涓嶅瓨鍦�");
+        }
+
+        //  褰撳墠鎶ュ伐鍚堟牸鏁伴噺
+        BigDecimal qualifiedQty = dto.getQualifiedQuantity() == null ? BigDecimal.ZERO : dto.getQualifiedQuantity();
+        //  宸插畬鎴愭暟閲�
+        BigDecimal completeQty = productOrder.getCompleteQuantity() == null ? BigDecimal.ZERO : productOrder.getCompleteQuantity();
+        //  绱姞(鍙畻鍚堟牸)
+        BigDecimal newCompleteQty = completeQty.add(qualifiedQty);
+        productOrder.setCompleteQuantity(newCompleteQty);
+        //  闇�姹傛暟閲�
+        BigDecimal totalQty = productOrder.getQuantity() == null ? BigDecimal.ZERO : productOrder.getQuantity();
+        // 鍓╀綑鍙姤宸ユ暟閲�
+        BigDecimal remainQty = totalQty.subtract(completeQty);
+        //  鏈鎶ュ伐涓嶈兘瓒呰繃鍓╀綑鏁伴噺
+        if (qualifiedQty.compareTo(remainQty) > 0) {
+            throw new ServiceException("鎶ュ伐澶辫触锛屾湰娆℃姤宸ユ暟閲忎笉鑳藉ぇ浜庡墿浣欏彲鎶ュ伐鏁伴噺");
+        }
+        //  璁剧疆寮�濮嬫椂闂达紙绗竴娆℃姤宸ワ級
+        if (productOrder.getStartTime() == null) {
+            productOrder.setStartTime(LocalDateTime.now());
+        }
+        //  鐘舵�佸垽鏂�
+        if (newCompleteQty.compareTo(totalQty) >= 0 && totalQty.compareTo(BigDecimal.ZERO) > 0) {
+            productOrder.setStatus(ProductOrderStatusEnum.FINISHED.getCode());
+            productOrder.setEndTime(LocalDateTime.now());
+        } else {
+            productOrder.setStatus(ProductOrderStatusEnum.RUNNING.getCode());
+        }
+        boolean update = productOrderService.updateById(productOrder);
+        if (!update) {
+            throw new ServiceException("鎶ュ伐澶辫触,鐢熶骇璁㈠崟鏇存柊澶辫触");
+        }
+
+        //  瀹屾垚鎶ュ伐涓昏〃-鎶曞叆琛�-浜у嚭琛ㄦ暟鎹�
+        ProductionProductMain productionProductMain = new ProductionProductMain();
+        productionProductMain.setProductNo("BG" + UUID.randomUUID());
+        productionProductMain.setProductOrderId(dto.getProductOrderId());
+        productionProductMain.setSchedule(dto.getSchedule());
+        boolean result = productionProductMainService.save(productionProductMain);
+        if (!result) {
+            throw new ServiceException("鎶ュ伐澶辫触,鏁版嵁瀛樺偍澶辫触");
+        }
+
+        ProductionProductInput productionProductInput = new ProductionProductInput();
+        productionProductInput.setProductMainId(productionProductMain.getId());
+        productionProductInput.setProductModelId(dto.getProductId());
+        productionProductInput.setQuantity(dto.getQuantity());
+        result = productionProductInputService.save(productionProductInput);
+        if (!result) {
+            throw new ServiceException("鎶ュ伐澶辫触,鐢熶骇鎶曞叆瀛樺偍澶辫触");
+        }
+
+        ProductionProductOutput productionProductOutput = new ProductionProductOutput();
+        productionProductOutput.setProductMainId(productionProductMain.getId());
+        productionProductOutput.setProductModelId(dto.getProductId());
+        productionProductOutput.setQuantity(dto.getQualifiedQuantity());
+        productionProductOutput.setScrapQty(dto.getUnqualifiedQuantity());
+        result = productionProductOutputService.save(productionProductOutput);
+        if (!result) {
+            throw new ServiceException("鎶ュ伐澶辫触,鐢熶骇浜у嚭瀛樺偍澶辫触");
+        }
+
+        //  澶勭悊宸ュ簭
+        List<ProductionProductRouteItemDto> productionProductRouteItemDtoList = dto.getProductionProductRouteItemDtoList();
+        if (productionProductRouteItemDtoList == null || productionProductRouteItemDtoList.isEmpty()) {
+            throw new ServiceException("鎶ュ伐澶辫触,宸ュ簭鍙傛暟涓嶈兘涓虹┖");
+        }
+        for (ProductionProductRouteItemDto productRouteItemDto : productionProductRouteItemDtoList) {
+            //  澶勭悊宸ュ簭涓昏〃
+            ProductionProductRouteItem productRouteItemEntity = new ProductionProductRouteItem();
+            BeanUtils.copyProperties(productRouteItemDto, productRouteItemEntity, "id");
+            productRouteItemEntity.setProductMainId(productionProductMain.getId());
+            productionProductRouteItemService.save(productRouteItemEntity);
+
+            //  澶勭悊鍙傛暟鍙婃秷鑰椾骇鍝�
+            List<ProductionProductRouteItemParamDto> productionProductRouteItemParamDtoList = productRouteItemDto.getProductionProductRouteItemParamDtoList();
+            if (productionProductRouteItemParamDtoList != null && !productionProductRouteItemParamDtoList.isEmpty()) {
+                for (ProductionProductRouteItemParamDto productRouteItemParamDto : productionProductRouteItemParamDtoList) {
+                    ProductionProductRouteItemParam paramEntity = new ProductionProductRouteItemParam();
+                    BeanUtils.copyProperties(productRouteItemParamDto, paramEntity, "id");
+                    paramEntity.setProductionProductRouteItemId(productRouteItemEntity.getId());
+                    if (paramEntity.getProductId() != null) {
+                    } else {
+                        ProductionOrderRouteItemParam productionOrderRouteItemParam = productionOrderRouteItemParamService.getById(productRouteItemParamDto.getId());
+                        paramEntity.setParamName(productionOrderRouteItemParam.getParamName());
+                        paramEntity.setParamType(productionOrderRouteItemParam.getParamType());
+                        paramEntity.setParamFormat(productionOrderRouteItemParam.getParamFormat());
+                        paramEntity.setValueMode(productionOrderRouteItemParam.getValueMode());
+                    }
+
+                    productionProductRouteItemParamService.save(paramEntity);
+                }
+            }
+
+            //  澶勭悊宸ュ簭涓婁紶鐨勯檮浠�
+            List<String> files = productRouteItemDto.getFiles();
+            if (files != null && !files.isEmpty()) {
+                for (String tempId : files) {
+                    TempFile tempFile = tempFileMapper.selectById(tempId);
+                    if (tempFile == null) {
+                        log.warn("鏈壘鍒颁复鏃舵枃浠惰褰�: {}", tempId);
+                        continue;
+                    }
+
+                    try {
+                        //  姝e紡鐩綍璺緞锛堟寜鏃ユ湡鍒嗙粍锛�
+                        String formalDir = uploadDir + LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE);
+                        Path formalDirPath = Paths.get(formalDir);
+                        if (!Files.exists(formalDirPath)) {
+                            Files.createDirectories(formalDirPath);
+                        }
+
+                        //  姝e紡鏂囦欢鍚�
+                        String originalFilename = tempFile.getOriginalName();
+                        String fileExtension = FilenameUtils.getExtension(originalFilename);
+                        String formalFilename = productRouteItemEntity.getId() + "_" +
+                                System.currentTimeMillis() + "_" +
+                                UUID.randomUUID().toString().substring(0, 8) +
+                                (StringUtils.hasText(fileExtension) ? "." + fileExtension : "");
+
+                        Path formalFilePath = formalDirPath.resolve(formalFilename);
+
+                        //  鏂囦欢杩佺Щ (澶嶅埗+鍒犻櫎)
+                        Files.copy(Paths.get(tempFile.getTempPath()), formalFilePath, StandardCopyOption.REPLACE_EXISTING);
+                        Files.deleteIfExists(Paths.get(tempFile.getTempPath()));
+
+                        //  淇濆瓨鎶ュ伐闄勪欢璁板綍
+                        ProductionProductRouteItemFile fileEntity = new ProductionProductRouteItemFile();
+                        fileEntity.setProductionProductRouteItemId(productRouteItemEntity.getId());
+                        fileEntity.setFileName(originalFilename);
+                        fileEntity.setFileUrl(formalFilePath.toString());
+                        fileEntity.setFileSuffix(fileExtension);
+                        fileEntity.setFileSize(Files.size(formalFilePath));
+                        fileEntity.setCreateTime(LocalDateTime.now());
+                        fileEntity.setTenantId(SecurityUtils.getLoginUser().getTenantId());
+                        productionProductRouteItemFileService.save(fileEntity);
+
+                        //  鍒犻櫎涓存椂鏂囦欢璁板綍
+                        tempFileMapper.deleteById(tempId);
+                        log.info("宸ュ簭闄勪欢杩佺Щ鎴愬姛: {} -> {}", tempFile.getTempPath(), formalFilePath);
+
+                    } catch (IOException e) {
+                        log.error("宸ュ簭闄勪欢杩佺Щ澶辫触: {}", tempFile.getTempPath(), e);
+                        throw new ServiceException("宸ュ簭闄勪欢澶勭悊寮傚父: " + e.getMessage());
+                    }
+                }
+            }
+        }
+    }
+
+}

--
Gitblit v1.9.3