refactor(inspection-order): 1.检验委托单绑定机制支持多次下单
2.合格率统计口径调整
3.外购铜导体推送入库MES增加米重
4.报告英文字段调整
已添加9个文件
已修改15个文件
863 ■■■■■ 文件已修改
cnas-process/src/main/java/com/ruoyi/process/controller/InspectionOrderController.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cnas-process/src/main/java/com/ruoyi/process/dto/InspectionOrderBindingDto.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cnas-process/src/main/java/com/ruoyi/process/dto/InspectionOrderDto.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cnas-process/src/main/java/com/ruoyi/process/listener/InspectionOrderBindingDeleteListener.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cnas-process/src/main/java/com/ruoyi/process/mapper/InspectionOrderAttachmentMapper.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cnas-process/src/main/java/com/ruoyi/process/mapper/InspectionOrderBindingMapper.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cnas-process/src/main/java/com/ruoyi/process/mapper/InspectionOrderMapper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cnas-process/src/main/java/com/ruoyi/process/pojo/InspectionOrder.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cnas-process/src/main/java/com/ruoyi/process/pojo/InspectionOrderAttachment.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cnas-process/src/main/java/com/ruoyi/process/pojo/InspectionOrderBinding.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cnas-process/src/main/java/com/ruoyi/process/pojo/InspectionOrderDetail.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cnas-process/src/main/java/com/ruoyi/process/service/InspectionOrderService.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cnas-process/src/main/java/com/ruoyi/process/service/impl/InspectionOrderServiceImpl.java 379 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cnas-process/src/main/resources/mapper/InspectionOrderAttachmentMapper.xml 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cnas-process/src/main/resources/mapper/InspectionOrderBindingMapper.xml 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cnas-process/src/main/resources/mapper/InspectionOrderMapper.xml 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
inspect-server/src/main/java/com/ruoyi/inspect/aspect/MoveLocationAfterPushMesStockAspect.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
inspect-server/src/main/java/com/ruoyi/inspect/controller/InsOrderController.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
inspect-server/src/main/java/com/ruoyi/inspect/dto/InsPlaceOrderDto.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
inspect-server/src/main/java/com/ruoyi/inspect/event/InsOrderDeletingEvent.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
inspect-server/src/main/java/com/ruoyi/inspect/service/InsOrderService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
inspect-server/src/main/resources/mapper/DataAnalysisMapper.xml 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
inspect-server/src/main/resources/static/report-template.docx 补丁 | 查看 | 原始文档 | blame | 历史
cnas-process/src/main/java/com/ruoyi/process/controller/InspectionOrderController.java
@@ -5,6 +5,8 @@
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.inspect.dto.InsPlaceOrderDto;
import com.ruoyi.process.dto.InspectionOrderDto;
import com.ruoyi.process.dto.InspectionOrderBindingDto;
import com.ruoyi.process.pojo.InspectionOrderAttachment;
import com.ruoyi.process.pojo.InspectionOrder;
import com.ruoyi.process.service.InspectionOrderService;
import io.swagger.annotations.Api;
@@ -15,6 +17,7 @@
import org.springframework.security.access.prepost.PreAuthorize;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
 * <p>
@@ -57,6 +60,26 @@
    @GetMapping("/pageUnboundInspectionOrder")
    public Result<IPage<InspectionOrder>> pageUnboundInspectionOrder(InspectionOrder inspectionOrder, Page page) {
        return Result.success(inspectionOrderService.pageUnboundInspectionOrder(page, inspectionOrder));
    }
    @ApiOperation(value = "查询可重复绑定的检验委托单")
    @GetMapping("/pageSelectableInspectionOrder")
    public Result<IPage<InspectionOrder>> pageSelectableInspectionOrder(InspectionOrder inspectionOrder, Page page) {
        return Result.success(inspectionOrderService.pageUnboundInspectionOrder(page, inspectionOrder));
    }
    @ApiOperation(value = "查询检验委托单的历次下单记录")
    @GetMapping("/pageInspectionOrderBindings")
    public Result<IPage<InspectionOrderBindingDto>> pageInspectionOrderBindings(Page page, Integer inspectionOrderId,
                                                                                 Boolean includeDeleted) {
        return Result.success(inspectionOrderService.pageInspectionOrderBindings(page, inspectionOrderId, includeDeleted));
    }
    @ApiOperation(value = "查询检验委托单附件")
    @GetMapping("/listInspectionOrderAttachments")
    public Result<List<InspectionOrderAttachment>> listInspectionOrderAttachments(Integer inspectionOrderId,
                                                                                   Long bindingId) {
        return Result.success(inspectionOrderService.listInspectionOrderAttachments(inspectionOrderId, bindingId));
    }
    @ApiOperation(value = "获取成品下单关联的委托单信息")
@@ -119,13 +142,28 @@
        return Result.success(inspectionOrderService.uploadInspectionOrderFile(file, inspectionOrderId));
    }
    @ApiOperation(value = "按下单记录上传委托单附件")
    @PreAuthorize("@ss.hasPermi('add:insOrder')")
    @PostMapping("/uploadInspectionOrderBindingFile")
    public Result uploadInspectionOrderBindingFile(MultipartFile file, Long bindingId) {
        return Result.success(inspectionOrderService.uploadInspectionOrderBindingFile(file, bindingId));
    }
    @ApiOperation(value = "重试同步正式报告到检验委托单")
    @PreAuthorize("@ss.hasPermi('add:insOrder')")
    @PostMapping("/retryInspectionOrderReportSync")
    public Result retryInspectionOrderReportSync(Integer insReportId) {
        inspectionOrderService.syncReportFile(insReportId);
        return Result.success(true);
    }
    /**
     * å¯¼å‡ºæ£€éªŒå§”托单
     * @return
     */
    @ApiOperation(value = "导出检验委托单")
    @GetMapping("/exportInspectionOrder")
    public void exportInspectionOrder(Integer inspectionOrderId, HttpServletResponse response){
        inspectionOrderService.exportInspectionOrder(inspectionOrderId, response);
    public void exportInspectionOrder(Integer inspectionOrderId, Long bindingId, HttpServletResponse response){
        inspectionOrderService.exportInspectionOrder(inspectionOrderId, bindingId, response);
    }
}
cnas-process/src/main/java/com/ruoyi/process/dto/InspectionOrderBindingDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,25 @@
package com.ruoyi.process.dto;
import com.ruoyi.process.pojo.InspectionOrderBinding;
import lombok.Data;
import io.swagger.annotations.ApiModelProperty;
/**
 * å§”托单下的单次成品下单记录。
 */
@Data
public class InspectionOrderBindingDto extends InspectionOrderBinding {
    @ApiModelProperty("委托单号")
    private String inspectionOrderCode;
    @ApiModelProperty("成品订单委托编号")
    private String entrustCode;
    @ApiModelProperty("成品下单状态")
    private Integer orderState;
    @ApiModelProperty("检验结果")
    private Integer insResult;
    @ApiModelProperty("检验进度")
    private String insProgress;
    @ApiModelProperty("已批准正式报告数量")
    private Integer reportCount;
}
cnas-process/src/main/java/com/ruoyi/process/dto/InspectionOrderDto.java
@@ -20,6 +20,9 @@
    @ApiModelProperty("关联状态:0未绑定,1已绑定")
    private Integer bindingStatus;
    @ApiModelProperty("有效下单绑定数量")
    private Integer bindingCount;
    @ApiModelProperty("成品下单状态")
    private Integer orderState;
cnas-process/src/main/java/com/ruoyi/process/listener/InspectionOrderBindingDeleteListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
package com.ruoyi.process.listener;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.inspect.event.InsOrderDeletingEvent;
import com.ruoyi.process.mapper.InspectionOrderBindingMapper;
import com.ruoyi.process.pojo.InspectionOrderBinding;
import lombok.AllArgsConstructor;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
/**
 * åœ¨è®¢å•删除事务内保留委托单绑定追溯记录。
 */
