liding
4 小时以前 444409ba734d4457f9109f0b71422b83fed60cd6
inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderPlanServiceImpl.java
@@ -46,6 +46,7 @@
import com.ruoyi.inspect.service.*;
import com.ruoyi.inspect.util.HackLoopTableRenderPolicy;
import com.ruoyi.inspect.util.PreserveReportPicturePlaceholderHandler;
import com.ruoyi.inspect.util.ReportSignaturePictureUtils;
import com.ruoyi.inspect.vo.InsOrderPlanTaskSwitchVo;
import com.ruoyi.inspect.vo.InsOrderPlanVO;
import com.ruoyi.inspect.vo.InsSampleUserVO;
@@ -74,6 +75,7 @@
import java.nio.file.Paths;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
@@ -273,11 +275,11 @@
        // 查询订单Id
        InsOrder order = insOrderMapper.selectFirstSubmit(dto.getId());
        if (order == null) {
            return BeanUtil.isEmpty(insProducts) ? null : insProducts;
            return BeanUtil.isEmpty(insProducts) ? Collections.emptyList() : insProducts;
        }
        insProducts = mergeDirectTemplateSnapshots(order, dto.getId(), dto.getLaboratory(), insProducts);
        if (BeanUtil.isEmpty(insProducts)) {
            return null;
            return Collections.emptyList();
        }
        getTemplateThing(order, insProducts, dto.getLaboratory());
        return insProducts;
@@ -299,14 +301,6 @@
        if (snapshots.isEmpty()) {
            return source;
        }
        InsSample sample = insSampleMapper.selectById(sampleId);
        boolean directTemplateOrder = source.stream()
                .anyMatch(product -> product.getTemplateRowIndex() != null)
                || isDirectTemplateSample(order, sample);
        if (!directTemplateOrder) {
            return source;
        }
        Map<Integer, List<InsProduct>> productsByTemplate = source.stream()
                .filter(product -> product.getTemplateId() != null)
                .collect(Collectors.groupingBy(InsProduct::getTemplateId, LinkedHashMap::new, Collectors.toList()));
@@ -1217,13 +1211,12 @@
                .last("FOR UPDATE"));
        boolean isInspectionReport = Objects.equals(INSPECTION_REPORT, reportType);
        registerInsResults = isInspectionReport && Boolean.TRUE.equals(registerInsResults);
        // 1. 判断是否有重复编号, 有重复编号做提醒
        // 1. 委托编号全局唯一,提交复核时再次校验,防止并发或历史数据绕过生成校验。
        Long codeCount = insOrderMapper.selectCount(Wrappers.<InsOrder>lambdaQuery()
                .ne(InsOrder::getState, -1)
                .ne(InsOrder::getIfsInventoryId, order.getIfsInventoryId())
                .ne(InsOrder::getId, orderId)
                .eq(InsOrder::getEntrustCode, order.getEntrustCode()));
        if (codeCount > 0) {
            throw new ErrorException("当前编号有重复, 请先去修改重复编号");
            throw new ErrorException("样品/委托单已存在,请确认样品编号");
        }
        // 2. 判断该订单是否是第一次生产(后续报告生成只取第一次提交时间)
@@ -1985,13 +1978,13 @@
                || report.getExamineTime() != null;
        if (submitted) {
            User writer = getReportSigner(report.getWriteUserId(), "编制人");
            marks.put("writeUrl", Pictures.ofLocal(imgUrl + "/" + writer.getSignatureUrl()).create());
            marks.put("writeUrl", ReportSignaturePictureUtils.create(imgUrl, writer.getSignatureUrl()));
            marks.put("writeDateUrl", Pictures.ofStream(DateImageUtil.createDateImage(report.getWriteTime())).create());
            marks.put("insUrl", Pictures.ofLocal(imgUrl + "/" + writer.getSignatureUrl()).create());
            marks.put("insUrl", ReportSignaturePictureUtils.create(imgUrl, writer.getSignatureUrl()));
        }
        if (Objects.equals(report.getIsExamine(), 1)) {
            User examiner = getReportSigner(report.getExamineUserId(), "审核人");
            marks.put("examineUrl", Pictures.ofLocal(imgUrl + "/" + examiner.getSignatureUrl()).create());
            marks.put("examineUrl", ReportSignaturePictureUtils.create(imgUrl, examiner.getSignatureUrl()));
            marks.put("examineDateUrl", Pictures.ofStream(DateImageUtil.createDateImage(report.getExamineTime())).create());
        }
        return marks;
