吴羡
2026-10-24 3d397976d08f0359b8cfeb4e4f22403ae5d0c04f
inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsOrderServiceImpl.java
@@ -55,6 +55,7 @@
import com.ruoyi.inspect.vo.TemplateConditionVo;
import com.ruoyi.system.mapper.UserMapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationEventPublisher;
@@ -80,6 +81,7 @@
 * @description 针对表【ins_order(检验下单)】的数据库操作Service实现
 * @createDate 2024-03-12 16:17:55
 */
@Slf4j
@Service
@AllArgsConstructor
public class InsOrderServiceImpl extends ServiceImpl<InsOrderMapper, InsOrder>
@@ -581,6 +583,9 @@
                        .thenComparing(item -> item.getTemplateRowIndex() == null
                                ? Integer.MAX_VALUE : item.getTemplateRowIndex()))
                .collect(Collectors.toList());
        if (templateItems.isEmpty()) {
            throw new ErrorException("所选原始记录模板未配置检验项或导出值,不能下单");
        }
        StandardMethod standardMethod = standardMethodService.getById(standard.getStandardMethodId());
        if (standardMethod == null || StringUtils.isBlank(standardMethod.getCode())) {
@@ -596,6 +601,7 @@
        order.setIsExemption(0);
        order.setFactory(null);
        order.setLaboratory(standard.getLaboratory());
        order.setStandardTreeId(dto.getStandardTreeId());
        order.setSampleType(null);
        order.setSample(standardCode);
        order.setPrepareUserEn(null);
@@ -740,6 +746,9 @@
                .sorted(Comparator.comparing((TemplateInspectionItemDto item) -> templateSortMap.get(item.getTemplateId()))
                        .thenComparing(item -> item.getTemplateRowIndex() == null ? Integer.MAX_VALUE : item.getTemplateRowIndex()))
                .collect(Collectors.toList());
        if (templateItems.isEmpty()) {
            throw new ErrorException("所选原始记录模板未配置检验项或导出值,不能下单");
        }
        StandardMethod standardMethod = standardMethodService.getById(standard.getStandardMethodId());
        if (standardMethod == null || StringUtils.isBlank(standardMethod.getCode())) {
            throw new ErrorException("标准编号不存在");
@@ -754,6 +763,7 @@
        order.setIsExemption(currentOrder.getIsExemption());
        order.setFactory(null);
        order.setLaboratory(standard.getLaboratory());
        order.setStandardTreeId(dto.getStandardTreeId());
        order.setSampleType(null);
        order.setSample(standardCode);
        order.setPrepareUserEn(null);
@@ -836,9 +846,11 @@
            snapshot.setTemplateId(template.getId());
            snapshot.setName(template.getName());
            snapshot.setNumber(template.getNumber());
            snapshot.setStandardRequirement(template.getStandardRequirement());
            snapshot.setRemark(template.getRemark());
            snapshot.setThing(template.getThing());
            snapshot.setSort(selection.getSort());
            snapshot.setDeviceDefaultsInitialized(0);
            insOrderStandardTemplateMapper.insert(snapshot);
            StandardTreeTemplateBindingVo binding = bindingMap.get(selection.getTemplateId());
@@ -929,7 +941,9 @@
                        .eq(StandardMethod::getCode, insOrder.getSample())
                        .select(StandardMethod::getId)).stream()
                .map(StandardMethod::getId).collect(Collectors.toList());
        if (!methodIds.isEmpty() && !orderTemplateIds.isEmpty()) {
        if (insOrder.getStandardTreeId() != null) {
            map.put("standardTreeId", insOrder.getStandardTreeId());
        } else if (!methodIds.isEmpty() && !orderTemplateIds.isEmpty()) {
            List<StandardTree> candidates = standardTreeService.list(Wrappers.<StandardTree>lambdaQuery()
                    .in(StandardTree::getStandardMethodId, methodIds)
                    .isNull(StandardTree::getSampleType)
@@ -1053,8 +1067,14 @@
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> getInsOrderAndSample(Integer id, String laboratory) {
        Map<String, Object> map = new HashMap<>();
        try {
            initializeTemplateDevicesOnFirstOpen(id, laboratory);
        } catch (RuntimeException e) {
            log.warn("检验任务默认设备同步失败,orderId={}", id, e);
        }
//        InsOrder insOrder = insOrderMapper.selectById(id);
        IfsOrderVO ifsOrderVO = insOrderMapper.selectOrderInfoById(id);
        Map<Integer, List<Integer>> templateDeviceIds = insOrderTemplateDeviceMapper.selectList(
@@ -1072,6 +1092,7 @@
                                .select(InsOrderStandardTemplate::getTemplateId,
                                        InsOrderStandardTemplate::getTemperature,
                                        InsOrderStandardTemplate::getDetectionTime,
                                        InsOrderStandardTemplate::getDetectionEndTime,
                                        InsOrderStandardTemplate::getDetectionPlace,
                                        InsOrderStandardTemplate::getInsResult)
                                .orderByAsc(InsOrderStandardTemplate::getSort,
@@ -1081,6 +1102,8 @@
                    condition.setTemplateId(snapshot.getTemplateId());
                    condition.setTemperature(snapshot.getTemperature());
                    condition.setDetectionTime(snapshot.getDetectionTime());
                    condition.setDetectionEndTime(snapshot.getDetectionEndTime() == null
                            ? snapshot.getDetectionTime() : snapshot.getDetectionEndTime());
                    condition.setDetectionPlace(snapshot.getDetectionPlace());
                    condition.setInsResult(snapshot.getInsResult());
                    condition.setDeviceIds(templateDeviceIds.getOrDefault(
@@ -1097,6 +1120,165 @@
        return map;
    }
    /**
     * 打开检验任务时,把尚未被人工改动过的模板设备同步为标准库当前绑定的设备;
     * 检验员手动增删过的模板以人工为准,不再自动填充。
     */
    private void initializeTemplateDevicesOnFirstOpen(Integer orderId, String laboratory) {
        InsOrder order = insOrderMapper.selectById(orderId);
        if (order == null || !Objects.equals(order.getTypeSource(), -1)
                || !Objects.equals(order.getState(), 1)
                || "QUALITY_MONITOR".equals(order.getTaskSource())) {
            return;
        }
        if (StringUtils.isNotBlank(laboratory)) {
            InsOrderState orderState = insOrderStateService.getOne(Wrappers.<InsOrderState>lambdaQuery()
                    .eq(InsOrderState::getInsOrderId, orderId)
                    .eq(InsOrderState::getLaboratory, laboratory)
                    .last("limit 1"));
            // 仅待检、在检阶段同步;进入复核等后续状态后以保存下来的设备为准。
            if (orderState != null && orderState.getInsState() != null
                    && orderState.getInsState() != 0 && orderState.getInsState() != 1) {
                return;
            }
        }
        List<InsOrderStandardTemplate> snapshots = insOrderStandardTemplateMapper.selectList(
                Wrappers.<InsOrderStandardTemplate>lambdaQuery()
                        .eq(InsOrderStandardTemplate::getInsOrderId, orderId)
                        .select(InsOrderStandardTemplate::getId,
                                InsOrderStandardTemplate::getTemplateId,
                                InsOrderStandardTemplate::getDeviceDefaultsInitialized)
                        .orderByAsc(InsOrderStandardTemplate::getSort, InsOrderStandardTemplate::getId)
                        .last("FOR UPDATE"));
        if (snapshots.isEmpty() || snapshots.stream().allMatch(
                snapshot -> Objects.equals(snapshot.getDeviceDefaultsInitialized(), 1))) {
            return;
        }
        Map<Integer, List<InsOrderTemplateDevice>> existingDevices = insOrderTemplateDeviceMapper.selectList(
                        Wrappers.<InsOrderTemplateDevice>lambdaQuery()
                                .eq(InsOrderTemplateDevice::getInsOrderId, orderId)
                                .orderByAsc(InsOrderTemplateDevice::getSort, InsOrderTemplateDevice::getId))
                .stream().filter(relation -> relation.getTemplateId() != null)
                .collect(Collectors.groupingBy(InsOrderTemplateDevice::getTemplateId));
        Map<Integer, List<Integer>> defaults = findStandardDeviceDefaults(order, snapshots);
        for (InsOrderStandardTemplate snapshot : snapshots) {
            // 检验员手动选择或清空过的模板以人工为准,不再套用标准库默认值。
            if (Objects.equals(snapshot.getDeviceDefaultsInitialized(), 1)) {
                continue;
            }
            Integer templateId = snapshot.getTemplateId();
            if (templateId == null) {
                continue;
            }
            List<InsOrderTemplateDevice> currentDevices = existingDevices.getOrDefault(
                    templateId, Collections.emptyList());
            // 旧数据没有初始化标记,已有设备视为人工选择,标记后不再自动覆盖。
            if (snapshot.getDeviceDefaultsInitialized() == null && !currentDevices.isEmpty()) {
                insOrderStandardTemplateMapper.update(null,
                        Wrappers.<InsOrderStandardTemplate>lambdaUpdate()
                                .eq(InsOrderStandardTemplate::getId, snapshot.getId())
                                .set(InsOrderStandardTemplate::getDeviceDefaultsInitialized, 1));
                continue;
            }
            if (!defaults.containsKey(templateId)) {
                continue;
            }
            List<Integer> standardDeviceIds = defaults.get(templateId).stream()
                    .filter(Objects::nonNull).distinct().collect(Collectors.toList());
            List<Integer> currentDeviceIds = currentDevices.stream()
                    .map(InsOrderTemplateDevice::getDeviceId)
                    .filter(Objects::nonNull).distinct().collect(Collectors.toList());
            if (currentDeviceIds.equals(standardDeviceIds)) {
                continue;
            }
            // 未初始化过的模板完全对齐标准库绑定:绑定几个就显示几个。
            insOrderTemplateDeviceMapper.delete(
                    Wrappers.<InsOrderTemplateDevice>lambdaQuery()
                            .eq(InsOrderTemplateDevice::getInsOrderId, orderId)
                            .eq(InsOrderTemplateDevice::getTemplateId, templateId));
            for (int index = 0; index < standardDeviceIds.size(); index++) {
                InsOrderTemplateDevice relation = new InsOrderTemplateDevice();
                relation.setInsOrderId(orderId);
                relation.setTemplateId(templateId);
                relation.setDeviceId(standardDeviceIds.get(index));
                relation.setSort(index);
                insOrderTemplateDeviceMapper.insert(relation);
            }
        }
    }
    private Map<Integer, List<Integer>> findStandardDeviceDefaults(InsOrder order,
            List<InsOrderStandardTemplate> snapshots) {
        Set<Integer> templateIds = snapshots.stream().map(InsOrderStandardTemplate::getTemplateId)
                .filter(Objects::nonNull).collect(Collectors.toSet());
        Integer standardTreeId = order.getStandardTreeId();
        if (standardTreeId == null && StringUtils.isNotBlank(order.getSample()) && !templateIds.isEmpty()) {
            List<Integer> methodIds = standardMethodService.list(Wrappers.<StandardMethod>lambdaQuery()
                            .eq(StandardMethod::getCode, order.getSample())
                            .select(StandardMethod::getId)).stream()
                    .map(StandardMethod::getId).collect(Collectors.toList());
            if (!methodIds.isEmpty()) {
                List<StandardTree> candidates = standardTreeService.list(Wrappers.<StandardTree>lambdaQuery()
                        .in(StandardTree::getStandardMethodId, methodIds)
                        .eq(StandardTree::getLaboratory, order.getLaboratory())
                        .isNotNull(StandardTree::getSample)
                        .isNull(StandardTree::getSampleType)
                        .isNull(StandardTree::getModel));
                if (candidates.size() == 1) {
                    // 同一标准编号、同一实验室只有一个二级节点时直接认定,
                    // 避免标准库调整过模板后旧订单匹配不上。
                    standardTreeId = candidates.get(0).getId();
                } else if (!candidates.isEmpty()) {
                    List<StandardTree> matches = candidates.stream()
                            .filter(tree -> StringUtils.isNotBlank(tree.getSample()))
                            .filter(tree -> {
                                Set<Integer> boundIds = standardTreeService.selectTemplateBindings(tree.getId()).stream()
                                        .map(StandardTreeTemplateBindingVo::getTemplateId).collect(Collectors.toSet());
                                return boundIds.containsAll(templateIds);
                            }).collect(Collectors.toList());
                    if (matches.size() == 1) {
                        standardTreeId = matches.get(0).getId();
                    } else if (!matches.isEmpty()) {
                        List<StandardTree> exact = matches.stream().filter(tree ->
                                standardTreeService.selectTemplateBindings(tree.getId()).stream()
                                        .map(StandardTreeTemplateBindingVo::getTemplateId)
                                        .collect(Collectors.toSet()).equals(templateIds))
                                .collect(Collectors.toList());
                        if (exact.size() == 1) {
                            standardTreeId = exact.get(0).getId();
                        }
                    }
                }
            }
        }
        if (standardTreeId == null) {
            return Collections.emptyMap();
        }
        StandardTree standard = standardTreeService.getById(standardTreeId);
        if (standard == null || StringUtils.isBlank(standard.getSample())
                || !Objects.equals(standard.getLaboratory(), order.getLaboratory())
                || standard.getSampleType() != null || standard.getModel() != null) {
            return Collections.emptyMap();
        }
        if (order.getStandardTreeId() == null) {
            insOrderMapper.update(null, Wrappers.<InsOrder>lambdaUpdate()
                    .eq(InsOrder::getId, order.getId())
                    .isNull(InsOrder::getStandardTreeId)
                    .set(InsOrder::getStandardTreeId, standardTreeId));
        }
        List<StandardTreeTemplateBindingVo> bindings = standardTreeService.selectTemplateBindings(standardTreeId);
        Map<Integer, List<Integer>> defaults = new HashMap<>();
        for (StandardTreeTemplateBindingVo binding : bindings) {
            if (templateIds.contains(binding.getTemplateId())) {
                defaults.put(binding.getTemplateId(), binding.getDeviceIds() == null
                        ? Collections.emptyList() : binding.getDeviceIds());
            }
        }
        return defaults;
    }
    @Override
    public IPage<SampleProductDto2> selectSampleAndProductByOrderId(IPage<SampleProductDto2> page, SampleProductDto2 sampleProductDto) {
        IPage<SampleProductDto2> productDto2IPage = insOrderMapper.selectSampleAndProductByOrderId(page,