b9e71660ca35e947ccac8079d3033b88ece5190e..a4a0e2bd0ddcf0b6c55b701fc52875f3302cbe11
2026-05-27 buhuazhen
feat 校验提交修改
a4a0e2 对比 | 目录
2026-05-27 buhuazhen
Merge remote-tracking branch 'origin/dev_天津_阳光彩印' into dev_天津_阳光彩印
42bf6c 对比 | 目录
2026-05-27 buhuazhen
feat 页面显示巡检状态
f770e3 对比 | 目录
2026-05-27 liyong
验收应急用
b19637 对比 | 目录
2026-05-27 liyong
Merge remote-tracking branch 'origin/dev_天津_阳光彩印' into dev_天津_阳光彩印
d14764 对比 | 目录
2026-05-27 liyong
验收应急用
3ce16d 对比 | 目录
2026-05-27 buhuazhen
Merge remote-tracking branch 'origin/dev_天津_阳光彩印' into dev_天津_阳光彩印
cf3482 对比 | 目录
2026-05-27 buhuazhen
feat 页面显示巡检状态
ee6901 对比 | 目录
2026-05-27 liyong
生产入库逻辑修改,只有最后一道工序的报工才会入库,只有成品检验和原材料检验入库
5f33ae 对比 | 目录
2026-05-27 liyong
Merge remote-tracking branch 'origin/dev_天津_阳光彩印' into dev_天津_阳光彩印
8e941a 对比 | 目录
2026-05-27 liyong
生产入库逻辑修改,只有最后一道工序的报工才会入库,只有成品检验和原材料检验入库
407a9d 对比 | 目录
2026-05-27 buhuazhen
feat 设备报修添加范围、巡检添加三个状态
09b817 对比 | 目录
2026-05-27 liyong
Merge remote-tracking branch 'origin/dev_天津_阳光彩印' into dev_天津_阳光彩印
e3b3fd 对比 | 目录
2026-05-27 liyong
规章制度发布人名称反显错误修改
bf6003 对比 | 目录
2026-05-27 buhuazhen
feat(ProductionPrintOrder) 每一道工序多产生品都为成品
eb0679 对比 | 目录
2026-05-27 buhuazhen
feat(ProductionPrintOrder) 工序改为9位
aeb7d4 对比 | 目录
2026-05-27 buhuazhen
feat(ProductionPrintOrder) 工序添加是否质检
6690f4 对比 | 目录
2026-05-27 buhuazhen
feat(ProductionPrintOrder) 删除多余订单工艺路线
44197e 对比 | 目录
2026-05-27 buhuazhen
feat 质检检测调整
c78984 对比 | 目录
2026-05-27 buhuazhen
feat(production):报工实际添加order完成数量调整
03ac57 对比 | 目录
2026-05-25 buhuazhen
feat(production):添加成品名称查询
e2fea9 对比 | 目录
已添加3个文件
已修改21个文件
994 ■■■■ 文件已修改
src/main/java/com/ruoyi/basic/service/impl/ProductServiceImpl.java 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/dto/DeviceRepairDto.java 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/pojo/DeviceRepair.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/device/service/impl/DeviceDefectRecordServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/dto/InspectionTaskDto.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/pojo/InspectionTask.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/service/impl/InspectionTaskServiceImpl.java 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskJob.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/dto/ProcessRouteAnticlockwiseDto.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProcessRouteServiceImpl.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionPrintOrderServiceImpl.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/controller/QualityInspectController.java 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/dto/QualityInspectExportDTO.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/dto/QualityInspectExportVO.java 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/mapper/QualityInspectMapper.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/service/IQualityInspectService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/service/impl/QualityInspectExportHandle.java 277 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/collaborativeApproval/RulesRegulationsManagementMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/device/DeviceRepairMapper.xml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductWorkOrderMapper.xml 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/purchase/InvoicePurchaseMapper.xml 189 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/quality/QualityInspectMapper.xml 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/ProductServiceImpl.java
@@ -32,26 +32,60 @@
    @Override
    public List<ProductTreeDto> selectProductList(ProductDto productDto) {
        // æŸ¥è¯¢æ ¹èŠ‚ç‚¹ï¼ˆparentId ä¸º null)
        // ä¸€æ¬¡æ€§æŸ¥è¯¢æ‰€æœ‰æ•°æ®
        LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.isNull(Product::getParentId);
        // å¦‚果有产品名称条件,添加到查询中
        if (productDto.getProductName() != null && !productDto.getProductName().isEmpty()) {
            queryWrapper.like(Product::getProductName, productDto.getProductName());
        }
        List<Product> allProducts = productMapper.selectList(queryWrapper);
        // æŸ¥è¯¢æ ¹èŠ‚ç‚¹åˆ—è¡¨
        List<Product> rootProducts = productMapper.selectList(queryWrapper);
        // åœ¨å†…存中构建树结构
        return buildTree(allProducts);
    }
        // è½¬æ¢ä¸ºæ ‘节点并递归构建子树
    /**
     * æž„建树结构
     * @param allProducts æ‰€æœ‰äº§å“æ•°æ®
     * @return æ ‘形结构列表
     */
    private List<ProductTreeDto> buildTree(List<Product> allProducts) {
        // æŒ‰ parentId åˆ†ç»„
        java.util.Map<Long, List<Product>> parentMap = new java.util.HashMap<>();
        List<Product> rootList = new ArrayList<>();
        for (Product product : allProducts) {
            if (product.getParentId() == null) {
                rootList.add(product);
            } else {
                parentMap.computeIfAbsent(product.getParentId(), k -> new ArrayList<>()).add(product);
            }
        }
        // é€’归构建子节点
        List<ProductTreeDto> tree = new ArrayList<>();
        for (Product product : rootProducts) {
            ProductTreeDto node = convertToTreeDto(product);
            node.setChildren(buildChildrenNodes(product.getId()));
            tree.add(node);
        for (Product root : rootList) {
            tree.add(buildNode(root, parentMap));
        }
        return tree;
    }
    /**
     * é€’归构建节点及其子节点
     * @param product äº§å“å®žä½“
     * @param parentMap æŒ‰parentId分组的map
     * @return æ ‘节点
     */
    private ProductTreeDto buildNode(Product product, java.util.Map<Long, List<Product>> parentMap) {
        ProductTreeDto node = convertToTreeDto(product);
        List<Product> children = parentMap.get(product.getId());
        if (children != null && !children.isEmpty()) {
            List<ProductTreeDto> childNodes = new ArrayList<>();
            for (Product child : children) {
                childNodes.add(buildNode(child, parentMap));
            }
            node.setChildren(childNodes);
        }
        return node;
    }
    @Override
@@ -60,24 +94,7 @@
    }
    // é€’归构建子节点
    private List<ProductTreeDto> buildChildrenNodes(Long parentId) {
        // æŸ¥è¯¢å½“前父节点的子节点
        LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Product::getParentId, parentId);
        List<Product> childProducts = productMapper.selectList(queryWrapper);
        // è½¬æ¢å­èŠ‚ç‚¹å¹¶é€’å½’æž„å»ºå®ƒä»¬çš„å­æ ‘
        List<ProductTreeDto> children = new ArrayList<>();
        for (Product child : childProducts) {
            ProductTreeDto childNode = convertToTreeDto(child);
            childNode.setChildren(buildChildrenNodes(child.getId()));
            children.add(childNode);
        }
        return children;
    }
    // å°† Product è½¬æ¢ä¸º ProductTreeDto
    private ProductTreeDto convertToTreeDto(Product product) {
        ProductTreeDto dto = new ProductTreeDto();
src/main/java/com/ruoyi/device/dto/DeviceRepairDto.java
@@ -3,13 +3,19 @@
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DeviceRepairDto {
    @ApiModelProperty("设备报修id")
@@ -24,10 +30,15 @@
    @ApiModelProperty("设备型号")
    private String deviceModel;
    @ApiModelProperty("报修时间")
    private Date repairTime;
    private String repairTimeStr;
    @ApiModelProperty("报修时间开始")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime repairTimeStart;
    @ApiModelProperty("报修时间结束")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime repairTimeEnd;
    @ApiModelProperty("报修人")
    private String repairName;
src/main/java/com/ruoyi/device/pojo/DeviceRepair.java
@@ -26,8 +26,15 @@
    private String deviceModel;
    @ApiModelProperty("报修时间")
    private Date repairTime;
    @ApiModelProperty("报修时间开始")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime repairTimeStart;
    @ApiModelProperty("报修时间结束")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime repairTimeEnd;
    @ApiModelProperty("报修人")
    private String repairName;
src/main/java/com/ruoyi/device/service/impl/DeviceDefectRecordServiceImpl.java
@@ -39,7 +39,7 @@
            deviceRepair.setRemark(deviceDefectRecord.getDefectDescription());
            //获取当前登录用户
            deviceRepair.setRepairName(SecurityUtils.getUsername());
            deviceRepair.setRepairTime(new Date());
//            deviceRepair.setRepairTime(new Date());
            deviceRepairMapper.insert(deviceRepair);
            return deviceDefectRecordMapper.insert(deviceDefectRecord) > 0;
        } else if (status.equals("一般缺陷")) {
src/main/java/com/ruoyi/inspectiontask/dto/InspectionTaskDto.java
@@ -6,6 +6,7 @@
import com.ruoyi.sales.pojo.CommonFile;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
@Data
@@ -23,4 +24,14 @@
    private List<CommonFile> commonFileListAfter;  //生产后
    private List<CommonFile> commonFileListBefore; //生产前
    /**
     * è¦æ±‚的执行时间(来自定时任务的nextExecutionTime)
     */
    private LocalDateTime nextExecutionTime;
    /**
     * çŠ¶æ€ï¼šEXPIRED-已过期,IN_PROGRESS-巡检中,PENDING-待巡检
     */
    private String status;
}
src/main/java/com/ruoyi/inspectiontask/pojo/InspectionTask.java
@@ -94,4 +94,16 @@
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    @ApiModelProperty(value = "关联定时任务ID")
    private Long timingTaskId;
    @ApiModelProperty(value = "生产前是否存在异常")
    private Boolean hasExceptionBefore;
    @ApiModelProperty(value = "生产中是否存在异常")
    private Boolean hasExceptionAfter;
    @ApiModelProperty(value = "生产后是否存在异常")
    private Boolean hasExceptionIssue;
}
src/main/java/com/ruoyi/inspectiontask/service/impl/InspectionTaskServiceImpl.java
@@ -18,7 +18,9 @@
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.inspectiontask.dto.InspectionTaskDto;
import com.ruoyi.inspectiontask.mapper.InspectionTaskMapper;
import com.ruoyi.inspectiontask.mapper.TimingTaskMapper;
import com.ruoyi.inspectiontask.pojo.InspectionTask;
import com.ruoyi.inspectiontask.pojo.TimingTask;
import com.ruoyi.inspectiontask.service.InspectionTaskService;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysUserMapper;
@@ -31,6 +33,7 @@
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
@@ -71,6 +74,9 @@
    @Autowired
    private CommonFileServiceImpl commonFileService;
    @Autowired
    private TimingTaskMapper timingTaskMapper;
    @Override
    public IPage<InspectionTaskDto> selectInspectionTaskList(Page<InspectionTask> page, InspectionTaskDto inspectionTaskDto) {
@@ -134,6 +140,20 @@
        }
        List<CommonFile> finalCommonFiles = commonFiles;
        // æ‰¹é‡æŸ¥è¯¢å®šæ—¶ä»»åŠ¡èŽ·å–nextExecutionTime
        List<Long> timingTaskIds = entityPage.getRecords().stream()
                .map(InspectionTask::getTimingTaskId)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        Map<Long, TimingTask> timingTaskMap = new HashMap<>();
        if (!timingTaskIds.isEmpty()) {
            List<TimingTask> timingTasks = timingTaskMapper.selectBatchIds(timingTaskIds);
            timingTaskMap = timingTasks.stream()
                    .collect(Collectors.toMap(TimingTask::getId, Function.identity()));
        }
        final Map<Long, TimingTask> finalTimingTaskMap = timingTaskMap;
        final LocalDateTime now = LocalDateTime.now();
        List<InspectionTaskDto> dtoList = entityPage.getRecords().stream().map(inspectionTask -> {
            InspectionTaskDto dto = new InspectionTaskDto();
            BeanUtils.copyProperties(inspectionTask, dto);  // å¤åˆ¶ä¸»å¯¹è±¡å±žæ€§
@@ -173,6 +193,17 @@
                    .filter(commonFile -> commonFile.getCommonId().equals(taskId) && commonFile.getType().equals(FileNameType.INSPECTION_PRODUCTION_BEFORE.getValue()))
                    .collect(Collectors.toList()));
            // è®¡ç®—状态:已过期 > å·¡æ£€ä¸­ > å¾…巡检
            String status = calculateStatus(inspectionTask, finalTimingTaskMap, now);
            dto.setStatus(status);
            // è®¾ç½®nextExecutionTime用于前端展示
            if (inspectionTask.getTimingTaskId() != null) {
                TimingTask timingTask = finalTimingTaskMap.get(inspectionTask.getTimingTaskId());
                if (timingTask != null) {
                    dto.setNextExecutionTime(timingTask.getNextExecutionTime());
                }
            }
            return dto;
        }).collect(Collectors.toList());
