smartor/src/main/java/com/smartor/service/impl/ServiceSLTDHealthcareRecordServiceImpl.java
@@ -781,6 +781,8 @@
        patMedInhosp.setDelFlag("0");
        patMedInhosp.setOrgid(dto.getOrgId());
        patMedInhosp.setCampusid(dto.getCampusId());
        if (StringUtils.isNotEmpty(dto.getHealthcareRecordStatus()) && dto.getHealthcareRecordStatus().equals("FH0109.25"))
            patMedInhosp.setRemark("预出院");
        return patMedInhosp;
    }
@@ -807,15 +809,51 @@
        patMedInhosp.setHospitaldistrictname(dto.getAreaName());
    }
    /**
     * 处理患者档案(新增或更新)
     * 使用 Redis 分布式锁防止并发重复插入
     */
    private PatArchive processPatientArchive(ServiceSLTDInhospResDTO dto) {
        List<PatArchive> existingArchives = null;
        // 构建锁的 key:基于 patientno 或 idcardno
        String lockKey = "pat_archive_lock:" +
            (StringUtils.isNotEmpty(dto.getMedicalRecordNo()) ? dto.getMedicalRecordNo() : dto.getIdCardNo());
        // 尝试获取分布式锁,最多等待 3 秒,锁定 10 秒自动释放
        Boolean lockAcquired = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
        if (lockAcquired == null || !lockAcquired) {
            log.warn("【processPatientArchive】获取分布式锁失败,跳过本次处理(其他线程正在处理),patientno={}", dto.getMedicalRecordNo());
            // 等待一段时间后重试查询
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        try {
            return doProcessPatientArchive(dto);
        } finally {
            // 释放锁
            if (lockAcquired != null && lockAcquired) {
                redisTemplate.delete(lockKey);
            }
        }
    }
    /**
     * 实际执行患者档案处理逻辑
     */
    private PatArchive doProcessPatientArchive(ServiceSLTDInhospResDTO dto) {
        List<PatArchive> existingArchives = null;
        log.info("【processPatientArchive】新增患者档案,查询入参信息patientno:{},idcardno:{}", dto.getMedicalRecordNo(), dto.getIdCardNo());
        // 第一步:按 patientno 精确查重(与插入时使用的 medicalRecordNo 一致)
        String patientno = dto.getMedicalRecordNo() == null ? null : String.valueOf(dto.getMedicalRecordNo());
        String patientno = StringUtils.isEmpty(dto.getMedicalRecordNo()) ? null : dto.getMedicalRecordNo();
        if (StringUtils.isNotEmpty(patientno)) {
            PatArchive queryByPatientNo = new PatArchive();
            queryByPatientNo.setPatientno(patientno);
            existingArchives = patArchiveService.selectPatArchiveList(queryByPatientNo);
            log.debug("【processPatientArchive】按patientno查询,patientno={}, 结果数量={}", patientno, existingArchives.size());
        }
        // 第二步:按 patientno 查不到时,按 idcardno 查重(分步OR,避免AND条件漏查)
@@ -823,31 +861,55 @@
            PatArchive queryByIdCard = new PatArchive();
            queryByIdCard.setIdcardno(dto.getIdCardNo().trim());
            existingArchives = patArchiveService.selectPatArchiveList(queryByIdCard);
        }
        // 第三步:按 patidHis 查重(兼容旧数据,旧数据可能以 patientId 存为 patientno)
        if (CollectionUtils.isEmpty(existingArchives) && dto.getPatientId() != null) {
            PatArchive queryByPatidHis = new PatArchive();
            queryByPatidHis.setPatientno(String.valueOf(dto.getPatientId()));
            existingArchives = patArchiveService.selectPatArchiveList(queryByPatidHis);
            log.debug("【processPatientArchive】按idcardno查询,idcardno={}, 结果数量={}", dto.getIdCardNo(), existingArchives.size());
        }
        PatArchive patArchive = buildPatientArchive(dto);
        log.info("【processPatientArchive】患者档案查重完成,patientno={}, 是否已存在={}",
            patArchive.getPatientno(), CollectionUtils.isEmpty(existingArchives) ? "否" : "是(id=" + existingArchives.get(0).getId() + ")");
        if (CollectionUtils.isEmpty(existingArchives)) {
            try {
                patArchiveService.insertPatArchive(patArchive);
                log.debug("【processPatientArchive】新增患者档案,患者编号:{}", patArchive.getPatientno());
                // 最终确认查询(防御性编程:防止Redis锁失效等极端情况)
                PatArchive finalQuery = new PatArchive();
                if (StringUtils.isNotEmpty(dto.getIdCardNo())) {
                    finalQuery.setIdcardno(dto.getIdCardNo().trim());
                }
                if (StringUtils.isNotEmpty(dto.getMedicalRecordNo())) {
                    finalQuery.setPatientno(dto.getMedicalRecordNo());
                }
                List<PatArchive> finalCheck = patArchiveService.selectPatArchiveList(finalQuery);
                log.info("【processPatientArchive】最终确认查询,patientno={}, idcardno={}, 结果数量={}",
                    dto.getMedicalRecordNo(), dto.getIdCardNo(), finalCheck.size());
                if (CollectionUtils.isEmpty(finalCheck)) {
                    patArchiveService.insertPatArchive(patArchive);
                    log.info("【processPatientArchive】✓ 新增患者档案成功,patientno={}, id={}",
                        patArchive.getPatientno(), patArchive.getId());
                } else {
                    // 其他线程已经插入,直接使用已有记录
                    existingArchives = finalCheck;
                    patArchive.setId(existingArchives.get(0).getId());
                    patArchive.setNotrequiredFlag(existingArchives.get(0).getNotrequiredFlag());
                    patArchive.setNotrequiredreason(existingArchives.get(0).getNotrequiredreason());
                    log.info("【processPatientArchive】档案已被其他线程创建,使用已有记录,id={}", patArchive.getId());
                }
            } catch (org.springframework.dao.DuplicateKeyException e) {
                log.warn("【processPatientArchive】患者档案已存在(并发插入),跳过:patientno={}, idcardno={}", patArchive.getPatientno(), patArchive.getIdcardno());
                log.warn("【processPatientArchive】患者档案已存在(并发插入异常),跳过:patientno={}, idcardno={}",
                    patArchive.getPatientno(), patArchive.getIdcardno());
                // 并发插入场景,重新查询获取已存在的记录
                PatArchive queryRetry = new PatArchive();
                queryRetry.setPatientno(patArchive.getPatientno());
                if (StringUtils.isNotEmpty(patArchive.getIdcardno())) {
                    queryRetry.setIdcardno(patArchive.getIdcardno());
                }
                existingArchives = patArchiveService.selectPatArchiveList(queryRetry);
                if (CollectionUtils.isNotEmpty(existingArchives)) {
                    patArchive.setId(existingArchives.get(0).getId());
                    patArchive.setNotrequiredFlag(existingArchives.get(0).getNotrequiredFlag());
                    patArchive.setNotrequiredreason(existingArchives.get(0).getNotrequiredreason());
                    log.info("【processPatientArchive】从异常恢复,获取已有档案,id={}", patArchive.getId());
                }
            }
        } else {
@@ -855,7 +917,8 @@
            patArchive.setNotrequiredFlag(existingArchives.get(0).getNotrequiredFlag());
            patArchive.setNotrequiredreason(existingArchives.get(0).getNotrequiredreason());
            patArchiveService.updateArchive(patArchive);
            log.debug("【processPatientArchive】更新患者档案,患者编号:{}", patArchive.getPatientno());
            log.info("【processPatientArchive】✓ 更新患者档案,patientno={}, id={}",
                patArchive.getPatientno(), patArchive.getId());
        }
        return patArchive;
@@ -863,7 +926,7 @@
    private PatArchive buildPatientArchive(ServiceSLTDInhospResDTO dto) {
        PatArchive patArchive = new PatArchive();
        patArchive.setPatientno(dto.getMedicalRecordNo() == null ? null : String.valueOf(dto.getMedicalRecordNo()));
        patArchive.setPatientno(StringUtils.isEmpty(dto.getMedicalRecordNo()) ? null : dto.getMedicalRecordNo());
        patArchive.setPatidHis(dto.getPatientId() == null ? null : String.valueOf(dto.getPatientId()));
        patArchive.setIdcardno(StringUtils.isEmpty(dto.getIdCardNo()) ? "" + dto.getMedicalCardId() : dto.getIdCardNo().trim());
        patArchive.setName(dto.getPatientName());