inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java
@@ -507,6 +507,64 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int addNewJuInsOrder(InsPlaceOrderDto dto) {
        return createNewJuOrder(dto, null, false);
    }
    /**
     * 批量下单:公共委托信息只填一次,后台按样品逐条拆成独立委托单并共享批次号。
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int addBatchNewJuInsOrder(InsBatchPlaceOrderDto dto) {
        if (dto == null || dto.getInsOrder() == null) {
            throw new ErrorException("下单信息不能为空");
        }
        List<InsBatchSampleDto> rows = dto.getSampleList();
        if (CollectionUtils.isEmpty(rows)) {
            throw new ErrorException("请至少添加一个样品");
        }
        // 只有一个样品时按普通单样品下单处理,不产生批次
        if (rows.size() == 1) {
            return createNewJuOrder(buildBatchRowOrder(dto.getInsOrder(), rows.get(0)), null, false);
        }
        String batchNo = "PC" + DateUtil.format(new Date(), "yyyyMMddHHmmssSSS");
        int firstOrderId = 0;
        for (InsBatchSampleDto row : rows) {
            int orderId = createNewJuOrder(buildBatchRowOrder(dto.getInsOrder(), row), batchNo, true);
            if (firstOrderId == 0) {
                firstOrderId = orderId;
            }
        }
        return firstOrderId;
    }
    private InsPlaceOrderDto buildBatchRowOrder(InsOrder common, InsBatchSampleDto row) {
        if (common == null || row == null) {
            throw new ErrorException("下单信息不能为空");
        }
        if (row.getStandardTreeId() == null) {
            throw new ErrorException("请为每个样品选择检测依据");
        }
        if (StringUtils.isBlank(row.getSampleCode()) || row.getSampleCode().trim().length() < 2) {
            throw new ErrorException("样品编号不能为空且不能少于2位");
        }
        InsOrder order = new InsOrder();
        BeanUtils.copyProperties(common, order);
        order.setId(null);
        order.setEntrustCode(null);
        order.setBatchNo(null);
        order.setSampleView(row.getSampleView());
        order.setTestQuantity(row.getTestQuantity());
        order.setSampleStatus(row.getSampleStatus());
        InsPlaceOrderDto single = new InsPlaceOrderDto();
        single.setInsOrder(order);
        single.setStandardTreeId(row.getStandardTreeId());
        single.setSampleCode(row.getSampleCode());
        single.setTemplateList(row.getTemplateList());
        return single;
    }
    private int createNewJuOrder(InsPlaceOrderDto dto, String batchNo, boolean batchEntrustFallback) {
        if (dto == null || dto.getInsOrder() == null || dto.getStandardTreeId() == null) {
            throw new ErrorException("下单信息或标准不能为空");
        }
@@ -598,6 +656,7 @@
        InsOrder order = dto.getInsOrder();
        order.setId(null);
        order.setBatchNo(StringUtils.isBlank(batchNo) ? null : batchNo);
        // 新聚下单免审核:直接受理,下单即流转到样品接收
        order.setState(1);
        order.setExamineTime(LocalDateTime.now());
@@ -658,6 +717,10 @@
        // 下单时生成委托编号并校验唯一性,重复则提示,避免留到审核才报错。
        String entrustCode = buildEntrustCode(order, Collections.singletonList(sample));
        if (batchEntrustFallback && isEntrustCodeUsed(entrustCode)) {
            // 批量下单时不同样品编号末两位可能相同,改用当天顺延编号兜底
            entrustCode = buildNextAvailableEntrustCode(order);
        }
        assertEntrustCodeUnique(entrustCode, order.getId());
        insOrderMapper.update(null, Wrappers.<InsOrder>lambdaUpdate()
                .eq(InsOrder::getId, order.getId())
@@ -1050,6 +1113,23 @@
        }
    }
    private boolean isEntrustCodeUsed(String entrustCode) {
        return StringUtils.isNotBlank(entrustCode) && insOrderMapper.selectCount(Wrappers.<InsOrder>lambdaQuery()
                .eq(InsOrder::getEntrustCode, entrustCode)) > 0;
    }
    private String buildNextAvailableEntrustCode(InsOrder order) {
        LocalDate entrustDate = order.getSampleDate() == null ? LocalDate.now() : order.getSampleDate();
        String prefix = "LMSY-" + entrustDate.format(DateTimeFormatter.BASIC_ISO_DATE) + "-";
        for (int seq = 1; seq <= 99; seq++) {
            String candidate = prefix + String.format("%02d", seq);
            if (!isEntrustCodeUsed(candidate)) {
                return candidate;
            }
        }
        throw new ErrorException("当天委托编号已用尽,请调整样品编号");
    }
    /**
     * 生成委托编号:新聚直绑模板订单末两位取样品编号末两位,其余按送样日期生成序号。
     */