@@ -206,6 +237,50 @@
        return dto;
    }
    /**
     * è®¡ç®—巡检任务状态
     * ä¼˜å…ˆçº§ï¼šå·²å®Œæˆå·¡æ£€ > å·¡æ£€ä¸­(已过期) > å·¡æ£€ä¸­ > å·²è¿‡æœŸ > å¾…巡检
     * @param inspectionTask å·¡æ£€ä»»åŠ¡
     * @param timingTaskMap å®šæ—¶ä»»åŠ¡Map
     * @param now å½“前时间
     * @return çŠ¶æ€ï¼šCOMPLETED-已完成巡检,IN_PROGRESS_EXPIRED-巡检中(已过期),IN_PROGRESS-巡检中,EXPIRED-已过期,PENDING-待巡检
     */
    private String calculateStatus(InspectionTask inspectionTask, Map<Long, TimingTask> timingTaskMap, LocalDateTime now) {
        if(inspectionTask.getTimingTaskId() == null){
            return "EXPIRED";
        }
        boolean isExpired = false;
        // åˆ¤æ–­æ˜¯å¦å·²è¿‡æœŸ
        if (inspectionTask.getTimingTaskId() != null) {
            TimingTask timingTask = timingTaskMap.get(inspectionTask.getTimingTaskId());
            if (timingTask != null && timingTask.getNextExecutionTime() != null) {
                isExpired = now.isAfter(timingTask.getNextExecutionTime());
            }
        }
        // 1. åˆ¤æ–­æ˜¯å¦å·²å®Œæˆå·¡æ£€ï¼ˆä¸‰ä¸ªå¼‚常字段都不为null)
        if (inspectionTask.getHasExceptionBefore() != null
                && inspectionTask.getHasExceptionAfter() != null
                && inspectionTask.getHasExceptionIssue() != null) {
            return "COMPLETED";
        }
        // 2. åˆ¤æ–­æ˜¯å¦å·¡æ£€ä¸­ï¼ˆä»»ä¸€å¼‚常字段不为null)
        if (inspectionTask.getHasExceptionBefore() != null
                || inspectionTask.getHasExceptionAfter() != null
                || inspectionTask.getHasExceptionIssue() != null) {
            return isExpired ? "IN_PROGRESS_EXPIRED" : "IN_PROGRESS";
        }
        // 3. å·²è¿‡æœŸ
        if (isExpired) {
            return "EXPIRED";
        }
        // 4. å¾…巡检
        return "PENDING";
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int addOrEditInspectionTask(InspectionTaskDto inspectionTaskDto) throws IOException {
src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskJob.java
@@ -116,6 +116,7 @@
        inspectionTask.setFrequencyType(timingTask.getFrequencyType());
        inspectionTask.setFrequencyDetail(timingTask.getFrequencyDetail());
        inspectionTask.setTenantId(timingTask.getTenantId());
        inspectionTask.setTimingTaskId(timingTask.getId());
        return inspectionTask;
    }
src/main/java/com/ruoyi/production/dto/ProcessRouteAnticlockwiseDto.java
@@ -1,5 +1,6 @@
package com.ruoyi.production.dto;
import com.ruoyi.production.pojo.ProductProcess;
import lombok.Data;
@Data
@@ -27,4 +28,6 @@
    private Long deviceId;
    private String uuid;
    private ProductProcess productProcess;;
}
src/main/java/com/ruoyi/production/service/impl/ProcessRouteServiceImpl.java
@@ -113,7 +113,7 @@
        ProductProcessRoute productProcessRoute = createProductProcessRoute(productModelId, productOrderId, productBom.getId(), processRoute.getProcessRouteCode());
        // 6. æ–°å¢žç”Ÿäº§å·¥è‰ºè·¯çº¿å­è¡¨
        buildProductProcessRouteItems(processRouteAnticlockwiseDtos, productProcessRoute.getId(), productModelId,productOrderId);
        buildProductProcessRouteItems(processRouteAnticlockwiseDtos, productProcessRoute.getId(), productModelId, productOrderId);
        return processRoute.getId();
    }