@@ -2536,13 +2529,18 @@
        enterFactoryReport.setLotBatchNo(ifsInventoryQuantity.getUpdateBatchNo());
        // 检测依据
        Set<String> standardMethod = new HashSet<>();
        Set<String> standardMethod = new LinkedHashSet<>();
        StringBuilder standardMethod2 = new StringBuilder();
        standardMethod.add(baseMapper.getStandardMethodCode(insSample.getStandardMethodListId()));
        String reportStandardMethod = baseMapper.getStandardMethodReportText(insSample.getStandardMethodListId());
        if (StringUtils.isNotBlank(reportStandardMethod)) {
            standardMethod.add(reportStandardMethod);
        }
        for (String s : standardMethod) {
            standardMethod2.append("、").append(s);
        }
        standardMethod2.replace(0, 1, "");
        if (standardMethod2.length() > 0) {
            standardMethod2.deleteCharAt(0);
        }
        // 样品类型
        String orderType = iSysDictTypeService.selectLabelByDict(DictDataConstants.CHECK_TYPE, insOrder.getOrderType());
@@ -3214,8 +3212,7 @@
        insReport.setReportType(reportType);
        boolean showResult = Objects.equals(reportType, INSPECTION_REPORT);
        List<Map<String, Object>> tables = new ArrayList<>();
        Set<String> standardMethod = new HashSet<>();
        Set<String> deviceSet = new HashSet<>();
        Set<String> standardMethod = new LinkedHashSet<>();
        Set<String> models = new HashSet<>();
        // 查询检验项数量
        AtomicInteger productSize = new AtomicInteger();