@Component
@AllArgsConstructor
public class InspectionOrderBindingDeleteListener {
    private final InspectionOrderBindingMapper bindingMapper;
    @EventListener
    public void markOrderDeleted(InsOrderDeletingEvent event) {
        bindingMapper.update(null, Wrappers.<InspectionOrderBinding>lambdaUpdate()
                .eq(InspectionOrderBinding::getInsOrderId, event.getInsOrderId())
                .set(InspectionOrderBinding::getOrderDeleted, 1)
                .set(InspectionOrderBinding::getUpdateUser, event.getOperatorId())
                .set(InspectionOrderBinding::getUpdateTime, event.getOperateTime()));
    }
}
cnas-process/src/main/java/com/ruoyi/process/mapper/InspectionOrderAttachmentMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package com.ruoyi.process.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.process.pojo.InspectionOrderAttachment;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface InspectionOrderAttachmentMapper extends BaseMapper<InspectionOrderAttachment> {
    List<InspectionOrderAttachment> selectVisibleAttachments(@Param("inspectionOrderId") Integer inspectionOrderId,
                                                             @Param("bindingId") Long bindingId);
}
cnas-process/src/main/java/com/ruoyi/process/mapper/InspectionOrderBindingMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
package com.ruoyi.process.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.process.dto.InspectionOrderBindingDto;
import com.ruoyi.process.pojo.InspectionOrderBinding;
import org.apache.ibatis.annotations.Param;
public interface InspectionOrderBindingMapper extends BaseMapper<InspectionOrderBinding> {
    Integer lockRequestUser(@Param("userId") Integer userId);
    InspectionOrderBinding selectByRequest(@Param("userId") Integer userId, @Param("requestId") String requestId);
    InspectionOrderBinding selectByOrderIdForUpdate(@Param("insOrderId") Integer insOrderId);
    IPage<InspectionOrderBindingDto> pageBindings(Page<?> page,
                                                   @Param("inspectionOrderId") Integer inspectionOrderId,
                                                   @Param("includeDeleted") Boolean includeDeleted);
}
cnas-process/src/main/java/com/ruoyi/process/mapper/InspectionOrderMapper.java
@@ -34,4 +34,6 @@
     */
    IPage<InspectionOrder> pageUnboundInspectionOrder(Page page, @Param("ew") QueryWrapper<InspectionOrder> ew);
    InspectionOrder selectByIdForUpdate(@Param("inspectionOrderId") Integer inspectionOrderId);
}
cnas-process/src/main/java/com/ruoyi/process/pojo/InspectionOrder.java
@@ -23,6 +23,7 @@
@ApiModel(value = "InspectionOrder对象", description = "检验委托单")
public class InspectionOrder {
    @ApiModelProperty("检验委托单ID")
    @TableId(value = "inspection_order_id", type = IdType.AUTO)
    private Integer inspectionOrderId;
cnas-process/src/main/java/com/ruoyi/process/pojo/InspectionOrderAttachment.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
package com.ruoyi.process.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.time.LocalDateTime;
/**
 * æ£€éªŒå§”托单附件,按具体下单或历史委托单归档。
 */
@Data
@TableName("cnas_inspection_order_attachment")
@ApiModel(value = "InspectionOrderAttachment对象", description = "检验委托单下单附件")
public class InspectionOrderAttachment {
    @ApiModelProperty("附件ID")
    @TableId(type = IdType.AUTO)
    private Long id;
    @ApiModelProperty("检验委托单ID")
    private Integer inspectionOrderId;
    @ApiModelProperty("绑定记录ID")
    private Long bindingId;
    @ApiModelProperty("正式报告ID")
    private Integer insReportId;
    @ApiModelProperty("历史委托单ID,用于迁移去重")
    private Integer legacyInspectionOrderId;
    @ApiModelProperty("来源类型:LEGACY、MANUAL、REPORT")
    private String sourceType;
    @ApiModelProperty("显示文件名")
    private String fileName;
    @ApiModelProperty("文件访问地址")
    private String fileUrl;
    @ApiModelProperty("创建人ID")
    private Integer createUser;
    @ApiModelProperty("创建时间")
    private LocalDateTime createTime;
    @ApiModelProperty("修改时间")
    private LocalDateTime updateTime;
}
cnas-process/src/main/java/com/ruoyi/process/pojo/InspectionOrderBinding.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,52 @@
package com.ruoyi.process.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
 * æ£€éªŒå§”托单与成品订单的一对多绑定记录。
 */
@Data
@TableName("cnas_inspection_order_binding")
@ApiModel(value = "InspectionOrderBinding对象", description = "检验委托单与成品订单绑定关系")
public class InspectionOrderBinding {
    @ApiModelProperty("绑定记录ID")
    @TableId(type = IdType.AUTO)
    private Long id;
    @ApiModelProperty("检验委托单ID")
    private Integer inspectionOrderId;
    @ApiModelProperty("成品订单ID")
    private Integer insOrderId;
    @ApiModelProperty("来源类型:LEGACY历史迁移,NEW新下单")
    private String sourceType;
    @ApiModelProperty("客户端下单请求号")
    private String requestId;
    @ApiModelProperty("首次请求业务内容SHA256")
    private String requestHash;
    @ApiModelProperty("首次请求用户ID")
    private Integer requestUserId;
    @ApiModelProperty("领样人ID")
    private Integer sampleTakerUserId;
    @ApiModelProperty("领样人名称快照")
    private String sampleTakerUser;
    @ApiModelProperty("领样日期")
    private LocalDate sampleData;
    @ApiModelProperty("订单是否已删除:0否,1是")
    private Integer orderDeleted;
    @ApiModelProperty("创建人ID")
    private Integer createUser;
    @ApiModelProperty("创建时间")
    private LocalDateTime createTime;
    @ApiModelProperty("修改人ID")
    private Integer updateUser;
    @ApiModelProperty("修改时间")
    private LocalDateTime updateTime;
}
cnas-process/src/main/java/com/ruoyi/process/pojo/InspectionOrderDetail.java
@@ -22,6 +22,7 @@
@ApiModel(value = "InspectionOrderDetail对象", description = "检验委托单详情表")
public class InspectionOrderDetail {
    @ApiModelProperty("检验委托单详情ID")
    @TableId(value = "inspection_order_detail_id", type = IdType.AUTO)
    private Integer inspectionOrderDetailId;
@@ -57,6 +58,7 @@
    private LocalDateTime updateTime;
    // å¯¼å‡ºä½¿ç”¨
    @ApiModelProperty("导出序号")
    @TableField(select = false, exist = false)
    private Integer index;
}
cnas-process/src/main/java/com/ruoyi/process/service/InspectionOrderService.java
@@ -5,10 +5,13 @@
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.inspect.dto.InsPlaceOrderDto;
import com.ruoyi.process.dto.InspectionOrderDto;
import com.ruoyi.process.dto.InspectionOrderBindingDto;
import com.ruoyi.process.pojo.InspectionOrderAttachment;
import com.ruoyi.process.pojo.InspectionOrder;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
 * <p>
@@ -61,6 +64,11 @@
     */
    IPage<InspectionOrder> pageUnboundInspectionOrder(Page page, InspectionOrder inspectionOrder);
    IPage<InspectionOrderBindingDto> pageInspectionOrderBindings(Page page, Integer inspectionOrderId,
                                                                  Boolean includeDeleted);
    List<InspectionOrderAttachment> listInspectionOrderAttachments(Integer inspectionOrderId, Long bindingId);
    /**
     * èŽ·å–æˆå“ä¸‹å•åˆå§‹åŒ–æ‰€éœ€çš„å§”æ‰˜å•ä¿¡æ¯ã€‚
     */
@@ -94,10 +102,12 @@
     */
    boolean uploadInspectionOrderFile(MultipartFile file, Integer inspectionOrderId);
    boolean uploadInspectionOrderBindingFile(MultipartFile file, Long bindingId);
    /**
     * å¯¼å‡ºæ£€éªŒå§”托单
     * @param inspectionOrderId
     * @param response
     */
    void exportInspectionOrder(Integer inspectionOrderId, HttpServletResponse response);
    void exportInspectionOrder(Integer inspectionOrderId, Long bindingId, HttpServletResponse response);
}
cnas-process/src/main/java/com/ruoyi/process/service/impl/InspectionOrderServiceImpl.java
@@ -2,7 +2,6 @@
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@@ -17,24 +16,23 @@
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.framework.exception.ErrorException;
import com.ruoyi.inspect.dto.InsPlaceOrderDto;
import com.ruoyi.inspect.mapper.InsProductResultMapper;
import com.ruoyi.inspect.mapper.InsSampleMapper;
import com.ruoyi.inspect.pojo.InsOrder;
import com.ruoyi.inspect.pojo.InsProductResult;
import com.ruoyi.inspect.pojo.InsReport;
import com.ruoyi.inspect.service.InsOrderService;
import com.ruoyi.inspect.service.InsReportService;
import com.ruoyi.inspect.util.HackLoopTableRenderPolicy;
import com.ruoyi.process.dto.InspectionOrderDto;
import com.ruoyi.process.dto.InspectionOrderBindingDto;
import com.ruoyi.process.dto.InspectionOrderExportDto;
import com.ruoyi.process.mapper.InspectionOrderBindLogMapper;
import com.ruoyi.process.mapper.InspectionOrderMapper;
import com.ruoyi.process.mapper.ProcessOrderDeviceMapper;
import com.ruoyi.process.mapper.ProcessSampleMapper;
import com.ruoyi.process.mapper.InspectionOrderAttachmentMapper;
import com.ruoyi.process.mapper.InspectionOrderBindingMapper;
import com.ruoyi.process.pojo.InspectionOrder;
import com.ruoyi.process.pojo.InspectionOrderAttachment;
import com.ruoyi.process.pojo.InspectionOrderBinding;
import com.ruoyi.process.pojo.InspectionOrderBindLog;
import com.ruoyi.process.pojo.InspectionOrderDetail;
import com.ruoyi.process.pojo.ProcessOrderDevice;
import com.ruoyi.process.service.*;
import com.ruoyi.system.mapper.UserMapper;
import com.ruoyi.system.mapper.CustomMapper;
@@ -54,13 +52,16 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.time.LocalDateTime;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.LinkedHashMap;
import java.util.Objects;
import java.util.UUID;
/**
 * <p>
@@ -76,33 +77,21 @@
    @Resource
    private InspectionOrderBindLogMapper inspectionOrderBindLogMapper;
    @Resource
    private InspectionOrderBindingMapper inspectionOrderBindingMapper;
    @Resource
    private InspectionOrderAttachmentMapper inspectionOrderAttachmentMapper;
    @Resource
    private InspectionOrderDetailService inspectionOrderDetailService;
    @Resource
    private InsOrderService insOrderService;
    @Resource
    private InsSampleMapper insSampleMapper;
    @Resource
    private InsReportService insReportService;
    @Value("${wordUrl}")
    private String wordUrl;
    @Resource
    private ProcessReportService processReportService;
    @Resource
    private ProcessOrderDeviceMapper processOrderDeviceMapper;
    @Resource
    private InsProductResultMapper insProductResultMapper;
    @Resource
    private ProcessOrderDeviceService processOrderDeviceService;
    @Resource
    private UserMapper userMapper;
    @Resource
    private CustomMapper customMapper;
    @Resource
    private ProcessSampleService processSampleService;
    @Resource
    private ProcessSampleMapper processSampleMapper;
    @Resource
    private ProcessDealService processDealService;
    @Resource
    private NumberGenerator<InspectionOrder> numberGenerator;
@@ -149,47 +138,6 @@
        return inspectionOrder;
    }
    private synchronized void addDeviceRecord(InspectionOrder inspectionOrder, Integer userId) {
        // æŸ¥è¯¢è®¾å¤‡ä½¿ç”¨è®°å½•查询该订单的使用记录
        Set<String> recordCodeset = processOrderDeviceMapper.selectDeviceNumber(inspectionOrder.getInspectionOrderId());
        // èŽ·å–è®¢å•è®¾å¤‡ç¼–å·
        List<InsProductResult> resultList = insProductResultMapper.selectResultByOrderId(inspectionOrder.getInsOrderId());
        Set<String> deviceCodeSet = new HashSet<>();
        for (InsProductResult result : resultList) {
            // æ·»åŠ è®¾å¤‡ç¼–å·
            List<JSONObject> jsonObjects = JSON.parseArray(result.getEquipValue(), JSONObject.class);
            for (JSONObject jsonObject : jsonObjects) {
                if (!"".equals(jsonObject.get("v") + "")) {
                    List<String> v = StrUtil.split(jsonObject.get("v") + "", ",");
                    deviceCodeSet.addAll(v);
                }
            }
        }
        // 1.判断是否有没有添加的使用记录
        Set<String> orderDeviceNumbers = getDeviceDifference(deviceCodeSet, recordCodeset);
        // æ·»åŠ ä½¿ç”¨è®°å½•, æ ¹æ®ç¼–号查询设备id
        if (CollectionUtils.isNotEmpty(orderDeviceNumbers)) {
            List<Integer> orderDeviceIds = processOrderDeviceMapper.selectDeviceIdsByNumbers(orderDeviceNumbers);
            List<ProcessOrderDevice> collect = orderDeviceIds.stream().map(deviceId -> {
                ProcessOrderDevice processOrderDevice = new ProcessOrderDevice();
                processOrderDevice.setInspectionOrderId(inspectionOrder.getInspectionOrderId());
                processOrderDevice.setDeviceId(deviceId);
                processOrderDevice.setSampleCode(inspectionOrder.getEntrustCode());
                processOrderDevice.setUseBefore(1);
                processOrderDevice.setUseAfter(1);
                processOrderDevice.setUsePerson(userMapper.selectById(userId).getName());//使用人
                processOrderDevice.setUsePersonId(userId);//使用人id
                return processOrderDevice;
            }).collect(Collectors.toList());
            processOrderDeviceService.saveBatch(collect);
        }
    }
    private static Set<String> getDeviceDifference(Set<String> number1, Set<String> number2) {
        return number1.stream().filter(s1 -> number2.stream().noneMatch(s2 -> s1.equals(s2)))
                .collect(Collectors.toSet());
    }
    /**
     * æ£€éªŒå§”托单修改
     *
@@ -198,9 +146,14 @@
     */
    @Override
    public boolean updateInspectionOrder(InspectionOrderDto InspectionOrder) {
        InspectionOrder oldInspectionOrder = baseMapper.selectById(InspectionOrder.getInspectionOrderId());
        InspectionOrder oldInspectionOrder = baseMapper.selectByIdForUpdate(InspectionOrder.getInspectionOrderId());
        if (oldInspectionOrder == null) {
            throw new ErrorException("检验委托单不存在");
        }
        Long bindingHistoryCount = inspectionOrderBindingMapper.selectCount(Wrappers.<InspectionOrderBinding>lambdaQuery()
                .eq(InspectionOrderBinding::getInspectionOrderId, InspectionOrder.getInspectionOrderId()));
        if (bindingHistoryCount > 0 && !Objects.equals(oldInspectionOrder.getCommissionUnitId(), InspectionOrder.getCommissionUnitId())) {
            throw new ErrorException("已有下单记录,不允许修改委托单位");
        }
        normalizeCommissionParty(InspectionOrder);
        // ç¼–号、关联关系、正式委托编号和报告地址只能由专用流程维护。
@@ -235,12 +188,19 @@
     */
    @Override
    public boolean delInspectionOrder(Integer inspectionOrderId) {
        InspectionOrder inspectionOrder = baseMapper.selectById(inspectionOrderId);
        InspectionOrder inspectionOrder = baseMapper.selectByIdForUpdate(inspectionOrderId);
        if (inspectionOrder == null) {
            throw new ErrorException("检验委托单不存在");
        }
        if (inspectionOrder.getInsOrderId() != null) {
            throw new ErrorException("已绑定成品下单的检验委托单不允许删除");
        Long bindingHistoryCount = inspectionOrderBindingMapper.selectCount(Wrappers.<InspectionOrderBinding>lambdaQuery()
                .eq(InspectionOrderBinding::getInspectionOrderId, inspectionOrderId));
        Long bindLogCount = inspectionOrderBindLogMapper.selectCount(Wrappers.<InspectionOrderBindLog>lambdaQuery()
                .and(wrapper -> wrapper.eq(InspectionOrderBindLog::getOldInspectionOrderId, inspectionOrderId)
                        .or().eq(InspectionOrderBindLog::getNewInspectionOrderId, inspectionOrderId)));
        Long attachmentCount = inspectionOrderAttachmentMapper.selectCount(Wrappers.<InspectionOrderAttachment>lambdaQuery()
                .eq(InspectionOrderAttachment::getInspectionOrderId, inspectionOrderId));
        if (bindingHistoryCount > 0 || bindLogCount > 0 || attachmentCount > 0) {
            throw new ErrorException("该检验委托单已有下单或附件历史,不允许删除");
        }
        inspectionOrderDetailService.remove(Wrappers.<InspectionOrderDetail>lambdaQuery()
@@ -258,6 +218,9 @@
    @Override
    public InspectionOrderDto getInspectionOrderOne(Integer inspectionOrderId) {
        InspectionOrder inspectionOrder = baseMapper.selectById(inspectionOrderId);
        if (inspectionOrder == null) {
            throw new ErrorException("检验委托单不存在");
        }
        InspectionOrderDto inspectionOrderDto = new InspectionOrderDto();
        BeanUtils.copyProperties(inspectionOrder, inspectionOrderDto);
@@ -273,13 +236,33 @@
    }
    @Override
    public IPage<InspectionOrderBindingDto> pageInspectionOrderBindings(Page page, Integer inspectionOrderId,
                                                                         Boolean includeDeleted) {
        if (inspectionOrderId == null || baseMapper.selectById(inspectionOrderId) == null) {
            throw new ErrorException("检验委托单不存在");
        }
        return inspectionOrderBindingMapper.pageBindings(page, inspectionOrderId, includeDeleted);
    }
    @Override
    public List<InspectionOrderAttachment> listInspectionOrderAttachments(Integer inspectionOrderId, Long bindingId) {
        if (inspectionOrderId == null || baseMapper.selectById(inspectionOrderId) == null) {
            throw new ErrorException("检验委托单不存在");
        }
        if (bindingId != null) {
            InspectionOrderBinding binding = inspectionOrderBindingMapper.selectById(bindingId);
            if (binding == null || !Objects.equals(binding.getInspectionOrderId(), inspectionOrderId)) {
                throw new ErrorException("下单记录不属于该检验委托单");
            }
        }
        return inspectionOrderAttachmentMapper.selectVisibleAttachments(inspectionOrderId, bindingId);
    }
    @Override
    public InspectionOrderDto getInspectionOrderForPlaceOrder(Integer inspectionOrderId) {
        InspectionOrder inspectionOrder = baseMapper.selectById(inspectionOrderId);
        if (inspectionOrder == null) {
            throw new ErrorException("检验委托单不存在");
        }
        if (inspectionOrder.getInsOrderId() != null) {
            throw new ErrorException("该检验委托单已绑定成品下单,不能重复选择");
        }
        return getInspectionOrderOne(inspectionOrderId);
    }
@@ -292,12 +275,26 @@
        if (insPlaceOrderDto.getInsOrder() == null) {
            throw new ErrorException("缺少成品下单信息");
        }
        InspectionOrder inspectionOrder = baseMapper.selectById(insPlaceOrderDto.getInspectionOrderId());
        if (CollectionUtils.isEmpty(insPlaceOrderDto.getSampleList())) {
            throw new ErrorException("请填写本次样品");
        }
        String requestId = normalizeRequestId(insPlaceOrderDto.getRequestId());
        Integer requestUserId = SecurityUtils.getUserId().intValue();
        String requestHash = calculateRequestHash(insPlaceOrderDto);
        if (inspectionOrderBindingMapper.lockRequestUser(requestUserId) == null) {
            throw new ErrorException("当前操作人不存在");
        }
        InspectionOrderBinding existing = inspectionOrderBindingMapper.selectByRequest(requestUserId, requestId);
        if (existing != null) {
            return resolveIdempotentRequest(existing, requestHash);
        }
        InspectionOrder inspectionOrder = baseMapper.selectByIdForUpdate(insPlaceOrderDto.getInspectionOrderId());
        if (inspectionOrder == null) {
            throw new ErrorException("检验委托单不存在");
        }
        if (inspectionOrder.getInsOrderId() != null) {
            throw new ErrorException("该检验委托单已绑定成品下单,不能重复提交");
        existing = inspectionOrderBindingMapper.selectByRequest(requestUserId, requestId);
        if (existing != null) {
            return resolveIdempotentRequest(existing, requestHash);
        }
        if (inspectionOrder.getCommissionUnitId() == null) {
            throw new ErrorException("请先完善委托单位");
@@ -310,16 +307,60 @@
        Integer insOrderId = insOrderService.addInsOrder(insPlaceOrderDto.getSampleList(), insPlaceOrderDto.getInsOrder());
        Long sampleTakerUserId = SecurityUtils.getUserId();
        User sampleTaker = sampleTakerUserId == null ? null : userMapper.selectById(sampleTakerUserId);
        int updated = baseMapper.update(null, Wrappers.<InspectionOrder>lambdaUpdate()
                .eq(InspectionOrder::getInspectionOrderId, inspectionOrder.getInspectionOrderId())
                .isNull(InspectionOrder::getInsOrderId)
                .set(InspectionOrder::getInsOrderId, insOrderId)
                .set(InspectionOrder::getSampleTakerUserId, sampleTakerUserId == null ? null : sampleTakerUserId.intValue())
                .set(InspectionOrder::getSampleTakerUser, sampleTaker == null ? null : sampleTaker.getName()));
        if (updated != 1) {
            throw new ErrorException("检验委托单已被其他下单绑定,请刷新后重试");
        }
        InspectionOrderBinding binding = new InspectionOrderBinding();
        binding.setInspectionOrderId(inspectionOrder.getInspectionOrderId());
        binding.setInsOrderId(insOrderId);
        binding.setSourceType("NEW");
        binding.setRequestId(requestId);
        binding.setRequestHash(requestHash);
        binding.setRequestUserId(requestUserId);
        binding.setSampleTakerUserId(sampleTakerUserId == null ? null : sampleTakerUserId.intValue());
        binding.setSampleTakerUser(sampleTaker == null ? null : sampleTaker.getName());
        binding.setSampleData(LocalDate.now());
        binding.setOrderDeleted(0);
        binding.setCreateUser(requestUserId);
        binding.setCreateTime(LocalDateTime.now());
        inspectionOrderBindingMapper.insert(binding);
        return insOrderId;
    }
    private String normalizeRequestId(String requestId) {
        if (StrUtil.isBlank(requestId)) {
            throw new ErrorException("缺少下单请求号,请刷新页面后重试");
        }
        try {
            return UUID.fromString(requestId.trim()).toString();
        } catch (IllegalArgumentException e) {
            throw new ErrorException("下单请求号格式错误,请刷新页面后重试");
        }
    }
    private Integer resolveIdempotentRequest(InspectionOrderBinding existing, String requestHash) {
        if (!Objects.equals(existing.getRequestHash(), requestHash)) {
            throw new ErrorException("请求号已被其他下单内容使用,请重新发起下单");
        }
        if (Integer.valueOf(1).equals(existing.getOrderDeleted())) {
            throw new ErrorException("原订单已删除,请重新发起下单");
        }
        return existing.getInsOrderId();
    }
    private String calculateRequestHash(InsPlaceOrderDto dto) {
        LinkedHashMap<String, Object> content = new LinkedHashMap<>();
        content.put("inspectionOrderId", dto.getInspectionOrderId());
        content.put("insOrder", dto.getInsOrder());
        content.put("sampleList", dto.getSampleList());
        try {
            byte[] digest = MessageDigest.getInstance("SHA-256")
                    .digest(JSON.toJSONString(content).getBytes(StandardCharsets.UTF_8));
            StringBuilder result = new StringBuilder(64);
            for (byte value : digest) {
                result.append(String.format("%02x", value & 0xff));
            }
            return result.toString();
        } catch (Exception e) {
            throw new ErrorException("下单请求校验失败");
        }
    }
    private void fillInsOrderFromInspectionOrder(InspectionOrder inspectionOrder, InsOrder insOrder) {
@@ -361,16 +402,7 @@
    @Override
    public void syncEntrustCode(Integer insOrderId) {
        if (insOrderId == null) {
            return;
        }
        InsOrder insOrder = insOrderService.getById(insOrderId);
        if (insOrder == null || StrUtil.isBlank(insOrder.getEntrustCode())) {
            return;
        }
        baseMapper.update(null, Wrappers.<InspectionOrder>lambdaUpdate()
                .eq(InspectionOrder::getInsOrderId, insOrderId)
                .set(InspectionOrder::getEntrustCode, insOrder.getEntrustCode()));
        // å§”托编号属于具体成品订单,页面通过绑定关系实时读取,不再回写委托单主表。
    }
    @Override
@@ -382,12 +414,15 @@
        if (insReport == null || !Integer.valueOf(1).equals(insReport.getIsRatify())) {
            return;
        }
        InspectionOrder inspectionOrder = baseMapper.selectOne(Wrappers.<InspectionOrder>lambdaQuery()
                .eq(InspectionOrder::getInsOrderId, insReport.getInsOrderId())
        InspectionOrderBinding binding = inspectionOrderBindingMapper.selectOne(Wrappers.<InspectionOrderBinding>lambdaQuery()
                .eq(InspectionOrderBinding::getInsOrderId, insReport.getInsOrderId())
                .eq(InspectionOrderBinding::getOrderDeleted, 0)
                .last("limit 1"));
        if (inspectionOrder == null) {
        if (binding == null) {
            return;
        }
        InspectionOrder inspectionOrder = baseMapper.selectById(binding.getInspectionOrderId());
        if (inspectionOrder == null) return;
        String sourceUrl = StrUtil.isBlank(insReport.getUrlS()) ? insReport.getUrl() : insReport.getUrlS();
        if (StrUtil.isBlank(sourceUrl)) {
@@ -396,8 +431,8 @@
        String sourceFileName = sourceUrl.substring(sourceUrl.lastIndexOf('/') + 1);
        String extension = sourceFileName.lastIndexOf('.') >= 0
                ? sourceFileName.substring(sourceFileName.lastIndexOf('.')) : ".docx";
        String fileName = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyMMddHHmmss"))
                + "_" + inspectionOrder.getInspectionOrderCode() + "_委托单报告" + extension;
        String fileName = inspectionOrder.getInspectionOrderCode() + "_order_" + insReport.getInsOrderId()
                + "_report_" + insReportId + "_" + UUID.randomUUID() + extension;
        Path sourcePath = Paths.get(wordUrl + sourceUrl.replaceFirst("/word", ""));
        Path targetPath = Paths.get(wordUrl, fileName);
        try {
@@ -405,9 +440,26 @@
                throw new ErrorException("正式报告文件不存在,无法同步到检验委托单");
            }
            Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
            baseMapper.update(null, Wrappers.<InspectionOrder>lambdaUpdate()
                    .eq(InspectionOrder::getInspectionOrderId, inspectionOrder.getInspectionOrderId())
                    .set(InspectionOrder::getFileUrl, "/word/" + fileName));
            InspectionOrderAttachment attachment = inspectionOrderAttachmentMapper.selectOne(
                    Wrappers.<InspectionOrderAttachment>lambdaQuery()
                            .eq(InspectionOrderAttachment::getInsReportId, insReportId).last("limit 1"));
            if (attachment == null) {
                attachment = new InspectionOrderAttachment();
                attachment.setInsReportId(insReportId);
                attachment.setSourceType("REPORT");
                attachment.setCreateUser(SecurityUtils.getUserId().intValue());
                attachment.setCreateTime(LocalDateTime.now());
            }
            attachment.setInspectionOrderId(binding.getInspectionOrderId());
            attachment.setBindingId(binding.getId());
            attachment.setFileName(fileName);
            attachment.setFileUrl("/word/" + fileName);
            attachment.setUpdateTime(LocalDateTime.now());
            if (attachment.getId() == null) {
                inspectionOrderAttachmentMapper.insert(attachment);
            } else {
                inspectionOrderAttachmentMapper.updateById(attachment);
            }
        } catch (ErrorException e) {
            throw e;
        } catch (Exception e) {
@@ -428,25 +480,32 @@
                || StrUtil.isNotBlank(insOrder.getEntrustCode())) {
            throw new ErrorException("当前下单已进入检验流程或已生成委托编号,不允许变更关联");
        }
        InspectionOrder target = baseMapper.selectById(inspectionOrderId);
        if (target == null || target.getInsOrderId() != null) {
            throw new ErrorException("目标检验委托单不存在或已被绑定");
        InspectionOrderBinding binding = inspectionOrderBindingMapper.selectByOrderIdForUpdate(insOrderId);
        if (binding == null || Integer.valueOf(1).equals(binding.getOrderDeleted())) {
            throw new ErrorException("成品下单未绑定有效检验委托单");
        }
        InspectionOrder oldInspectionOrder = baseMapper.selectOne(Wrappers.<InspectionOrder>lambdaQuery()
                .eq(InspectionOrder::getInsOrderId, insOrderId));
        baseMapper.update(null, Wrappers.<InspectionOrder>lambdaUpdate()
                .eq(InspectionOrder::getInsOrderId, insOrderId)
                .set(InspectionOrder::getInsOrderId, null));
        int updated = baseMapper.update(null, Wrappers.<InspectionOrder>lambdaUpdate()
                .eq(InspectionOrder::getInspectionOrderId, inspectionOrderId)
                .isNull(InspectionOrder::getInsOrderId)
                .set(InspectionOrder::getInsOrderId, insOrderId));
        if (updated != 1) {
            throw new ErrorException("目标检验委托单已被其他下单绑定,请刷新后重试");
        InspectionOrder target = baseMapper.selectByIdForUpdate(inspectionOrderId);
        if (target == null) {
            throw new ErrorException("目标检验委托单不存在");
        }
        if (Objects.equals(binding.getInspectionOrderId(), inspectionOrderId)) {
            throw new ErrorException("目标检验委托单与当前委托单相同");
        }
        if (!Objects.equals(target.getCommissionUnitId(), insOrder.getCompanyId())) {
            throw new ErrorException("目标检验委托单与成品订单的委托单位不一致");
        }
        Integer oldInspectionOrderId = binding.getInspectionOrderId();
        binding.setInspectionOrderId(inspectionOrderId);
        binding.setUpdateUser(SecurityUtils.getUserId().intValue());
        binding.setUpdateTime(LocalDateTime.now());
        inspectionOrderBindingMapper.updateById(binding);
        inspectionOrderAttachmentMapper.update(null, Wrappers.<InspectionOrderAttachment>lambdaUpdate()
                .eq(InspectionOrderAttachment::getBindingId, binding.getId())
                .set(InspectionOrderAttachment::getInspectionOrderId, inspectionOrderId)
                .set(InspectionOrderAttachment::getUpdateTime, LocalDateTime.now()));
        InspectionOrderBindLog bindLog = new InspectionOrderBindLog();
        bindLog.setInsOrderId(insOrderId);
        bindLog.setOldInspectionOrderId(oldInspectionOrder == null ? null : oldInspectionOrder.getInspectionOrderId());
        bindLog.setOldInspectionOrderId(oldInspectionOrderId);
        bindLog.setNewInspectionOrderId(inspectionOrderId);
        bindLog.setChangeReason(reason.trim());
        bindLog.setCreateUser(SecurityUtils.getUserId().intValue());
@@ -464,33 +523,71 @@
     */
    @Override
    public boolean uploadInspectionOrderFile(MultipartFile file, Integer inspectionOrderId) {
        String urlString;
        String pathName;
        try {
            String path = wordUrl;
            File realpath = new File(path);
            if (!realpath.exists()) {
                realpath.mkdirs();
            }
            pathName = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyMMddHHmmss")) + "_" + file.getOriginalFilename();
            urlString = realpath + "/" + pathName;
            file.transferTo(new File(urlString));
            baseMapper.update(null, Wrappers.<InspectionOrder>lambdaUpdate()
                    .eq(InspectionOrder::getInspectionOrderId, inspectionOrderId)
                    .set(InspectionOrder::getFileUrl, "/word/" + pathName));
        } catch (Exception e) {
            throw new ErrorException("文件上传失败");
        }
        return true;
        throw new ErrorException("请在下单记录中选择具体订单后上传附件");
    }
    @Override
    public void exportInspectionOrder(Integer inspectionOrderId, HttpServletResponse response) {
    public boolean uploadInspectionOrderBindingFile(MultipartFile file, Long bindingId) {
        if (file == null || file.isEmpty() || bindingId == null) {
            throw new ErrorException("请选择下单记录和上传文件");
        }
        InspectionOrderBinding binding = inspectionOrderBindingMapper.selectById(bindingId);
        if (binding == null || Integer.valueOf(1).equals(binding.getOrderDeleted())) {
            throw new ErrorException("下单记录不存在或订单已删除");
        }
        try {
            File realpath = new File(wordUrl);
            if (!realpath.exists() && !realpath.mkdirs()) {
                throw new ErrorException("文件目录创建失败");
            }
            String originalName = new File(file.getOriginalFilename() == null ? "attachment" : file.getOriginalFilename()).getName();
            String pathName = "binding_" + bindingId + "_" + UUID.randomUUID() + "_" + originalName;
            file.transferTo(new File(realpath, pathName));
            InspectionOrderAttachment attachment = new InspectionOrderAttachment();
            attachment.setInspectionOrderId(binding.getInspectionOrderId());
            attachment.setBindingId(bindingId);
            attachment.setSourceType("MANUAL");
            attachment.setFileName(originalName);
            attachment.setFileUrl("/word/" + pathName);
            attachment.setCreateUser(SecurityUtils.getUserId().intValue());
            attachment.setCreateTime(LocalDateTime.now());
            inspectionOrderAttachmentMapper.insert(attachment);
            return true;
        } catch (ErrorException e) {
            throw e;
        } catch (Exception e) {
            throw new ErrorException("文件上传失败");
        }
    }
    @Override
    public void exportInspectionOrder(Integer inspectionOrderId, Long bindingId, HttpServletResponse response) {
        InspectionOrder inspectionOrder = baseMapper.selectById(inspectionOrderId);
        if (inspectionOrder == null) {
            throw new ErrorException("检验委托单不存在");
        }
        InspectionOrderExportDto inspectionOrderExportDto = extracted(inspectionOrder);
        if (bindingId == null) {
            inspectionOrderExportDto.setEntrustCode(null);
            inspectionOrderExportDto.setSampleTakerUser(null);
            inspectionOrderExportDto.setSampleTakerUserId(null);
            inspectionOrderExportDto.setSampleData(null);
            inspectionOrderExportDto.setSampleDataString(null);
        } else {
            InspectionOrderBinding binding = inspectionOrderBindingMapper.selectById(bindingId);
            if (binding == null || !Objects.equals(binding.getInspectionOrderId(), inspectionOrderId)) {
                throw new ErrorException("下单记录不属于该检验委托单");
            }
            InsOrder insOrder = insOrderService.getById(binding.getInsOrderId());
            inspectionOrderExportDto.setEntrustCode(insOrder == null ? null : insOrder.getEntrustCode());
            inspectionOrderExportDto.setSampleTakerUser(binding.getSampleTakerUser());
            inspectionOrderExportDto.setSampleTakerUserId(binding.getSampleTakerUserId());
            inspectionOrderExportDto.setSampleData(binding.getSampleData());
            if (binding.getSampleData() != null) {
                inspectionOrderExportDto.setSampleDataString(binding.getSampleData()
                        .format(DateTimeFormatter.ofPattern("yyyyå¹´MM月dd日")));
            }
        }
        List<InspectionOrderDetail> list = inspectionOrderDetailService.list(Wrappers.<InspectionOrderDetail>lambdaQuery()
                .eq(InspectionOrderDetail::getInspectionOrderId, inspectionOrderId));
        int index = 1;
cnas-process/src/main/resources/mapper/InspectionOrderAttachmentMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
<?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.process.mapper.InspectionOrderAttachmentMapper">
    <select id="selectVisibleAttachments" resultType="com.ruoyi.process.pojo.InspectionOrderAttachment">
        select a.*
        from cnas_inspection_order_attachment a
        left join ins_report r on r.id = a.ins_report_id
        where a.inspection_order_id = #{inspectionOrderId}
          and (a.source_type != 'REPORT' or r.is_ratify = 1)
        <if test="bindingId != null">
            and a.binding_id = #{bindingId}
        </if>
        order by a.create_time desc, a.id desc
    </select>
</mapper>
cnas-process/src/main/resources/mapper/InspectionOrderBindingMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,53 @@
<?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.process.mapper.InspectionOrderBindingMapper">
    <select id="lockRequestUser" resultType="java.lang.Integer">
        select id from `user` where id = #{userId} for update
    </select>
    <select id="selectByRequest" resultType="com.ruoyi.process.pojo.InspectionOrderBinding">
        select *
        from cnas_inspection_order_binding
        where request_user_id = #{userId} and request_id = #{requestId}
        limit 1
    </select>
    <select id="selectByOrderIdForUpdate" resultType="com.ruoyi.process.pojo.InspectionOrderBinding">
        select *
        from cnas_inspection_order_binding
        where ins_order_id = #{insOrderId} limit 1
        for
        update
    </select>
    <select id="pageBindings" resultType="com.ruoyi.process.dto.InspectionOrderBindingDto">
        select b.*, cio.inspection_order_code, io.entrust_code, io.state as order_state, io.ins_result,
               case
                   when total_product_counts.total_count is null or total_product_counts.total_count = 0 then '0%'
                   else concat(round(ifnull(approved_product_counts.approved_count, 0) /
                                     total_product_counts.total_count * 100, 2), '%')
               end as ins_progress,
               ifnull(report_counts.report_count, 0) as report_count
        from cnas_inspection_order_binding b
        join cnas_inspection_order cio on cio.inspection_order_id = b.inspection_order_id
        left join ins_order io on io.id = b.ins_order_id
        left join (select ins_sample.ins_order_id, count(*) as total_count
                   from ins_product join ins_sample on ins_product.ins_sample_id = ins_sample.id
                   where ins_product.state = 1 group by ins_sample.ins_order_id) total_product_counts
                  on total_product_counts.ins_order_id = b.ins_order_id
        left join (select ins_sample.ins_order_id, count(*) as approved_count
                   from ins_product join ins_sample on ins_product.ins_sample_id = ins_sample.id
                   where ins_product.state = 1 and ins_product.ins_result is not null
                   group by ins_sample.ins_order_id) approved_product_counts
                  on approved_product_counts.ins_order_id = b.ins_order_id
        left join (select ins_order_id, count(*) as report_count from ins_report
                   where is_ratify = 1 group by ins_order_id) report_counts
                  on report_counts.ins_order_id = b.ins_order_id
        where b.inspection_order_id = #{inspectionOrderId}
        <if test="includeDeleted == null or includeDeleted == false">
            and b.order_deleted = 0
        </if>
        order by b.create_time desc, b.id desc
    </select>
</mapper>
cnas-process/src/main/resources/mapper/InspectionOrderMapper.xml
@@ -2,40 +2,26 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.process.mapper.InspectionOrderMapper">
    <select id="selectByIdForUpdate" resultType="com.ruoyi.process.pojo.InspectionOrder">
        select *
        from cnas_inspection_order
        where inspection_order_id = #{inspectionOrderId}
        for update
    </select>
    <!--检验委托单分页查询-->
    <select id="pageInspectionOrder" resultType="com.ruoyi.process.dto.InspectionOrderDto">
        select *
        from (
            select cio.*,
                   case when cio.ins_order_id is null then 0 else 1 end as binding_status,
                   io.state as order_state,
                   io.ins_result as ins_result,
                   case
                       when cio.ins_order_id is null then null
                       when total_product_counts.total_count is null or total_product_counts.total_count = 0 then '0%'
                       else concat(round(ifnull(approved_product_counts.approved_count, 0) / total_product_counts.total_count * 100, 2), '%')
                   end as ins_progress,
                   case
                       when cio.file_url is not null and trim(cio.file_url) != '' then 2
                       when approved_report.id is not null then 1
                       else 0
                   end as report_status
                   ifnull(binding_counts.binding_count, 0) as binding_count,
                   case when ifnull(binding_counts.binding_count, 0) = 0 then 0 else 1 end as binding_status
            from cnas_inspection_order cio
                     left join ins_order io on cio.ins_order_id = io.id
                     left join (select max(id) as id, ins_order_id
                                from ins_report
                                where is_ratify = 1
                                group by ins_order_id) approved_report on approved_report.ins_order_id = io.id
                     left join (select ins_sample.ins_order_id, count(*) as total_count
                                from ins_product
                                         join ins_sample on ins_product.ins_sample_id = ins_sample.id
                                where ins_product.state = 1
                                group by ins_sample.ins_order_id) total_product_counts on total_product_counts.ins_order_id = io.id
                     left join (select ins_sample.ins_order_id, count(*) as approved_count
                                from ins_product
                                         join ins_sample on ins_product.ins_sample_id = ins_sample.id
                                where ins_product.state = 1 and ins_product.ins_result is not null
                                group by ins_sample.ins_order_id) approved_product_counts on approved_product_counts.ins_order_id = io.id
                     left join (select inspection_order_id, count(*) as binding_count
                                from cnas_inspection_order_binding
                                where order_deleted = 0
                                group by inspection_order_id) binding_counts
                               on binding_counts.inspection_order_id = cio.inspection_order_id
            order by cio.create_time desc
        ) a
        <if test="ew.customSqlSegment != null and ew.customSqlSegment != ''">
@@ -43,13 +29,12 @@
        </if>
    </select>
    <!--成品下单选择尚未绑定的检验委托单-->
    <!--兼容原接口名:多次绑定后,所有委托单均可供成品下单选择。-->
    <select id="pageUnboundInspectionOrder" resultType="com.ruoyi.process.pojo.InspectionOrder">
        select *
        from (
            select *
            from cnas_inspection_order
            where ins_order_id is null
            order by create_time desc
        ) a
        <if test="ew.customSqlSegment != null and ew.customSqlSegment != ''">
inspect-server/src/main/java/com/ruoyi/inspect/aspect/MoveLocationAfterPushMesStockAspect.java
@@ -18,6 +18,8 @@
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
/**
@@ -83,6 +85,14 @@
                    requestMap.put("newPartBatchNo", one.getLotBatchNo()); // æ–°é›¶ä»¶æ‰¹å·
                    requestMap.put("stockQuantity", one.getLength()); // åº“存数量1
                    requestMap.put("qty", one.getQtyStock()); // åº“存数量2
                    // å¯¼å…¥é•¿åº¦ä¸º km、重量为 kg;米重按 kg/km å‘下保留 6 ä½ï¼Œé¿å…æ¢ç®—后超过原重量。
                    BigDecimal lengthKm = one.getLength();
                    BigDecimal weightKg = one.getQtyStock();
                    if (lengthKm == null || lengthKm.signum() <= 0 || weightKg == null || weightKg.signum() <= 0) {
                        throw new IllegalArgumentException("批号 " + one.getLotBatchNo() + " çš„长度或重量为空或不大于 0,无法计算米重");
                    }
                    BigDecimal meterWeight = weightKg.divide(lengthKm, 6, RoundingMode.DOWN);
                    requestMap.put("meterWeight", meterWeight); // ç±³é‡ï¼Œkg/km
                    requestMap.put("insulationColor", one.getInsulationColor()); // ç»ç¼˜é¢œè‰²
                    requestMap.put("outerColor", one.getOuterColor()); // å¤–护颜色
                    requestMap.put("letteringInfo", one.getLetteringInfo()); // å°å­—信息
inspect-server/src/main/java/com/ruoyi/inspect/controller/InsOrderController.java
@@ -208,13 +208,7 @@
    @ApiOperation(value = "删除退回订单")
    @DeleteMapping("/delInsOrder")
    public Result<?> delInsOrder(Integer insOrderId) {
        // æŸ¥è¯¢è®¢å•
        InsOrder order = insOrderService.getById(insOrderId);
        if (!(order.getState().equals(2) || order.getState().equals(3))) {
            throw new ErrorException("只有退回订单才能删除");
        }
        return Result.success(insOrderService.removeById(insOrderId));
        return Result.success(insOrderService.deleteReturnedOrder(insOrderId));
    }
    @ApiOperation(value = "成品标签打印")
inspect-server/src/main/java/com/ruoyi/inspect/dto/InsPlaceOrderDto.java
@@ -15,6 +15,9 @@
@Data
public class InsPlaceOrderDto{
    @ApiModelProperty("下单请求号,用于防止网络重试重复创建订单")
    private String requestId;
    @ApiModelProperty("关联的检验委托单ID")
    private Integer inspectionOrderId;
inspect-server/src/main/java/com/ruoyi/inspect/event/InsOrderDeletingEvent.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
package com.ruoyi.inspect.event;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.time.LocalDateTime;
/** æˆå“è®¢å•物理删除前发布的同步事务事件。 */
@Data
@AllArgsConstructor
public class InsOrderDeletingEvent {
    @ApiModelProperty("成品订单ID")
    private Integer insOrderId;
    @ApiModelProperty("操作人ID")
    private Integer operatorId;
    @ApiModelProperty("操作时间")
    private LocalDateTime operateTime;
}
inspect-server/src/main/java/com/ruoyi/inspect/service/InsOrderService.java
@@ -36,6 +36,9 @@
    int addInsOrder(List<SampleProductDto> list, InsOrder insOrder);
    /** åˆ é™¤é€€å›ž/撤销订单,并同步保留相关业务追溯记录。 */
    boolean deleteReturnedOrder(Integer insOrderId);
    Map<String, Object> getInsOrder(Integer id);
    int upInsOrderOfState(InsOrder insOrder);
inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java
@@ -35,6 +35,7 @@
import com.ruoyi.common.utils.api.IfsApiUtils;
import com.ruoyi.framework.exception.ErrorException;
import com.ruoyi.inspect.dto.*;
import com.ruoyi.inspect.event.InsOrderDeletingEvent;
import com.ruoyi.inspect.mapper.*;
import com.ruoyi.inspect.pojo.*;
import com.ruoyi.inspect.service.InsOrderService;
@@ -48,6 +49,7 @@
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
@@ -88,6 +90,7 @@
    private InsUnqualifiedRetestProductMapper insUnqualifiedRetestProductMapper;
    private IfsApiUtils ifsApiUtils;
    private SpotCheckQuarterItemMapper spotCheckQuarterItemMapper;
    private ApplicationEventPublisher applicationEventPublisher;
    private StandardProductListMapper standardProductListMapper;
    private StructureItemParameterMapper structureItemParameterMapper;
@@ -406,6 +409,21 @@
        return insOrder.getId();
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteReturnedOrder(Integer insOrderId) {
        InsOrder order = insOrderMapper.selectById(insOrderId);
        if (order == null) {
            throw new ErrorException("成品订单不存在");
        }
        if (!(Integer.valueOf(2).equals(order.getState()) || Integer.valueOf(3).equals(order.getState()))) {
            throw new ErrorException("只有退回或撤销订单才能删除");
        }
        Integer operatorId = SecurityUtils.getUserId().intValue();
        applicationEventPublisher.publishEvent(new InsOrderDeletingEvent(insOrderId, operatorId, LocalDateTime.now()));
        return removeById(insOrderId);
    }
    /**
     * æ·»åŠ æ£€éªŒé¡¹
     *
inspect-server/src/main/resources/mapper/DataAnalysisMapper.xml
@@ -2,6 +2,16 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.ruoyi.inspect.mapper.DataAnalysisMapper">
    <!-- æœ‰éžç©ºç™½æè¿°ä¸”符合原有 OA æ¡ä»¶çš„处理记录,才作为不合格依据。 -->
    <sql id="countableUnqualifiedBatch">
        SELECT inventory_quantity_id, 1 AS has_unqualified
        FROM ins_unqualified_handler
        WHERE oa_state IS NOT NULL
          AND oa_state != 4
          AND unqualified_desc REGEXP '[^[:space:] ]'
        GROUP BY inventory_quantity_id
    </sql>
    <!-- èŽ·å–æœ¬æœˆçš„ç‰©æ–™å±žæ€§ä¿¡æ¯ -->
    <!-- èŽ·å–æœ¬æœˆçš„ç‰©æ–™å±žæ€§ä¿¡æ¯ï¼ˆæŒ‰å¤©ï¼Œè¡¥å…¨æ—¥æœŸï¼‰ -->
    <select id="getRawPassRateByBarChartByDay" resultType="java.util.Map">
@@ -25,17 +35,21 @@
        SELECT
        DATE(report_time) AS day,
        COUNT(*) AS total,
        SUM(CASE WHEN inspect_status = 1 and (iuh_id is null) THEN 1 ELSE 0 END) AS qualified,
        SUM(CASE WHEN inspect_status != 1 or (iuh_id is not null) THEN 1 ELSE 0 END) AS unQualified
        SUM(CASE WHEN has_unqualified = 0 THEN 1 ELSE 0 END) AS qualified,
        SUM(CASE WHEN has_unqualified = 1 THEN 1 ELSE 0 END) AS unQualified
        FROM (SELECT
        IFNULL(iuh.feedback_time,io1.send_time) report_time,
        iuh.id AS iuh_id,
        COALESCE(counted_iuh.has_unqualified, 0) AS has_unqualified,
        iiq.inspect_status
        FROM ifs_inventory_quantity iiq
        LEFT JOIN ins_order io1
        ON io1.ifs_inventory_id = iiq.id
        AND io1.order_type = #{dto.orderType}
        AND io1.state != -1
        LEFT JOIN (
        <include refid="countableUnqualifiedBatch"/>
        ) counted_iuh ON counted_iuh.inventory_quantity_id = iiq.id
        LEFT JOIN (
        SELECT
        MAX(iuh.id) AS id,
@@ -111,18 +125,22 @@
        SELECT
            MONTH(report_time) AS month,
            COUNT(*) AS total,
            SUM(CASE WHEN inspect_status = 1 and (iuh_id is null) THEN 1 ELSE 0 END) AS qualified,
            SUM(CASE WHEN inspect_status != 1 or (iuh_id is not null) THEN 1 ELSE 0 END) AS unQualified
            SUM(CASE WHEN has_unqualified = 0 THEN 1 ELSE 0 END) AS qualified,
            SUM(CASE WHEN has_unqualified = 1 THEN 1 ELSE 0 END) AS unQualified
        FROM (
        SELECT
        IFNULL(iuh.feedback_time,io1.send_time) report_time,
        iuh.id AS iuh_id,
        COALESCE(counted_iuh.has_unqualified, 0) AS has_unqualified,
        iiq.inspect_status
        FROM ifs_inventory_quantity iiq
        LEFT JOIN ins_order io1
        ON io1.ifs_inventory_id = iiq.id
        AND io1.order_type = #{dto.orderType}
        AND io1.state != -1
        LEFT JOIN (
        <include refid="countableUnqualifiedBatch"/>
        ) counted_iuh ON counted_iuh.inventory_quantity_id = iiq.id
        LEFT JOIN (
        SELECT
        MAX(iuh.id) AS id,
@@ -168,16 +186,19 @@
        SELECT
            COUNT(*) AS sum,
            /* åˆæ ¼ */
            SUM(CASE WHEN inspect_status = 1 and (iuh_id is null) THEN 1 ELSE 0 END) AS qualified,
            SUM(CASE WHEN has_unqualified = 0 THEN 1 ELSE 0 END) AS qualified,
            /* ä¸åˆæ ¼ */
            SUM(CASE WHEN inspect_status != 1 or (iuh_id is not null) THEN 1 ELSE 0 END) AS unQualified
            SUM(CASE WHEN has_unqualified = 1 THEN 1 ELSE 0 END) AS unQualified
        FROM (
        SELECT
        iiq.inspect_status,
        iuh.id AS iuh_id
        COALESCE(counted_iuh.has_unqualified, 0) AS has_unqualified
        FROM ifs_inventory_quantity iiq
        INNER JOIN ins_order io1
        ON io1.ifs_inventory_id = iiq.id
        LEFT JOIN (
        <include refid="countableUnqualifiedBatch"/>
        ) counted_iuh ON counted_iuh.inventory_quantity_id = iiq.id
        LEFT JOIN (
        SELECT
        MAX(iuh.id) AS id,
@@ -224,20 +245,23 @@
        SELECT
            supplier_name,
            COUNT(id) AS totalBatch,
            SUM(CASE WHEN inspect_status != 1 or (iuh_id is not null) THEN 1 ELSE 0 END) AS unqualifiedBatch,
            ROUND(SUM(CASE WHEN inspect_status = 1 and iuh_id is null THEN 1 ELSE 0 END) / COUNT(*)* 100, 2 ) AS passRate
            SUM(CASE WHEN has_unqualified = 1 THEN 1 ELSE 0 END) AS unqualifiedBatch,
            ROUND(SUM(CASE WHEN has_unqualified = 0 THEN 1 ELSE 0 END) / COUNT(*)* 100, 2 ) AS passRate
        FROM
        (
            SELECT
                iiq.supplier_name,
                iiq.id,
                iuh.id AS iuh_id,
                COALESCE(counted_iuh.has_unqualified, 0) AS has_unqualified,
                iiq.inspect_status
            FROM ifs_inventory_quantity iiq
            INNER JOIN ins_order io1
            ON io1.ifs_inventory_id = iiq.id
            AND io1.order_type = #{dto.orderType}
            AND io1.state != -1
            LEFT JOIN (
                <include refid="countableUnqualifiedBatch"/>
            ) counted_iuh ON counted_iuh.inventory_quantity_id = iiq.id
            LEFT JOIN (
            SELECT
                MAX(iuh.id) AS id,
@@ -382,13 +406,17 @@
    <!-- æŸ¥è¯¢æœ¬æœˆä¸Žä¸Šæœˆåˆæ ¼çŽ‡å¯¹æ¯” -->
    <select id="getRawUpMonth" resultType="java.util.Map">
        select DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 1 MONTH), '%Y-%m') as                           month,
               (select ROUND((COUNT(*) - SUM(CASE WHEN inspect_status in (2, 4) THEN 1 ELSE 0 END)) / COUNT(*) *
                             100,
                             2) passRate
               (select ROUND(
                            SUM(CASE WHEN counted_iuh.has_unqualified IS NULL THEN 1 ELSE 0 END) / COUNT(*) *
                            100,
                            2) passRate
                from ifs_inventory_quantity iiq
                         LEFT JOIN ins_order io1 on io1.ifs_inventory_id = iiq.id
                    and io1.order_type = '进厂检验'
                    and io1.state != -1
                LEFT JOIN (
                    <include refid="countableUnqualifiedBatch"/>
                ) counted_iuh ON counted_iuh.inventory_quantity_id = iiq.id
                where iiq.is_finish = 1
                  and iiq.inspect_status not in (0, 3)
                  and (io1.send_time between DATE_FORMAT(DATE_SUB(DATE_FORMAT(NOW(), '%Y-%m-01'), INTERVAL 1 MONTH),
@@ -396,13 +424,17 @@
                    and DATE_FORMAT(LAST_DAY(DATE_SUB(NOW(), INTERVAL 1 MONTH)), '%Y-%m-%d 23:59:59'))) passRate
        UNION ALL
        select DATE_FORMAT(CURRENT_DATE, '%Y-%m') as                            month,
               (select ROUND((COUNT(*) - SUM(CASE WHEN inspect_status in (2, 4) THEN 1 ELSE 0 END)) / COUNT(*) *
                             100,
                             2) passRate
               (select ROUND(
                            SUM(CASE WHEN counted_iuh.has_unqualified IS NULL THEN 1 ELSE 0 END) / COUNT(*) *
                            100,
                            2) passRate
                from ifs_inventory_quantity iiq
                         LEFT JOIN ins_order io1 on io1.ifs_inventory_id = iiq.id
                    and io1.order_type = '进厂检验'
                    and io1.state != -1
                LEFT JOIN (
                    <include refid="countableUnqualifiedBatch"/>
                ) counted_iuh ON counted_iuh.inventory_quantity_id = iiq.id
                where iiq.is_finish = 1
                  and iiq.inspect_status not in (0, 3)
                  and (io1.send_time between
inspect-server/src/main/resources/static/report-template.docx
Binary files differ