@@ -163,7 +163,7 @@
        processRoute.setDescription("");
        this.save(processRoute);
        processRoute.setProcessRouteCode("GYLX." + String.format("%05d", processRoute.getId()));
        processRoute.setProcessRouteCode("GYLX." + String.format("%09d", processRoute.getId()));
        this.updateById(processRoute);
        return processRoute;
@@ -208,20 +208,21 @@
    /**
     * æž„建生产工艺路线子项列表
     */
    private void buildProductProcessRouteItems(List<ProcessRouteAnticlockwiseDto> dtos, Long productRouteId, Long productModelId,Long productOrderId) {
    private void buildProductProcessRouteItems(List<ProcessRouteAnticlockwiseDto> dtos, Long productRouteId, Long productModelId, Long productOrderId) {
        ProductOrder byId = productOrderService.getById(productOrderId);
        Integer num = 0;
        for (ProcessRouteAnticlockwiseDto dto : dtos) {
            ProductProcessRouteItem item = new ProductProcessRouteItem();
            item.setProductRouteId(productRouteId);
            item.setProcessId(dto.getProcessId());
            item.setProductModelId(dto.getProductModelId());
            item.setProductModelId(productModelId);
            item.setProcessRouteName(dto.getProcessRouteName());
            item.setProcessRouteOpenNum(dto.getProcessRouteOpenNum());
            item.setProcessRouteNum(dto.getProcessRouteNum());
            item.setProcessRouteAddNum(dto.getProcessRouteAddNum());
            item.setProcessRouteRequire(dto.getProcessRouteRequire());
            item.setDragSort(num++);
            item.setIsQuality(dto.getProductProcess().getIsQuality() != null && dto.getProductProcess().getIsQuality());
            item.setUuid(dto.getUuid());
            productProcessRouteItemService.save(item);
            ProductProcess productProcess = productProcessService.getById(item.getProcessId());
@@ -233,7 +234,7 @@
            productWorkOrder.setDeviceId(dto.getDeviceId());
            productWorkOrder.setUserIds(dto.getUserIds());
            productWorkOrder.setUserNames(dto.getUserNames());
            productWorkOrder.setWorkOrderNo(productWorkOrderService.generateProductWorkOrder( productProcess.getName(), byId.getNpsNo()));
            productWorkOrder.setWorkOrderNo(productWorkOrderService.generateProductWorkOrder(productProcess.getName(), byId.getNpsNo()));
            productWorkOrder.setStatus(1);
            productWorkOrderService.save(productWorkOrder);
        }
src/main/java/com/ruoyi/production/service/impl/ProductionPrintOrderServiceImpl.java
@@ -20,6 +20,7 @@
import com.ruoyi.production.pojo.*;
import com.ruoyi.production.service.ProductBomService;
import com.ruoyi.production.service.ProductProcessRouteService;
import com.ruoyi.production.service.ProductProcessService;
import com.ruoyi.production.service.ProductionPrintOrderService;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.Nullable;
@@ -29,6 +30,7 @@
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
@@ -51,11 +53,15 @@
    private final ProductBomService productBomService;
    private final CustomerFollowUpFileService customerFollowUpFileService;
    private final ProductProcessMapper productProcessMapper;
    private final ProductProcessService productProcessService;
    @Override
    @Transactional
    public void save(SaveProductionPrintOrderDto dto) {
        Assert.isFalse(CollUtil.isEmpty(dto.getProcessContent()),"情至少添加一条工序信息");
        ProductionPrintOrder productionPrintOrder = BeanUtil.copyProperties(dto, ProductionPrintOrder.class);
        if(dto.getId() != null){
        if(dto.getProductOrderId() != null){
            // å…ˆåˆ é™¤ç”Ÿäº§å·¥å•数据
            LambdaQueryWrapper<ProductWorkOrder> l1 = new LambdaQueryWrapper<>();
            l1.eq(ProductWorkOrder::getProductOrderId,dto.getProductOrderId());
@@ -79,6 +85,9 @@
        });
        MaterialInfoDto materialInfoDtoFirst = dto.getMaterialInfo().get(0);
        // è°ƒç”¨å·¥åºæ–¹å¢ž å‡½æ•°
        // æŸ¥è¯¢å·¥åºä¿¡æ¯
        List<Long> processIds = dto.getProcessContent().stream().map(ProcessContentDto::getProcessId).collect(Collectors.toList());
        Map<Long, ProductProcess> productProcessMap = productProcessService.listByIds(processIds).stream().collect(Collectors.toMap(ProductProcess::getId, productProcess -> productProcess));
        List<ProcessRouteAnticlockwiseDto> processRouteAnticlockwiseDtos = processContentDtoList.stream().map(it -> {
            ProcessRouteAnticlockwiseDto pdto = new ProcessRouteAnticlockwiseDto();
            pdto.setProcessId(it.getProcessId());
@@ -92,6 +101,7 @@
            pdto.setUserNames(it.getReportWorkerList().stream().map(SimplePersonDto::getUserName).collect(Collectors.joining(",")));
            pdto.setDeviceId(it.getDeviceId());
            pdto.setUuid(it.getId());
            pdto.setProductProcess(productProcessMap.get(it.getProcessId()));
            return pdto;
        }).collect(Collectors.toList());
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -222,7 +222,7 @@
            if (ObjectUtils.isNull(productOrder.getStartTime())) {
                productOrder.setStartTime(now);//开始时间
            }
            if (productProcessRouteItem.getDragSort() == productProcessRouteItems.size()) {
            if (productProcessRouteItem.getDragSort() >= productProcessRouteItems.size() -1 ) {
                //如果是最后一道工序报工之后生产订单完成数量+
                productOrder.setCompleteQuantity(productOrder.getCompleteQuantity().add(productQty));
                if (productOrder.getCompleteQuantity().compareTo(productOrder.getQuantity()) >= 0) {
@@ -337,7 +337,7 @@
                //对应的过程检或者出厂检
                int inspectType = 1;
                String process = productProcess.getName();//工序
                if (productProcessRouteItem.getDragSort() == productProcessRouteItems.size()) {
                if (productProcessRouteItem.getDragSort() == (productProcessRouteItems.size()-1)) {
                    //最后一道工序生成出厂检
                    inspectType = 2;
                    process = null;
@@ -371,7 +371,10 @@
                }
            } else {
                //直接入库
                stockUtils.addStock(productProcessRouteItem.getProductModelId(), productQty, StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(), productionProductMain.getId(), "-", "-", "-");
                if (productProcessRouteItem.getDragSort() == (productProcessRouteItems.size()-1)) {
                    //最后一道工序才会入库
                    stockUtils.addStock(productProcessRouteItem.getProductModelId(), productQty, StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(), productionProductMain.getId(), "-", "-", "-");
                }
            }
            /*添加生产核算        åŒºåˆ†å·¥åºæ˜¯è®¡ä»¶è¿˜æ˜¯è®¡æ—¶*/
src/main/java/com/ruoyi/quality/controller/QualityInspectController.java
@@ -8,6 +8,7 @@
import com.ruoyi.procurementrecord.service.ProcurementRecordService;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.quality.dto.QualityInspectDto;
import com.ruoyi.quality.dto.QualityInspectExportDTO;
import com.ruoyi.quality.pojo.QualityInspect;
import com.ruoyi.quality.pojo.QualityInspectFile;
import com.ruoyi.quality.pojo.QualityInspectParam;
@@ -112,16 +113,26 @@
    }
    /**
     * å¯¼å‡º
     * å¯¼å‡ºï¼ˆæ—§æŽ¥å£ï¼Œä¿ç•™å…¼å®¹ï¼‰
     * @param response
     * @param qualityInspect
     */
    @PostMapping("/export")
    public void qualityInspectExport(HttpServletResponse response,QualityInspect qualityInspect) {
    public void qualityInspectExport(HttpServletResponse response, QualityInspect qualityInspect) {
        qualityInspectService.qualityInspectExport(response, qualityInspect);
    }
    /**
     * å¯¼å‡ºï¼ˆæ–°æŽ¥å£ï¼Œæ”¯æŒé€‰ä¸­å¯¼å‡ºå’Œæ£€éªŒå‚数)
     * @param response
     * @param exportDTO
     */
    @PostMapping("/exportNew")
    public void qualityInspectExportNew(HttpServletResponse response, @RequestBody QualityInspectExportDTO exportDTO) {
        qualityInspectService.qualityInspectExportNew(response, exportDTO);
    }
    /**
     * æäº¤
     * @param qualityInspect
     * @return
src/main/java/com/ruoyi/quality/dto/QualityInspectExportDTO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
package com.ruoyi.quality.dto;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
 * è´¨é‡æ£€éªŒå¯¼å‡ºè¯·æ±‚参数
 */
@Data
public class QualityInspectExportDTO implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * æ£€éªŒç±»åž‹(0:原材料检验;1:过程检验;2:出厂检验)
     */
    private Integer inspectType;
    /**
     * é€‰ä¸­çš„ID列表(为空则全部导出)
     */
    private List<Long> ids;
    /**
     * ä¾›åº”商(原材料检验筛选)
     */
    private String supplier;
    /**
     * å·¥åºï¼ˆè¿‡ç¨‹æ£€éªŒç­›é€‰ï¼‰
     */
    private String process;
    /**
     * äº§å“åç§°ï¼ˆå‡ºåŽ‚æ£€éªŒç­›é€‰ï¼‰
     */
    private String productName;
    /**
     * æ£€æµ‹æ—¥æœŸå¼€å§‹
     */
    private String entryDateStart;
    /**
     * æ£€æµ‹æ—¥æœŸç»“束
     */
    private String entryDateEnd;
}
src/main/java/com/ruoyi/quality/dto/QualityInspectExportVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,90 @@
package com.ruoyi.quality.dto;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
 * è´¨é‡æ£€éªŒå¯¼å‡ºæ•°æ®VO(每个检验参数一行)
 */
@Data
public class QualityInspectExportVO implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * æ£€æµ‹æ—¥æœŸ
     */
    private Date checkTime;
    /**
     * é‡‡è´­è®¢å•号/生产工单号
     */
    private String orderNo;
    /**
     * ä¾›åº”商/工序
     */
    private String supplierOrProcess;
    /**
     * æ£€éªŒå‘˜
     */
    private String checkName;
    /**
     * äº§å“åç§°
     */
    private String productName;
    /**
     * è§„格型号
     */
    private String model;
    /**
     * å•位
     */
    private String unit;
    /**
     * æ•°é‡
     */
    private BigDecimal quantity;
    /**
     * æ£€æµ‹å•位
     */
    private String checkCompany;
    /**
     * æ£€æµ‹ç»“æžœ
     */
    private String checkResult;
    /**
     * æŒ‡æ ‡
     */
    private String parameterItem;
    /**
     * æŒ‡æ ‡å•位
     */
    private String paramUnit;
    /**
     * æ ‡å‡†å€¼
     */
    private String standardValue;
    /**
     * å†…控值
     */
    private String controlValue;
    /**
     * æ£€éªŒå€¼
     */
    private String testValue;
}
src/main/java/com/ruoyi/quality/mapper/QualityInspectMapper.java
@@ -19,6 +19,11 @@
    List<QualityInspect> qualityInspectExport(@Param("qualityInspect") QualityInspect qualityInspect);
    /**
     * æ ¹æ®ID列表查询检验记录(用于导出)
     */
    List<QualityInspect> qualityInspectExportByIds(@Param("ids") List<Long> ids, @Param("qualityInspect") QualityInspect qualityInspect);
    /**
     * æ ¹æ®ç”Ÿäº§ä¸»è¡¨ID批量删除过程检验
     */
    int deleteByProductMainIds(@Param("productMainIds") List<Long> productMainIds);
src/main/java/com/ruoyi/quality/service/IQualityInspectService.java
@@ -4,6 +4,7 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.quality.dto.QualityInspectDto;
import com.ruoyi.quality.dto.QualityInspectExportDTO;
import com.ruoyi.quality.pojo.QualityInspect;
import javax.servlet.http.HttpServletResponse;
@@ -19,6 +20,13 @@
    void qualityInspectExport(HttpServletResponse response, QualityInspect qualityInspect);
    /**
     * å¯¼å‡ºæ£€éªŒè®°å½•(支持选中导出和全部导出,包含检验参数)
     * @param response å“åº”
     * @param exportDTO å¯¼å‡ºå‚æ•°
     */
    void qualityInspectExportNew(HttpServletResponse response, QualityInspectExportDTO exportDTO);
    QualityInspectDto getDetailById(Integer id);
    int submit(QualityInspect qualityInspect);
src/main/java/com/ruoyi/quality/service/impl/QualityInspectExportHandle.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,277 @@
package com.ruoyi.quality.service.impl;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.quality.dto.QualityInspectExportDTO;
import com.ruoyi.quality.dto.QualityInspectExportVO;
import com.ruoyi.quality.mapper.QualityInspectMapper;
import com.ruoyi.quality.pojo.QualityInspect;
import com.ruoyi.quality.pojo.QualityInspectParam;
import com.ruoyi.quality.service.IQualityInspectParamService;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
 * è´¨é‡æ£€éªŒå¯¼å‡ºå¤„理类
 */
@Component
public class QualityInspectExportHandle {
    @Resource
    private QualityInspectMapper qualityInspectMapper;
    @Resource
    private IQualityInspectParamService qualityInspectParamService;
    /**
     * æŸ¥è¯¢æ£€éªŒè®°å½•(支持选中导出和全部导出)
     * @param exportDTO å¯¼å‡ºå‚æ•°
     * @return æ£€éªŒè®°å½•列表
     */
    public List<QualityInspect> queryInspectList(QualityInspectExportDTO exportDTO) {
        QualityInspect qualityInspect = new QualityInspect();
        qualityInspect.setInspectType(exportDTO.getInspectType());
        qualityInspect.setSupplier(exportDTO.getSupplier());
        qualityInspect.setProcess(exportDTO.getProcess());
        qualityInspect.setProductName(exportDTO.getProductName());
        qualityInspect.setEntryDateStart(exportDTO.getEntryDateStart());
        qualityInspect.setEntryDateEnd(exportDTO.getEntryDateEnd());
        if (!CollectionUtils.isEmpty(exportDTO.getIds())) {
            return qualityInspectMapper.qualityInspectExportByIds(exportDTO.getIds(), qualityInspect);
        } else {
            return qualityInspectMapper.qualityInspectExportByIds(null, qualityInspect);
        }
    }
    /**
     * æž„建导出数据(每个检验参数一行)
     * åŒä¸€æ£€éªŒè®°å½•的多个参数行,只在第一行显示左侧基础信息,后续行留空
     * @param qualityInspects æ£€éªŒè®°å½•列表
     * @param inspectType æ£€éªŒç±»åž‹
     * @return å¯¼å‡ºæ•°æ®åˆ—表
     */
    public List<QualityInspectExportVO> buildExportData(List<QualityInspect> qualityInspects, Integer inspectType) {
        if (CollectionUtils.isEmpty(qualityInspects)) {
            return new ArrayList<>();
        }
        // èŽ·å–æ‰€æœ‰æ£€éªŒè®°å½•çš„ID,批量查询检验参数
        List<Long> inspectIds = qualityInspects.stream().map(QualityInspect::getId).collect(Collectors.toList());
        List<QualityInspectParam> allParams = qualityInspectParamService.list(
            Wrappers.<QualityInspectParam>lambdaQuery().in(QualityInspectParam::getInspectId, inspectIds)
        );
        // æŒ‰inspectId分组
        Map<Long, List<QualityInspectParam>> paramMap = allParams.stream()
            .collect(Collectors.groupingBy(QualityInspectParam::getInspectId));
        // æž„建导出数据:每个检验参数一行
        List<QualityInspectExportVO> exportList = new ArrayList<>();
        for (QualityInspect inspect : qualityInspects) {
            List<QualityInspectParam> params = paramMap.getOrDefault(inspect.getId(), new ArrayList<>());
            if (params.isEmpty()) {
                // æ²¡æœ‰æ£€éªŒå‚数,也输出一行
                QualityInspectExportVO vo = buildVO(inspect, null, inspectType, true);
                exportList.add(vo);
            } else {
                // æœ‰æ£€éªŒå‚数,每个参数一行,第一行显示基础信息,后续行左侧留空
                boolean isFirst = true;
                for (QualityInspectParam param : params) {
                    QualityInspectExportVO vo = buildVO(inspect, param, inspectType, isFirst);
                    exportList.add(vo);
                    isFirst = false;
                }
            }
        }
        return exportList;
    }
    /**
     * æž„建单行导出数据
     * @param inspect æ£€éªŒè®°å½•
     * @param param æ£€éªŒå‚数(可为null)
     * @param inspectType æ£€éªŒç±»åž‹
     * @param showBaseInfo æ˜¯å¦æ˜¾ç¤ºå·¦ä¾§åŸºç¡€ä¿¡æ¯ï¼ˆåŒä¸€æ£€éªŒè®°å½•的多行,只在第一行显示)
     */
    private QualityInspectExportVO buildVO(QualityInspect inspect, QualityInspectParam param, Integer inspectType, boolean showBaseInfo) {
        QualityInspectExportVO vo = new QualityInspectExportVO();
        // åªæœ‰ç¬¬ä¸€è¡Œæ˜¾ç¤ºå·¦ä¾§åŸºç¡€ä¿¡æ¯ï¼ŒåŽç»­è¡Œç•™ç©º
        if (showBaseInfo) {
            vo.setCheckTime(inspect.getCheckTime());
            vo.setCheckName(inspect.getCheckName());
            vo.setProductName(inspect.getProductName());
            vo.setModel(inspect.getModel());
            vo.setUnit(inspect.getUnit());
            vo.setQuantity(inspect.getQuantity());
            vo.setCheckCompany(inspect.getCheckCompany());
            vo.setCheckResult(inspect.getCheckResult());
            // è®¾ç½®è®¢å•号和供应商/工序
            if (inspectType == 0) {
                vo.setOrderNo(inspect.getPurchaseContractNo());
                vo.setSupplierOrProcess(inspect.getSupplier());
            } else if (inspectType == 1) {
                vo.setOrderNo(inspect.getWorkOrderNo());
                vo.setSupplierOrProcess(inspect.getProcess());
            } else {
                vo.setOrderNo(inspect.getWorkOrderNo());
                vo.setSupplierOrProcess("");
            }
        }
        // è®¾ç½®æ£€éªŒå‚数(每行都要显示)
        if (param != null) {
            vo.setParameterItem(param.getParameterItem());
            vo.setParamUnit(param.getUnit());
            vo.setStandardValue(param.getStandardValue());
            vo.setControlValue(param.getControlValue());
            vo.setTestValue(param.getTestValue());
        }
        return vo;
    }
    /**
     * å¯¼å‡ºExcel
     * @param response å“åº”
     * @param exportList å¯¼å‡ºæ•°æ®
     * @param inspectType æ£€éªŒç±»åž‹
     */
    public void exportExcel(HttpServletResponse response, List<QualityInspectExportVO> exportList, Integer inspectType) {
        try {
            Workbook workbook = new XSSFWorkbook();
            Sheet sheet = workbook.createSheet();
            // åˆ›å»ºæ ·å¼
            CellStyle headerStyle = createHeaderStyle(workbook);
            CellStyle dataStyle = createDataStyle(workbook);
            // æž„建表头
            Row headerRow = sheet.createRow(0);
            String[] headers = {"检测日期", "订单号", "供应商/工序", "检验员", "产品名称", "规格型号", "单位", "数量", "检测单位", "检测结果", "指标", "指标单位", "标准值", "内控值", "检验值"};
            for (int i = 0; i < headers.length; i++) {
                Cell cell = headerRow.createCell(i);
                cell.setCellValue(headers[i]);
                cell.setCellStyle(headerStyle);
            }
            // å¡«å……数据
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            int rowIndex = 1;
            for (QualityInspectExportVO vo : exportList) {
                Row dataRow = sheet.createRow(rowIndex++);
                createCell(dataRow, 0, vo.getCheckTime() != null ? sdf.format(vo.getCheckTime()) : "", dataStyle);
                createCell(dataRow, 1, vo.getOrderNo() != null ? vo.getOrderNo() : "", dataStyle);
                createCell(dataRow, 2, vo.getSupplierOrProcess() != null ? vo.getSupplierOrProcess() : "", dataStyle);
                createCell(dataRow, 3, vo.getCheckName() != null ? vo.getCheckName() : "", dataStyle);
                createCell(dataRow, 4, vo.getProductName() != null ? vo.getProductName() : "", dataStyle);
                createCell(dataRow, 5, vo.getModel() != null ? vo.getModel() : "", dataStyle);
                createCell(dataRow, 6, vo.getUnit() != null ? vo.getUnit() : "", dataStyle);
                createCell(dataRow, 7, vo.getQuantity() != null ? vo.getQuantity().toString() : "", dataStyle);
                createCell(dataRow, 8, vo.getCheckCompany() != null ? vo.getCheckCompany() : "", dataStyle);
                createCell(dataRow, 9, vo.getCheckResult() != null ? vo.getCheckResult() : "", dataStyle);
                createCell(dataRow, 10, vo.getParameterItem() != null ? vo.getParameterItem() : "", dataStyle);
                createCell(dataRow, 11, vo.getParamUnit() != null ? vo.getParamUnit() : "", dataStyle);
                createCell(dataRow, 12, vo.getStandardValue() != null ? vo.getStandardValue() : "", dataStyle);
                createCell(dataRow, 13, vo.getControlValue() != null ? vo.getControlValue() : "", dataStyle);
                createCell(dataRow, 14, vo.getTestValue() != null ? vo.getTestValue() : "", dataStyle);
            }
            // è®¾ç½®åˆ—宽
            for (int i = 0; i < headers.length; i++) {
                sheet.setColumnWidth(i, 15 * 256);
            }
            // å¯¼å‡ºæ–‡ä»¶å
            String fileName = getFileName(inspectType);
            // è¾“出
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".xlsx", "UTF-8"));
            OutputStream os = response.getOutputStream();
            workbook.write(os);
            os.flush();
            os.close();
            workbook.close();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("导出失败: " + e.getMessage());
        }
    }
    /**
     * åˆ›å»ºè¡¨å¤´æ ·å¼
     */
    private CellStyle createHeaderStyle(Workbook workbook) {
        CellStyle style = workbook.createCellStyle();
        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderTop(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        Font font = workbook.createFont();
        font.setBold(true);
        style.setFont(font);
        return style;
    }
    /**
     * åˆ›å»ºæ•°æ®æ ·å¼
     */
    private CellStyle createDataStyle(Workbook workbook) {
        CellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderTop(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        return style;
    }
    /**
     * åˆ›å»ºå•元格并设置值
     */
    private void createCell(Row row, int colIndex, String value, CellStyle style) {
        Cell cell = row.createCell(colIndex);
        cell.setCellValue(value);
        cell.setCellStyle(style);
    }
    /**
     * èŽ·å–å¯¼å‡ºæ–‡ä»¶å
     */
    private String getFileName(Integer inspectType) {
        if (inspectType == null) {
            return "检验导出";
        }
        switch (inspectType) {
            case 0:
                return "原材料检验导出";
            case 1:
                return "过程检验导出";
            case 2:
                return "出厂检验导出";
            default:
                return "检验导出";
        }
    }
}
src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
@@ -9,25 +9,24 @@
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
import com.ruoyi.common.utils.HackLoopTableRenderPolicy;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.procurementrecord.service.ProcurementRecordService;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.quality.dto.QualityInspectDto;
import com.ruoyi.quality.dto.QualityInspectExportDTO;
import com.ruoyi.quality.dto.QualityInspectExportVO;
import com.ruoyi.quality.mapper.QualityInspectMapper;
import com.ruoyi.quality.mapper.QualityTestStandardMapper;
import com.ruoyi.quality.mapper.QualityUnqualifiedMapper;
import com.ruoyi.quality.pojo.QualityInspect;
import com.ruoyi.quality.pojo.QualityInspectParam;
import com.ruoyi.quality.pojo.QualityUnqualified;
import com.ruoyi.quality.service.IQualityInspectParamService;
import com.ruoyi.quality.service.IQualityInspectService;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
@@ -47,13 +46,9 @@
    private IQualityInspectParamService qualityInspectParamService;
    private QualityTestStandardMapper qualityTestStandardMapper;
    private QualityUnqualifiedMapper qualityUnqualifiedMapper;
    private SalesLedgerProductMapper salesLedgerProductMapper;
    private ProcurementRecordService procurementRecordService;
    private QualityInspectExportHandle qualityInspectExportHandle;
    @Override
    public int add(QualityInspectDto qualityInspectDto) {
@@ -78,15 +73,12 @@
        return qualityInspectDto;
    }
    //提交
    @Override
    public int submit(QualityInspect inspect) {
        QualityInspect qualityInspect = qualityInspectMapper.selectById(inspect.getId());
        //提交前必须判断是否合格
        if (ObjectUtils.isNull(qualityInspect.getCheckResult())) {
            throw new RuntimeException("请先判断是否合格");
        }
        /*判断不合格*/
        if (qualityInspect.getCheckResult().equals("不合格")) {
            QualityUnqualified qualityUnqualified = new QualityUnqualified();
            BeanUtils.copyProperties(qualityInspect, qualityUnqualified);
@@ -98,13 +90,14 @@
            qualityUnqualifiedMapper.insert(qualityUnqualified);
        } else {
            //合格直接入库
            stockUtils.addStock(qualityInspect.getProductModelId(), qualityInspect.getQuantity(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode(), qualityInspect.getId(), "-", "-", "-");
            if (qualityInspect.getInspectType() == 2 || qualityInspect.getInspectType() == 0) {
                stockUtils.addStock(qualityInspect.getProductModelId(), qualityInspect.getQuantity(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode(), qualityInspect.getId(), "-", "-", "-");
            }
        }
        qualityInspect.setInspectState(1);//已提交
        return qualityInspectMapper.updateById(qualityInspect);
    }
    /*生成检验报告*/
    @Override
    public void down(HttpServletResponse response, QualityInspect qualityInspect) {
        QualityInspect inspect = qualityInspectMapper.selectById(qualityInspect.getId());
@@ -140,11 +133,9 @@
        try {
            response.setContentType("application/msword");
            String fileName = URLEncoder.encode(
                    "检验报告", "UTF-8");
            String fileName = URLEncoder.encode("检验报告", "UTF-8");
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
            response.setHeader("Content-disposition",
                    "attachment;filename=" + fileName + ".docx");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".docx");
            OutputStream os = response.getOutputStream();
            template.write(os);
            os.flush();
@@ -190,8 +181,25 @@
                util.exportExcel(response, qualityInspects, "出厂检验导出");
                break;
        }
    }
    /**
     * å¯¼å‡ºæ£€éªŒè®°å½•(支持选中导出和全部导出,包含检验参数)
     * æ¯ä¸ªæ£€éªŒå‚数一行(一个检验记录展开成多行)
     */
    @Override
    public void qualityInspectExportNew(HttpServletResponse response, QualityInspectExportDTO exportDTO) {
        // 1. æŸ¥è¯¢æ£€éªŒè®°å½•
        List<QualityInspect> qualityInspects = qualityInspectExportHandle.queryInspectList(exportDTO);
        if (CollectionUtils.isEmpty(qualityInspects)) {
            throw new RuntimeException("没有可导出的数据");
        }
        // 2. æž„建导出数据(每个检验参数一行)
        List<QualityInspectExportVO> exportList = qualityInspectExportHandle.buildExportData(qualityInspects, exportDTO.getInspectType());
        // 3. å¯¼å‡ºExcel
        qualityInspectExportHandle.exportExcel(response, exportList, exportDTO.getInspectType());
    }
}
src/main/resources/mapper/collaborativeApproval/RulesRegulationsManagementMapper.xml
@@ -13,7 +13,7 @@
    </resultMap>
    <select id="listPage" resultMap="RulesRegulationsManagementDTOMap">
        select rrm.*, su.user_name as create_user_name
        select rrm.*, su.nick_name as create_user_name
        from rules_regulations_management rrm
        left join sys_user su on rrm.create_user = su.user_id
        <where>
src/main/resources/mapper/device/DeviceRepairMapper.xml
@@ -8,10 +8,11 @@
    <select id="queryPage" resultType="com.ruoyi.device.dto.DeviceRepairDto">
        select dr.id,
               dr.device_ledger_id,
                dr.repair_time,
                dr.repair_name,
                dr.remark,
                dr.repair_project,
                dr.repair_time_start as repairTimeStart,
                dr.repair_time_end as repairTimeEnd,
                dr.maintenance_name,
                dr.maintenance_time,
                dr.maintenance_result,
@@ -45,22 +46,26 @@
            <if test="deviceRepairDto.maintenanceName != null">
                and dr.maintenance_name like concat('%',#{deviceRepairDto.maintenanceName},'%')
            </if>
            <if test="deviceRepairDto.repairTimeStr != null and deviceRepairDto.repairTimeStr != '' ">
                and dr.repair_time like concat('%',#{deviceRepairDto.repairTimeStr},'%')
            <if test="deviceRepairDto.repairTimeStart != null">
                and dr.repair_time_start &gt;= #{deviceRepairDto.repairTimeStart}
            </if>
            <if test="deviceRepairDto.repairTimeEnd != null">
                and dr.repair_time_end &lt;= #{deviceRepairDto.repairTimeEnd}
            </if>
            <if test="deviceRepairDto.maintenanceTimeStr != null and deviceRepairDto.maintenanceTimeStr != '' ">
                and dr.maintenance_time like concat('%',#{deviceRepairDto.maintenanceTimeStr},'%')
            </if>
        </where>
        order by dr.status asc, dr.create_time desc
    </select>
    <select id="detailById" resultType="com.ruoyi.device.dto.DeviceRepairDto">
        select dr.id,
               dr.device_ledger_id,
               dr.repair_time,
               dr.repair_name,
               dr.remark,
               dr.repair_project,
               dr.repair_time_start as repairTimeStart,
               dr.repair_time_end as repairTimeEnd,
               dr.maintenance_name,
               dr.maintenance_time,
               dr.maintenance_result,
src/main/resources/mapper/production/ProductWorkOrderMapper.xml
@@ -67,7 +67,8 @@
            ROUND(pwo.complete_quantity / pwo.plan_quantity * 100, 2) AS completionStatus,
            sum(ppo.scrap_qty) scrapQty,
            pp.device_id,
            pp.device_name
            pp.device_name,
            t8.product_name as final_product_model
        FROM
            product_work_order pwo
                LEFT JOIN product_process_route_item ppri ON ppri.id = pwo.product_process_route_item_id
@@ -77,6 +78,8 @@
                LEFT JOIN product_process pp ON pp.id = ppri.process_id
                LEFT JOIN product_model pm ON pm.id = ppri.product_model_id
                LEFT JOIN product p ON p.id = pm.product_id
                left join product_model t7 on t7.id = po.product_model_id
                left join product as t8 on t7.product_id = t8.id
        WHERE pwo.id = #{id}
        GROUP BY pwo.id, pwo.product_process_route_item_id, pwo.create_time, pwo.update_time, pwo.work_order_no, pwo.plan_start_time, pwo.plan_end_time, pwo.actual_start_time, pwo.actual_end_time, pwo.status, pwo.tenant_id, pwo.plan_quantity, pwo.product_order_id, pwo.complete_quantity,
                 pp.device_id,
src/main/resources/mapper/purchase/InvoicePurchaseMapper.xml
@@ -30,88 +30,121 @@
        sl.sales_contract_no
    </select>
    <select id="listVat" resultType="com.ruoyi.purchase.dto.VatDto">
        select *
        from (SELECT
                  COALESCE(a1.month, a2.month) AS month,
                  IFNULL(a1.tax_amount, 0) AS j_tax_amount,
                  IFNULL(a2.x_tax_amount, 0) AS x_tax_amount
              FROM (
                       -- ç¬¬ä¸€ä¸ªæŸ¥è¯¢ï¼šæ¥è‡ª invoice_ledger çš„税额
                       SELECT
                           DATE_FORMAT(il.invoice_date, '%Y-%m') AS month,
                           ROUND(SUM(pr.invoice_amount - pr.invoice_amount / (1 + pr.tax_rate / 100)), 2) AS tax_amount
                       FROM invoice_ledger il
                                LEFT JOIN invoice_registration_product pr ON pr.id = il.invoice_registration_product_id
                       WHERE il.invoice_no IS NOT NULL
                         AND invoice_type = '增专票'
                         AND DATE_FORMAT(il.invoice_date, '%Y-%m') IS NOT NULL  -- æ–°å¢žï¼šè¿‡æ»¤month为NULL的情
                       GROUP BY DATE_FORMAT(il.invoice_date, '%Y-%m')
                   ) a1
                       LEFT JOIN (
                  -- ç¬¬äºŒä¸ªæŸ¥è¯¢ï¼šæ¥è‡ª ticket_registration çš„税额
                  SELECT
                      DATE_FORMAT(a.issue_date, '%Y-%m') AS month,
                      SUM(a.invoice_amount) AS x_tax_amount
                  FROM (
                           SELECT DISTINCT pr.id,
                                           tr.issue_date,
                                           ROUND(pr.tickets_amount / (1 + pr.tax_rate / 100), 2) AS un_tickets_price,
                                           ROUND(pr.tickets_amount - pr.tickets_amount / (1 + pr.tax_rate / 100), 2) AS invoice_amount
                           FROM product_record pr
                                    LEFT JOIN purchase_ledger pl ON pl.id = pr.purchase_ledger_id
                                    LEFT JOIN sales_ledger sl ON sl.id = pl.sales_ledger_id
                                    LEFT JOIN ticket_registration tr ON tr.purchase_ledger_id = pl.id
                                    LEFT JOIN product_model pm ON pm.id = pr.product_model_id
                           WHERE type = 2
                             AND tr.invoice_number IS NOT NULL
                       ) a
                  GROUP BY DATE_FORMAT(a.issue_date, '%Y-%m')
              ) a2 ON a1.month = a2.month
        <!--        select *-->
        <!--        from (SELECT-->
        <!--                  COALESCE(a1.month, a2.month) AS month,-->
        <!--                  IFNULL(a1.tax_amount, 0) AS j_tax_amount,-->
        <!--                  IFNULL(a2.x_tax_amount, 0) AS x_tax_amount-->
        <!--              FROM (-->
        <!--                       &#45;&#45; ç¬¬ä¸€ä¸ªæŸ¥è¯¢ï¼šæ¥è‡ª invoice_ledger çš„税额-->
        <!--                       SELECT-->
        <!--                           DATE_FORMAT(il.invoice_date, '%Y-%m') AS month,-->
        <!--                           ROUND(SUM(pr.invoice_amount - pr.invoice_amount / (1 + pr.tax_rate / 100)), 2) AS tax_amount-->
        <!--                       FROM invoice_ledger il-->
        <!--                                LEFT JOIN invoice_registration_product pr ON pr.id = il.invoice_registration_product_id-->
        <!--                       WHERE il.invoice_no IS NOT NULL-->
        <!--                         AND invoice_type = '增专票'-->
        <!--                         AND DATE_FORMAT(il.invoice_date, '%Y-%m') IS NOT NULL  &#45;&#45; æ–°å¢žï¼šè¿‡æ»¤month为NULL的情-->
        <!--                       GROUP BY DATE_FORMAT(il.invoice_date, '%Y-%m')-->
        <!--                   ) a1-->
        <!--                       LEFT JOIN (-->
        <!--                  &#45;&#45; ç¬¬äºŒä¸ªæŸ¥è¯¢ï¼šæ¥è‡ª ticket_registration çš„税额-->
        <!--                  SELECT-->
        <!--                      DATE_FORMAT(a.issue_date, '%Y-%m') AS month,-->
        <!--                      SUM(a.invoice_amount) AS x_tax_amount-->
        <!--                  FROM (-->
        <!--                           SELECT DISTINCT pr.id,-->
        <!--                                           tr.issue_date,-->
        <!--                                           ROUND(pr.tickets_amount / (1 + pr.tax_rate / 100), 2) AS un_tickets_price,-->
        <!--                                           ROUND(pr.tickets_amount - pr.tickets_amount / (1 + pr.tax_rate / 100), 2) AS invoice_amount-->
        <!--                           FROM product_record pr-->
        <!--                                    LEFT JOIN purchase_ledger pl ON pl.id = pr.purchase_ledger_id-->
        <!--                                    LEFT JOIN sales_ledger sl ON sl.id = pl.sales_ledger_id-->
        <!--                                    LEFT JOIN ticket_registration tr ON tr.purchase_ledger_id = pl.id-->
        <!--                                    LEFT JOIN product_model pm ON pm.id = pr.product_model_id-->
        <!--                           WHERE type = 2-->
        <!--                             AND tr.invoice_number IS NOT NULL-->
        <!--                       ) a-->
        <!--                  GROUP BY DATE_FORMAT(a.issue_date, '%Y-%m')-->
        <!--              ) a2 ON a1.month = a2.month-->
              UNION ALL
        <!--              UNION ALL-->
              SELECT
                  COALESCE(a1.month, a2.month) AS month,
                  IFNULL(a1.tax_amount, 0) AS tax_amount,
                  IFNULL(a2.x_tax_amount, 0) AS x_tax_amount
              FROM (
                       -- ç¬¬äºŒä¸ªæŸ¥è¯¢ï¼šæ¥è‡ª ticket_registration çš„税额(反过来补全没有匹配到的)
                       SELECT
                           DATE_FORMAT(a.issue_date, '%Y-%m') AS month,
                           SUM(a.invoice_amount) AS x_tax_amount
                       FROM (
                                SELECT DISTINCT pr.id,
                                                tr.issue_date,
                                                ROUND(pr.tickets_amount / (1 + pr.tax_rate / 100), 2) AS un_tickets_price,
                                                ROUND(pr.tickets_amount - pr.tickets_amount / (1 + pr.tax_rate / 100), 2) AS invoice_amount
                                FROM product_record pr
                                         LEFT JOIN purchase_ledger pl ON pl.id = pr.purchase_ledger_id
                                         LEFT JOIN sales_ledger sl ON sl.id = pl.sales_ledger_id
                                         LEFT JOIN ticket_registration tr ON tr.purchase_ledger_id = pl.id
                                         LEFT JOIN product_model pm ON pm.id = pr.product_model_id
                                WHERE type = 2
                                  AND tr.invoice_number IS NOT NULL
                            ) a
                       GROUP BY DATE_FORMAT(a.issue_date, '%Y-%m')
                   ) a2
                       LEFT JOIN (
                  -- ç¬¬ä¸€ä¸ªæŸ¥è¯¢ï¼šæ¥è‡ª invoice_ledger çš„税额
                  SELECT
                      DATE_FORMAT(il.invoice_date, '%Y-%m') AS month,
                      ROUND(SUM(pr.invoice_amount - pr.invoice_amount / (1 + pr.tax_rate / 100)), 2) AS tax_amount
                  FROM invoice_ledger il
                           LEFT JOIN invoice_registration_product pr ON pr.id = il.invoice_registration_product_id
                  WHERE il.invoice_no IS NOT NULL
                    AND invoice_type = '增专票'
                    AND DATE_FORMAT(il.invoice_date, '%Y-%m') IS NOT NULL  -- æ–°å¢žï¼šè¿‡æ»¤month为NULL的情
                  GROUP BY DATE_FORMAT(il.invoice_date, '%Y-%m')
              ) a1 ON a1.month = a2.month
              WHERE a1.month IS NULL
              ORDER BY month
             )as a
        <!--              SELECT-->
        <!--                  COALESCE(a1.month, a2.month) AS month,-->
        <!--                  IFNULL(a1.tax_amount, 0) AS tax_amount,-->
        <!--                  IFNULL(a2.x_tax_amount, 0) AS x_tax_amount-->
        <!--              FROM (-->
        <!--                       &#45;&#45; ç¬¬äºŒä¸ªæŸ¥è¯¢ï¼šæ¥è‡ª ticket_registration çš„税额(反过来补全没有匹配到的)-->
        <!--                       SELECT-->
        <!--                           DATE_FORMAT(a.issue_date, '%Y-%m') AS month,-->
        <!--                           SUM(a.invoice_amount) AS x_tax_amount-->
        <!--                       FROM (-->
        <!--                                SELECT DISTINCT pr.id,-->
        <!--                                                tr.issue_date,-->
        <!--                                                ROUND(pr.tickets_amount / (1 + pr.tax_rate / 100), 2) AS un_tickets_price,-->
        <!--                                                ROUND(pr.tickets_amount - pr.tickets_amount / (1 + pr.tax_rate / 100), 2) AS invoice_amount-->
        <!--                                FROM product_record pr-->
        <!--                                         LEFT JOIN purchase_ledger pl ON pl.id = pr.purchase_ledger_id-->
        <!--                                         LEFT JOIN sales_ledger sl ON sl.id = pl.sales_ledger_id-->
        <!--                                         LEFT JOIN ticket_registration tr ON tr.purchase_ledger_id = pl.id-->
        <!--                                         LEFT JOIN product_model pm ON pm.id = pr.product_model_id-->
        <!--                                WHERE type = 2-->
        <!--                                  AND tr.invoice_number IS NOT NULL-->
        <!--                            ) a-->
        <!--                       GROUP BY DATE_FORMAT(a.issue_date, '%Y-%m')-->
        <!--                   ) a2-->
        <!--                       LEFT JOIN (-->
        <!--                  &#45;&#45; ç¬¬ä¸€ä¸ªæŸ¥è¯¢ï¼šæ¥è‡ª invoice_ledger çš„税额-->
        <!--                  SELECT-->
        <!--                      DATE_FORMAT(il.invoice_date, '%Y-%m') AS month,-->
        <!--                      ROUND(SUM(pr.invoice_amount - pr.invoice_amount / (1 + pr.tax_rate / 100)), 2) AS tax_amount-->
        <!--                  FROM invoice_ledger il-->
        <!--                           LEFT JOIN invoice_registration_product pr ON pr.id = il.invoice_registration_product_id-->
        <!--                  WHERE il.invoice_no IS NOT NULL-->
        <!--                    AND invoice_type = '增专票'-->
        <!--                    AND DATE_FORMAT(il.invoice_date, '%Y-%m') IS NOT NULL  &#45;&#45; æ–°å¢žï¼šè¿‡æ»¤month为NULL的情-->
        <!--                  GROUP BY DATE_FORMAT(il.invoice_date, '%Y-%m')-->
        <!--              ) a1 ON a1.month = a2.month-->
        <!--              WHERE a1.month IS NULL-->
        <!--              ORDER BY month-->
        <!--             )as a-->
        <!--        <where>-->
        <!--            a.month is not null-->
        <!--            <if test="month != null">-->
        <!--                and a.month = #{month}-->
        <!--            </if>-->
        <!--        </where>-->
        select * from (
        SELECT
        month,
        SUM(sales_tax_amount) AS j_tax_amount,
        SUM(purchase_tax_amount) AS x_tax_amount
        FROM (
        SELECT
        DATE_FORMAT(entry_date, '%Y-%m') AS month,
        ROUND(SUM(contract_amount * 0.13), 2) AS sales_tax_amount,
        0 AS purchase_tax_amount
        FROM sales_ledger
        WHERE entry_date IS NOT NULL
        GROUP BY DATE_FORMAT(entry_date, '%Y-%m')
        UNION ALL
        SELECT
        DATE_FORMAT(entry_date, '%Y-%m') AS month,
        0 AS sales_tax_amount,
        ROUND(SUM(contract_amount * 0.26), 2) AS purchase_tax_amount
        FROM purchase_ledger
        WHERE entry_date IS NOT NULL
        GROUP BY DATE_FORMAT(entry_date, '%Y-%m')
        ) t
        GROUP BY month
        ORDER BY month
        ) a
        <where>
            a.month is not null
            <if test="month != null">
            <if test="month != null and month != ''">
                and a.month = #{month}
            </if>
        </where>
src/main/resources/mapper/quality/QualityInspectMapper.xml
@@ -43,7 +43,11 @@
        <if test="qualityInspect.entryDateEnd != null and qualityInspect.entryDateEnd != '' ">
            AND qi.check_time &lt;= DATE_FORMAT(#{qualityInspect.entryDateEnd},'%Y-%m-%d')
        </if>
        ORDER BY qi.check_time DESC
        ORDER BY
        CASE WHEN qi.check_result IS NULL OR qi.check_result = '' THEN 0 ELSE 1 END,
        inspect_state,
        qi.check_time DESC,
        qi.id DESC
    </select>
    <select id="qualityInspectExport" resultType="com.ruoyi.quality.pojo.QualityInspect">
@@ -66,6 +70,52 @@
        </if>
    </select>
    <select id="qualityInspectExportByIds" resultType="com.ruoyi.quality.pojo.QualityInspect">
        SELECT
        qi.*,
        <choose>
            <when test="qualityInspect.inspectType == 0">
                pl.purchase_contract_number as purchase_contract_no
            </when>
            <otherwise>
                pwo.work_order_no
            </otherwise>
        </choose>
        FROM quality_inspect qi
        <choose>
            <when test="qualityInspect.inspectType == 0">
                LEFT JOIN purchase_ledger pl ON pl.id = qi.purchase_ledger_id
            </when>
            <otherwise>
                LEFT JOIN production_product_main ppm ON qi.product_main_id = ppm.id
                LEFT JOIN product_work_order pwo ON ppm.work_order_id = pwo.id
            </otherwise>
        </choose>
        WHERE qi.inspect_type=#{qualityInspect.inspectType}
        <if test="ids != null and ids.size() > 0">
            AND qi.id IN
            <foreach collection="ids" item="id" open="(" separator="," close=")">
                #{id}
            </foreach>
        </if>
        <if test="qualityInspect.supplier != null and qualityInspect.supplier != '' ">
            AND qi.supplier like concat('%',#{qualityInspect.supplier},'%')
        </if>
        <if test="qualityInspect.process != null and qualityInspect.process != '' ">
            AND qi.process like concat('%',#{qualityInspect.process},'%')
        </if>
        <if test="qualityInspect.productName != null and qualityInspect.productName != '' ">
            AND qi.product_name like concat('%',#{qualityInspect.productName},'%')
        </if>
        <if test="qualityInspect.entryDateStart != null and qualityInspect.entryDateStart != '' ">
            AND qi.check_time &gt;= DATE_FORMAT(#{qualityInspect.entryDateStart},'%Y-%m-d')
        </if>
        <if test="qualityInspect.entryDateEnd != null and qualityInspect.entryDateEnd != '' ">
            AND qi.check_time &lt;= DATE_FORMAT(#{qualityInspect.entryDateEnd},'%Y-%m-d')
        </if>
        ORDER BY qi.check_time DESC
    </select>
    <delete id="deleteByProductMainIds">
        DELETE FROM quality_inspect
        WHERE product_main_id IN