@@ -3227,21 +3224,12 @@
        /*基础报告(根据绘制的原始记录模版形成)*/
        samples.forEach(a -> {
            models.add(a.getModel());
            String standardMethodCode = baseMapper.getStandardMethodCode(a.getStandardMethodListId());
            if (StrUtil.isNotBlank(a.getSpecialStandardMethod())) {
                standardMethodCode = standardMethodCode + "+" + a.getSpecialStandardMethod();
            }
            standardMethod.add(standardMethodCode);
            for (InsProduct b : a.getInsProduct()) {
                if (b.getInsProductResult() != null) {
                    List<JSONObject> jsonObjects = JSON.parseArray(b.getInsProductResult().getEquipValue(), JSONObject.class);
                    for (JSONObject jsonObject : jsonObjects) {
                        if (!"".equals(jsonObject.get("v") + "")) {
                            List<String> v = StrUtil.split(jsonObject.get("v") + "", ",");
                            deviceSet.addAll(v);
                        }
                    }
            String standardMethodCode = baseMapper.getStandardMethodReportText(a.getStandardMethodListId());
            if (StrUtil.isNotBlank(standardMethodCode)) {
                if (StrUtil.isNotBlank(a.getSpecialStandardMethod())) {
                    standardMethodCode = standardMethodCode + "+" + a.getSpecialStandardMethod();
                }
                standardMethod.add(standardMethodCode);
            }
            // 直绑模板的检测报告、检验报告都使用新版固定结果行,不再进入旧版检验项表格逻辑。
            // 直绑模板中的承载记录没有旧检验项字段,进入旧逻辑会在格式化时产生空指针。
@@ -3272,28 +3260,6 @@
                }
                max = a.getQuantity();
                // 季度检验需要进厂检验的设备
                // 查询是否有进厂检验
                InsOrder order = insOrderMapper.selectOne(Wrappers.<InsOrder>lambdaQuery()
                        .eq(InsOrder::getIfsInventoryId, insOrder.getIfsInventoryId())
                        .ne(InsOrder::getState, -1)
                        .eq(InsOrder::getOrderType, InsOrderTypeConstants.ENTER_THE_FACTORY)
                        .ne(InsOrder::getId, insOrder.getId())
                        .last("limit 1"));
                if (order != null) {
                    List<SampleProductDto> sampleProductDtos = insSampleMapper.selectSampleProductListByOrderId(order.getId());
                    for (InsProduct b : sampleProductDtos.get(0).getInsProduct()) {
                        if (b.getInsProductResult() != null) {
                            List<JSONObject> jsonObjects = JSON.parseArray(b.getInsProductResult().getEquipValue(), JSONObject.class);
                            for (JSONObject jsonObject : jsonObjects) {
                                if (!"".equals(jsonObject.get("v") + "")) {
                                    List<String> v = StrUtil.split(jsonObject.get("v") + "", ",");
                                    deviceSet.addAll(v);
                                }
                            }
                        }
                    }
                }
                if (StringUtils.isBlank(insOrder.getSampleView())) {
                    insOrder.setSampleView(insOrder.getSample());
                }
@@ -3449,20 +3415,13 @@
        tables.forEach(table -> {
            table.put("tableSize", tables.size() + 1);
        });
        // 新订单按模板选择设备;旧订单没有模板设备关系时回退到订单级设备记录。
        Set<String> reportDeviceNumbers = insOrderTemplateDeviceMapper
                .selectManagementNumbersByOrderId(orderId).stream()
                .filter(StringUtils::isNotBlank)
        // 报告只展示检验单各模板选择的设备,并按设备ID去重。
        Set<Integer> reportDeviceIds = insOrderTemplateDeviceMapper
                .selectDeviceIdsByOrderId(orderId).stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toCollection(LinkedHashSet::new));
        if (reportDeviceNumbers.isEmpty()) {
            reportDeviceNumbers.addAll(insOrderDeviceRecordMapper.selectDeviceNumber(orderId).stream()
                    .map(InsOrderDeviceRecordDto::getManagementNumber)
                    .filter(StringUtils::isNotBlank)
                    .collect(Collectors.toList()));
        }
        reportDeviceNumbers.addAll(deviceSet);
        List<Map<String, String>> deviceList = reportDeviceNumbers.isEmpty()
                ? new ArrayList<>() : insOrderMapper.selectDeviceList(reportDeviceNumbers);
        List<Map<String, String>> deviceList = reportDeviceIds.isEmpty()
                ? new ArrayList<>() : insOrderMapper.selectDeviceListByIds(reportDeviceIds);
        if (CollectionUtils.isNotEmpty(deviceList)) {
            int count = 1;
            for (Map<String, String> stringMap : deviceList) {
@@ -3563,26 +3522,18 @@
            sendTime = reportInventory.getDeclareDate();
        }
        // 检测日期:首次保存模板值时间-首次提交时间
        // 检测日期:汇总检验单各模板填写的检测时间,日期相同显示一个,否则显示最早至最晚。
        LocalDateTime now = LocalDateTime.now();
        // 提交时间
        LocalDateTime submitTime = LocalDateTime.now();
        // 判断是否有提交时间
        if (insOrder.getFirstSubmitDate() != null) {
            submitTime = insOrder.getFirstSubmitDate();
        }
        LocalDateTime firstInspectDate = insOrder.getFirstInspectDate();
        // 字段上线前的历史订单沿用原来的下发时间,避免改变既有报告口径。
        if (firstInspectDate == null) {
            firstInspectDate = insOrder.getSendTime();
        }
        String insTime = firstInspectDate.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")) + "-"
                + submitTime.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日"));
        String insTimeEn = monthNames[firstInspectDate.getMonthValue() - 1] + " " + firstInspectDate.format(DateTimeFormatter.ofPattern("dd, yyyy")) + "-"
                + monthNames[submitTime.getMonthValue() - 1] + " " + submitTime.format(DateTimeFormatter.ofPattern("dd, yyyy"));
        List<InsOrderStandardTemplate> templateSnapshots = insOrderStandardTemplateService.list(
                Wrappers.<InsOrderStandardTemplate>lambdaQuery()
                        .eq(InsOrderStandardTemplate::getInsOrderId, orderId)
                        .orderByAsc(InsOrderStandardTemplate::getSort, InsOrderStandardTemplate::getId));
        List<LocalDate> detectionDates = templateSnapshots.stream()
                .map(InsOrderStandardTemplate::getDetectionTime)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        String insTime = formatReportTestDate(detectionDates);
        String insTimeEn = formatReportTestDateEn(detectionDates, monthNames);
        // 检验环境:优先汇总各模板填写的温湿度,报告展示全部模板的最小值到最大值。
        String environment = buildReportEnvironment(orderId, insOrder);
@@ -3620,10 +3571,6 @@
            batchNo = defaultReportText(reportInventory.getUpdateBatchNo(), reportInventory.getLotBatchNo());
        }
        // 新聚直绑模板订单:报告信息取委托信息和订单模板快照,不再取能力范围标准方法。
        List<InsOrderStandardTemplate> templateSnapshots = insOrderStandardTemplateService.list(
                Wrappers.<InsOrderStandardTemplate>lambdaQuery()
                        .eq(InsOrderStandardTemplate::getInsOrderId, orderId)
                        .orderByAsc(InsOrderStandardTemplate::getSort, InsOrderStandardTemplate::getId));
        boolean newJuTemplateOrder = !templateSnapshots.isEmpty() && directTemplateOrder;
        if (newJuTemplateOrder) {
            productName = defaultReportText(insOrder.getSampleView(), insOrder.getSample());
@@ -3636,11 +3583,8 @@
                productionDate = insOrder.getProductionDate().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日"));
            }
            batchNo = defaultReportText(insOrder.getProductionBatch(), "/");
            standardMethodText = templateSnapshots.stream()
                    .map(InsOrderStandardTemplate::getRemark)
                    .filter(StringUtils::isNotBlank)
                    .distinct()
                    .collect(Collectors.joining(";"));
            standardMethodText = defaultReportText(
                    baseMapper.getStandardMethodReportTextByCode(insOrder.getSample()), insOrder.getSample());
        }
        boolean containsOrganicChlorine = detectionResultRows.stream()
                .map(row -> row.get("itemName"))
@@ -3943,16 +3887,26 @@
        if (CollectionUtils.isEmpty(deviceList)) {
            return "/";
        }
        Set<String> lines = new LinkedHashSet<>();
        int sequence = 1;
        Set<String> equipmentItems = new LinkedHashSet<>();
        for (Map<String, String> device : deviceList) {
            String name = getMapText(device, "deviceName", "device_name");
            String managementNumber = getMapText(device, "managementNumber", "management_number");
            String line = sequence++ + ". " + defaultReportText(name, "/");
            if (StringUtils.isNotBlank(managementNumber)) {
                line += ":" + managementNumber;
            if (StringUtils.isBlank(name) || "/".equals(name.trim())) {
                continue;
            }
            lines.add(line);
            String number = StringUtils.isBlank(managementNumber) || "/".equals(managementNumber.trim())
                    ? "出厂编号" : managementNumber.trim();
            String item = name.trim() + ":" + number;
            equipmentItems.add(item);
        }
        if (equipmentItems.isEmpty()) {
            return "/";
        }
        List<String> items = new ArrayList<>(equipmentItems);
        List<String> lines = new ArrayList<>();
        for (int i = 0; i < items.size(); i++) {
            String punctuation = i == items.size() - 1 ? "。" : ";";
            lines.add((i + 1) + ". " + items.get(i) + punctuation);
        }
        return String.join("\n", lines);
    }
@@ -3973,7 +3927,7 @@
                .collect(Collectors.toList());
        String temperature = formatConditionRange(temperatures, order.getTemperature(), "℃");
        String humidity = formatConditionRange(humidities, order.getHumidity(), "%");
        String humidity = formatConditionRange(humidities, order.getHumidity(), "%RH");
        return Stream.of(temperature, humidity)
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.joining(" "));
@@ -4046,6 +4000,33 @@
        return StringUtils.isNotBlank(fallback) ? fallback : "/";
    }
    private static String formatReportTestDate(List<LocalDate> detectionDates) {
        if (CollectionUtils.isEmpty(detectionDates)) {
            return "/";
        }
        LocalDate startDate = Collections.min(detectionDates);
        LocalDate endDate = Collections.max(detectionDates);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
        if (startDate.equals(endDate)) {
            return startDate.format(formatter);
        }
        return startDate.format(formatter) + "至" + endDate.format(formatter);
    }
    private static String formatReportTestDateEn(List<LocalDate> detectionDates, String[] monthNames) {
        if (CollectionUtils.isEmpty(detectionDates)) {
            return "/";
        }
        LocalDate startDate = Collections.min(detectionDates);
        LocalDate endDate = Collections.max(detectionDates);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd, yyyy");
        String startText = monthNames[startDate.getMonthValue() - 1] + " " + startDate.format(formatter);
        if (startDate.equals(endDate)) {
            return startText;
        }
        return startText + "-" + monthNames[endDate.getMonthValue() - 1] + " " + endDate.format(formatter);
    }
    /**
     * 计算表格列宽度
     *