liusheng
3 天以前 27df1079c1d230fab29f565f5209f2a02e0def8a
smartor/src/main/java/com/smartor/service/impl/ServiceSLTDHealthcareRecordServiceImpl.java
@@ -63,6 +63,12 @@
    private SysUserRole2Mapper sysUserRoleMapper;
    @Autowired
    private MedicationItemMapper medicationItemMapper;
    @Autowired
    private MedicationDoseInfoMapper medicationDoseInfoMapper;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Value("${sltd_pub_path}")
@@ -74,13 +80,22 @@
    @Value("${lwl_app_key}")
    private String APP_KEY;
    @Value("${spring.profiles.active}")
    private String active;
    @Override
    public List<ServiceSLTDInhospResDTO> queryHealthcareRecordList(ServiceSLTDInhospReqVO reqVO) {
        try {
            Map<String, Object> requestParams = buildRequestParams(reqVO);
            Map<String, String> headers = buildRequestHeaders();
            log.info("请求参数出院数据地址:{},appKey:{}", sltdPubPath + "/osj/hbos-thirdparty-integration/standard/common/healthcareRecord/dtcQueryHealthcareRecordList", APP_KEY);
            String result = HttpUtils.sendPostByHeader(sltdPubPath + "/osj/hbos-thirdparty-integration/standard/common/healthcareRecord/dtcQueryHealthcareRecordList", new Gson().toJson(requestParams), headers);
            String result = null;
            if (reqVO.getSize() == null && reqVO.getCurrent() == null)
                result = HttpUtils.sendPostByHeader(sltdPubPath + "/osj/hbos-thirdparty-integration/standard/common/healthcareRecord/dtcQueryHealthcareRecordList", new Gson().toJson(requestParams), headers);
            else
                result = HttpUtils.sendPostByHeader(sltdPubPath + "/osj/hbos-thirdparty-integration/standard/common/healthcareRecord/dtcPageHealthcareRecordList", new Gson().toJson(requestParams), headers);
            log.info("queryHealthcareRecordList--result返回的结果值:{}", result == null ? "空值" : "有值");
            String cry = determineCry(reqVO);
            log.info("cry的值为:{}", cry);
@@ -91,6 +106,31 @@
            log.error("【queryHealthcareRecordList】调用省立同德健康记录查询接口异常,请求参数:{}", reqVO, e);
            throw new RuntimeException("调用省立同德健康记录查询接口失败:" + e.getMessage());
        }
    }
    @Override
    public Boolean queryMedicationItemList(ServiceSLTDInhospReqVO reqVO) {
        try {
            Map<String, Object> requestParams = buildRequestParams(reqVO);
            Map<String, String> headers = buildRequestHeaders();
            log.info("请求参药品信息地址:{},appKey:{}", sltdPubPath + "/hbos-thirdparty-integration/standard/base/mc/service/medication/queryMedicationInfoPage", APP_KEY);
            String result = HttpUtils.sendPostByHeader(sltdPubPath + "/hbos-thirdparty-integration/standard/base/mc/service/medication/queryMedicationInfoPage", new Gson().toJson(requestParams), headers);
            List<Map<String, Object>> dataList = getDataList(result, 2);
            for (Map<String, Object> dataItem : dataList) {
                MedicationItem medicationItem = convertToMedication(dataItem);
                log.info("medicationItem的值为:{}", medicationItem);
                medicationItemMapper.insertMedicationItem(medicationItem);
                List<MedicationDoseInfo> doseInfoList = medicationItem.getDoseInfoList();
                for (MedicationDoseInfo doseInfo : doseInfoList) {
                    doseInfo.setMedicationItemId(medicationItem.getId());
                    medicationDoseInfoMapper.insertMedicationDoseInfo(doseInfo);
                }
            }
        } catch (Exception e) {
            log.error("【queryMedicationItemList】调用省立同德药品信息查询接口异常,请求参数:{}", reqVO, e);
            throw new RuntimeException(e);
        }
        return true;
    }
@@ -132,7 +172,7 @@
            Map<String, String> headers = buildRequestHeaders();
            String result = HttpUtils.sendPostByHeader(sltdPubPath + "/osj/hbos-thirdparty-integration/standard/common/dept/queryDeptList", new Gson().toJson(params), headers);
            log.info("【queryDeptWardAreaInfoList】接口响应结果:{}", StringUtils.isEmpty(result) ? "空的" : "不空");
            List<Map<String, Object>> dataList = getDataList(result);
            List<Map<String, Object>> dataList = getDataList(result, 1);
            log.info("-----------dataList接口响应结果:{}", dataList.size());
            for (Map<String, Object> dataItem : dataList) {
                SysDept sysDept = new SysDept();
@@ -167,10 +207,15 @@
                sysDept.setUpdateTime(new Date());
                sysDept.setUpdateBy(null);
                SysDept sysDept1 = sysDeptMapper.selectDeptByCode(sysDept.getDeptCode(), sysDept.getOrgid());
                // 按 deptCode + orgid + campusid 查重,避免跨院区科室重复
                SysDept sysDept1 = sysDeptMapper.selectDeptByCodeAndCampus(sysDept.getDeptCode(), sysDept.getOrgid(), sysDept.getCampusid());
                if (Objects.isNull(sysDept1)) {
                    int i = sysDeptMapper.insertDept(sysDept);
                    log.info("ServiceExternalServiceImpl---addDeptInfo是否新增成功:{}", i);
                    try {
                        int i = sysDeptMapper.insertDept(sysDept);
                        log.info("ServiceExternalServiceImpl---addDeptInfo是否新增成功:{}", i);
                    } catch (org.springframework.dao.DuplicateKeyException e) {
                        log.warn("【queryDeptWardAreaInfoList】科室已存在(并发插入),跳过:deptCode={}, orgid={}, campusid={}", sysDept.getDeptCode(), sysDept.getOrgid(), sysDept.getCampusid());
                    }
                } else {
                    sysDept.setDeptId(sysDept1.getDeptId());
                    int i = sysDeptMapper.updateDept(sysDept);
@@ -181,20 +226,6 @@
            e.printStackTrace();
        }
        return true;
    }
    @Override
    public void aa(Map<String, Object> map) {
        List<String> types = new ArrayList<>();
        types.add("FH0109.27");
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            String jsonString = objectMapper.writeValueAsString(map);
            parseResponseData(jsonString, types, "1", "20001001");
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }
@@ -210,7 +241,7 @@
        Map<String, String> headers = buildRequestHeaders();
        String result = HttpUtils.sendPostByHeader(sltdPubPath + "/osj/hbos-thirdparty-integration/standard/common/staff/queryStaffList", new Gson().toJson(requestParams), headers);
        log.info("【queryHealthcareRecordList】接口响应结果是否有值:{}", StringUtils.isEmpty(result) ? "没值" : "有值");
        List<Map<String, Object>> dataList = getDataList(result);
        List<Map<String, Object>> dataList = getDataList(result, 1);
        for (Map<String, Object> dataItem : dataList) {
            SysUser sysUser = new SysUser();
            if (StringUtils.isEmpty(getStringValue(dataItem, "accountNo"))) {
@@ -248,19 +279,29 @@
            sysUser.setUpdateTime(new Date());
            sysUser.setUpdateBy("admin");
            sysUser.setCreateBy("admin");
            sysUser.setCreateBy("admin");
            sysUser.setOrgid("" + getLongValue(dataItem, "orgId"));
            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            sysUser.setPassword(passwordEncoder.encode(userPwd));
            SysUser sysUser1 = sysUser2Mapper.selectUserByUserName(sysUser.getUserName());
            if (ObjectUtils.isNotEmpty(sysUser1)) {
                //由人工维护的字段是不需要更新的
                //已存在:由人工维护的字段是不需要更新的,orgid/campusid保留原值不覆盖
                sysUser.setSearchscope(null);
                sysUser.setPassword(null);
                sysUser.setUserId(sysUser1.getUserId());
                sysUser.setOrgid(null);
                sysUser.setCampusid(null);
                sysUser2Mapper.updateUser(sysUser);
            } else {
                sysUser2Mapper.insertUser(sysUser);
                try {
                    sysUser2Mapper.insertUser(sysUser);
                } catch (org.springframework.dao.DuplicateKeyException e) {
                    //并发插入场景:重新查询获取已存在记录,避免重复
                    log.warn("【queryHospUserInfoList】用户已存在(并发插入),跳过:userName={}", sysUser.getUserName());
                    SysUser existingUser = sysUser2Mapper.selectUserByUserName(sysUser.getUserName());
                    if (ObjectUtils.isNotEmpty(existingUser)) {
                        sysUser.setUserId(existingUser.getUserId());
                    }
                }
            }
            // 处理用户与部门的关系
@@ -275,8 +316,8 @@
                        log.info("------businessDeptMap是否有值:{}", businessDeptMap);
                        String hisDeptId = getStringValue(businessDeptMap, "deptId");
                        log.info("------hisDeptId是否有值:{}, reqVO.getOrgId()的值为:{}", hisDeptId, reqVO.getCampusId());
                        //在这里,hisDeptId就是deptCode
                        SysDept sysDept = sysDeptMapper.selectDeptByCode(hisDeptId, reqVO.getOrgId());
                        //在这里,hisDeptId就是deptCode,按院区+机构查科室,避免跨院区查错
                        SysDept sysDept = sysDeptMapper.selectDeptByCodeAndCampus(hisDeptId, reqVO.getOrgId(), reqVO.getCampusId() != null ? reqVO.getCampusId().toString() : null);
                        log.info("------hisDeptId是否有值:{}, reqVO.getCampusId()的值为:{}", hisDeptId, reqVO.getCampusId());
                        if (Objects.isNull(sysDept)) continue;
                        SysUserDept sysUserDept = new SysUserDept();
@@ -336,17 +377,25 @@
    }
    private String determineCry(ServiceSLTDInhospReqVO reqVO) {
        if (CollectionUtils.isEmpty(reqVO.getStatusList())) return null;
        if (reqVO.getStatusList().contains("FH0109.26")) {
            //入院
            return "0";
        } else if (reqVO.getStatusList().contains("FH0109.27")) {
            //出院
            return "1";
        } else if (reqVO.getStatusList().contains("FH0109.22") || reqVO.getStatusList().contains("FH0109.23") || reqVO.getStatusList().contains("FH0109.53")) {
            //预入院
            return "3";
        if (CollectionUtils.isEmpty(reqVO.getStatusList()) && CollectionUtils.isEmpty(reqVO.getHealthcareRecordTypeList()))
            return null;
        if (reqVO.getStatusList() != null) {
            if (reqVO.getStatusList().contains("FH0109.24")) {
                //入院
                return "0";
            } else if (reqVO.getStatusList().contains("FH0109.27")) {
                //出院
                return "1";
            } else if (reqVO.getStatusList().contains("FH0109.22") || reqVO.getStatusList().contains("FH0109.23") || reqVO.getStatusList().contains("FH0109.53")) {
                //预入院
                return "3";
            }
        }
        if (reqVO.getHealthcareRecordTypeList() != null) {
            if (reqVO.getHealthcareRecordTypeList().contains("FH0108.03") || reqVO.getHealthcareRecordTypeList().contains("FH0108.01")) {
                //门急诊
                return "4";
            }
        }
        return null;
    }
@@ -357,7 +406,7 @@
            params.put("orgId", Long.parseLong(reqVO.getOrgId()));
        }
        if (reqVO.getCampusId() != null) {
            params.put("campusId", reqVO.getCampusId());
            params.put("campusIds", reqVO.getCampusId());
        }
        if (reqVO.getStartHeadTime() != null) {
            params.put("startHeadTime", reqVO.getStartHeadTime());
@@ -412,12 +461,13 @@
    private List<ServiceSLTDInhospResDTO> parseResponseData(String result, List<String> types, String cry, String campusId) {
        try {
            List<Map<String, Object>> dataList = getDataList(result);
            List<Map<String, Object>> dataList = getDataList(result, cry.equals("4") ? 2 : 1);
            log.info("【parseResponseData】成功解析dataList:{}条健康记录数据", dataList.size());
            List<ServiceSLTDInhospResDTO> resultList = new ArrayList<>();
            for (Map<String, Object> dataItem : dataList) {
                resultList.add(convertToDTO(dataItem));
            }
            log.info("【parseResponseData】成功解析{}条健康记录数据", resultList.size());
            log.info("【parseResponseData】成功解析resultList:{}条健康记录数据", resultList.size());
            processResultList(resultList, types, cry, campusId);
            return resultList;
@@ -427,11 +477,20 @@
        }
    }
    public List<Map<String, Object>> getDataList(String result) {
    /**
     * 解析接口返回数据
     *
     * @param result 接口返回数据
     * @param flag   1代表,数组在data里,2代表数组在data/records里
     * @return 解析后的数据列表
     */
    public List<Map<String, Object>> getDataList(String result, Integer flag) {
        Gson gson = new Gson();
        Type mapType = new TypeToken<Map<String, Object>>() {
        }.getType();
        Map<String, Object> responseMap = gson.fromJson(result, mapType);
        log.info("【parseResponseData】接口返回数据的responseMap:{}", Objects.isNull(responseMap) ? "空的" : "有值");
        Number codeNum = (Number) responseMap.get("code");
        String code = BigDecimal.valueOf(codeNum.longValue()).toPlainString();
        if (StringUtils.isEmpty(code) || !code.equals("200")) {
@@ -440,15 +499,30 @@
        }
        Object dataObj = responseMap.get("data");
        if (flag == 1) {
            dataObj = responseMap.get("data");
        } else if (flag == 2) {
            //门急诊的分页数据是在records中
            dataObj = ((Map<String, Object>) responseMap.get("data")).get("records");
            log.info("【parseResponseData】接口返回数据的dataObj:{}", Objects.isNull(dataObj) ? "空的" : "有值");
        }
        if (dataObj == null) {
            log.info("【parseResponseData】接口返回数据为空");
            return new ArrayList<>();
        }
        String dataJson = gson.toJson(dataObj);
        Type listType = new TypeToken<List<Map<String, Object>>>() {
        }.getType();
        List<Map<String, Object>> dataList = gson.fromJson(dataJson, listType);
        // 兼容data为数组或对象两种情况:接口正常时data为[{...}]数组,
        // 异常或空数据时可能返回{}对象,直接按List解析会抛JsonSyntaxException
        List<Map<String, Object>> dataList;
        if (dataObj instanceof List) {
            String dataJson = gson.toJson(dataObj);
            Type listType = new TypeToken<List<Map<String, Object>>>() {
            }.getType();
            dataList = gson.fromJson(dataJson, listType);
        } else {
            log.info("【parseResponseData】接口返回data不是数组,而是对象类型,data内容:{}", gson.toJson(dataObj));
            return new ArrayList<>();
        }
        // 使用 Set 去重,确保没有重复的数据
        Set<Map<String, Object>> uniqueDataSet = new HashSet<>(dataList);
@@ -473,7 +547,7 @@
                        log.info("【parseResponseData】门急诊数据已处理,跳过 type={}", type);
                    }
                    break;
                case "FH0109.26":
                case "FH0109.24":
                    log.info("【parseResponseData】解析住院数据");
                    inHospitalDate(resultList, cry);
                    break;
@@ -585,7 +659,6 @@
        queryInhosp.setSerialnum(StringUtils.trim(patMedInhosp.getSerialnum()));
        queryInhosp.setOrgid(StringUtils.trim(dto.getOrgId()));
        queryInhosp.setInhospstate(cry);
        queryInhosp.setSchemestatus(0L);
        log.info("----------------这里的入参为:{},{}", queryInhosp.getPatno(), queryInhosp.getSerialnum());
        List<PatMedInhosp> existingInhosps = patMedInhospService.selectPatMedInhosp(queryInhosp);
@@ -596,8 +669,10 @@
                queryInhosp.setInhospstate("3");
                List<PatMedInhosp> patMedInhospList = patMedInhospService.selectPatMedInhosp(queryInhosp);
                if (CollectionUtils.isNotEmpty(patMedInhospList)) {
                    //如果预入院不为空,则进行修改
                    //如果预入院不为空,则进行修改(预入院→入院)
                    patMedInhosp.setInhospid(patMedInhospList.get(0).getInhospid());
                    patMedInhospService.updatePatMedInhosp(patMedInhosp);
                    log.info("由预入院更新为入院:serialnum={}", patMedInhosp.getSerialnum());
                } else {
                    //如果出院不为空,则不进行处理
                    queryInhosp.setInhospstate("1");
@@ -674,9 +749,19 @@
            if (locked == null || Boolean.TRUE.equals(locked)) {
                try {
                    queryInhosp.setInhospstate(null);
                    queryInhosp.setSchemestatus(null);
                    queryInhosp.setPatno(null);
                    List<PatMedInhosp> patMedInhospList3 = patMedInhospService.selectPatMedInhosp(queryInhosp);
                    if (CollectionUtils.isEmpty(patMedInhospList3)) {
                        try {
                            //获取一下入院申请单
                            Map<String, String> headers = buildRequestHeaders();
                            Map<String, Object> requestParams = new HashMap<>();
                            requestParams.put("orgId", "20001001");
                            requestParams.put("20001001", patArchive.getPatidHis());
                            String result = HttpUtils.sendPostByHeader(sltdPubPath + "/hospitalizedApply/query", new Gson().toJson(requestParams), headers);
                            patMedInhospService.insertPatMedInhosp(patMedInhosp);
                            log.debug("成功插入预入院记录:serialnum={}", patMedInhosp.getSerialnum());
                        } catch (Exception e) {
@@ -726,12 +811,12 @@
        }
        if ("1".equals(cry)) {
            patMedInhosp.setInhospstate("1");
            if (CollectionUtils.isNotEmpty(dto.getDiagnosisList()) && dto.getDiagnosisList().size() > 0) {
                for (ServiceSLTDDiagnosisResDTO diagnosis : dto.getDiagnosisList()) {
                    if (diagnosis.getIsMainDiagnosis() == 1) {
                        patMedInhosp.setLeavediagname(diagnosis.getDiagnosisDictName() == null ? "" : diagnosis.getDiagnosisDictName());
                        patMedInhosp.setLeaveicd10code(diagnosis.getDiagnosisDictCode() == null ? "" : diagnosis.getDiagnosisDictCode());
                    }
            ServiceSLTDDiagnosisResDTO mainDischargeDiagnosis = dto.getMainDischargeDiagnosis();
            log.info("-----------mainDischargeDiagnosis的值有了吗?{}", mainDischargeDiagnosis);
            if (!Objects.isNull(mainDischargeDiagnosis)) {
                if (mainDischargeDiagnosis.getIsMainDiagnosis() == 1) {
                    patMedInhosp.setLeavediagname(StringUtils.defaultString(mainDischargeDiagnosis.getDiagnosisDictName(), ""));
                    patMedInhosp.setLeaveicd10code(StringUtils.defaultString(mainDischargeDiagnosis.getDiagnosisDictCode(), ""));
                }
            }
        }
@@ -763,6 +848,18 @@
        patMedInhosp.setDelFlag("0");
        patMedInhosp.setOrgid(dto.getOrgId());
        patMedInhosp.setCampusid(dto.getCampusId());
        if (StringUtils.isNotEmpty(dto.getHealthcareRecordStatus()) && dto.getHealthcareRecordStatus().equals("FH0109.25"))
            patMedInhosp.setRemark("预出院");
        if (active.equals("nhfy") && dto.getAreaId() != null && dto.getAreaId().toString().equals("40003483") && StringUtils.isNotEmpty(patMedInhosp.getPatname())) {
            //南华附一的产科,要求不生成“之子、之女、之婴”的随访任务
            if (patMedInhosp.getPatname().contains("之子") || patMedInhosp.getPatname().contains("之女") || patMedInhosp.getPatname().contains("之婴")) {
                patMedInhosp.setDeptcheckFlag("3");
                patMedInhosp.setWardcheckFlag("3");
                patMedInhosp.setDiagcheckFlag("3");
                patMedInhosp.setRemark(patMedInhosp.getRemark() + ";不生成之子、之女、之婴问卷");
            }
        }
        return patMedInhosp;
    }
@@ -789,27 +886,110 @@
        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());
        // 优先按 patientno 精确查重,查不到再按 idcardno 查重(AND条件会漏查同一人不同patientno的情况)
        if (dto.getPatientId() != null) {
            PatArchive queryByPatientNo = new PatArchive();
            queryByPatientNo.setPatientno(String.valueOf(dto.getPatientId()));
            queryByPatientNo.setIdcardno(StringUtils.isNotEmpty(dto.getIdCardNo()) ? dto.getIdCardNo().trim() : null);
            existingArchives = patArchiveService.selectPatArchiveList(queryByPatientNo);
        // 尝试获取分布式锁,最多等待 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 = 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条件漏查)
        if (CollectionUtils.isEmpty(existingArchives) && StringUtils.isNotEmpty(dto.getIdCardNo())) {
            PatArchive queryByIdCard = new PatArchive();
            queryByIdCard.setIdcardno(dto.getIdCardNo().trim());
            existingArchives = patArchiveService.selectPatArchiveList(queryByIdCard);
            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)) {
            patArchiveService.insertPatArchive(patArchive);
            log.debug("【processPatientArchive】新增患者档案,患者编号:{}", patArchive.getPatientno());
            try {
                // 最终确认查询(防御性编程:防止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());
                // 并发插入场景,重新查询获取已存在的记录
                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 {
            patArchive.setId(existingArchives.get(0).getId());
            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;
@@ -817,7 +997,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());
@@ -897,7 +1077,17 @@
        dto.setCostNatureName(getStringValue(dataItem, "costNatureName"));
        dto.setCostNatureCode(getStringValue(dataItem, "costNatureCode"));
        dto.setFurtherConsultationStatus(getIntegerValue(dataItem, "furtherConsultationStatus"));
        Object mainDiagObj = dataItem.get("mainDischargeDiagnosis");
        if (mainDiagObj instanceof Map) {
            Map<String, Object> mainDiagMap = (Map<String, Object>) mainDiagObj;
            ServiceSLTDDiagnosisResDTO mainDiag = new ServiceSLTDDiagnosisResDTO();
            mainDiag.setDiagnosisDictCode(getStringValue(mainDiagMap, "diagnosisDictCode"));
            mainDiag.setDiagnosisDictName(getStringValue(mainDiagMap, "diagnosisDictName"));
            mainDiag.setDiagnosisCategory(getStringValue(mainDiagMap, "diagnosisCategory"));
            mainDiag.setRecordType(getIntegerValue(mainDiagMap, "recordType"));
            mainDiag.setIsMainDiagnosis(getIntegerValue(mainDiagMap, "isMainDiagnosis"));
            dto.setMainDischargeDiagnosis(mainDiag);
        }
        Object contactsObj = dataItem.get("residentContactInfos");
        if (contactsObj instanceof List) {
            dto.setResidentContactInfos(parseContacts((List<?>) contactsObj));
@@ -910,6 +1100,55 @@
        return dto;
    }
    private MedicationItem convertToMedication(Map<String, Object> dataItem) {
        MedicationItem dto = new MedicationItem();
        dto.setOrgId(getLongValue(dataItem, "orgId"));
        dto.setIdentificationCode(getStringValue(dataItem, "identificationCode"));
        dto.setWbm(getStringValue(dataItem, "wbm"));
        dto.setMedicationCommonName(getStringValue(dataItem, "medicationCommonName"));
        dto.setManufacturerName(getStringValue(dataItem, "manufacturerName"));
        dto.setItemCode(getStringValue(dataItem, "itemCode"));
        dto.setSmallLargePackageRatio(getLongValue(dataItem, "smallLargePackageRatio"));
        dto.setRemark(getStringValue(dataItem, "remark"));
        dto.setItemName(getStringValue(dataItem, "itemName"));
        dto.setMedicationType(getStringValue(dataItem, "medicationType"));
        Object mainDiagObj = dataItem.get("doseInfoList");
        List<MedicationDoseInfo> doseInfoList = new ArrayList<>();
        if (mainDiagObj instanceof List) {
            List<Map<String, Object>> mainDiagList = (List<Map<String, Object>>) mainDiagObj;
            for (Map<String, Object> mainDiagMap : mainDiagList) {
                MedicationDoseInfo medicationDoseInfo = new MedicationDoseInfo();
                medicationDoseInfo.setDoseSmallPackageRation(getBigDecimalValue(mainDiagMap, "doseSmallPackageRation"));
                medicationDoseInfo.setDose(getLongValue(mainDiagMap, "dose"));
                medicationDoseInfo.setDoseSmallPackageNum(getLongValue(mainDiagMap, "doseSmallPackageNum"));
                medicationDoseInfo.setDoseUnit(getStringValue(mainDiagMap, "doseUnit"));
                medicationDoseInfo.setDoseUnitType(getLongValue(mainDiagMap, "doseUnitType"));
                doseInfoList.add(medicationDoseInfo);
            }
        }
        dto.setDoseInfoList(doseInfoList);
        dto.setAntimicrobialGradeCode(getStringValue(dataItem, "antimicrobialGradeCode"));
        dto.setLicenseNumber(getStringValue(dataItem, "licenseNumber"));
        dto.setDefaultUsageName(getStringValue(dataItem, "defaultUsageName"));
        dto.setSpecialDrugsName(getStringValue(dataItem, "specialDrugsName"));
        dto.setAntimicrobialGradeName(getStringValue(dataItem, "antimicrobialGradeName"));
        dto.setCommonPinyin(getStringValue(dataItem, "commonPinyin"));
        dto.setCommonWbm(getStringValue(dataItem, "commonWbm"));
        dto.setManufacturerId(getLongValue(dataItem, "manufacturerId"));
        dto.setDefaultUsageId(getLongValue(dataItem, "defaultUsageId"));
        dto.setSpecification(getStringValue(dataItem, "specification"));
        dto.setSmallPackageUnit(getStringValue(dataItem, "smallPackageUnit"));
        dto.setItemId(getLongValue(dataItem, "itemId"));
        dto.setSpecialDrugsCode(getStringValue(dataItem, "specialDrugsCode"));
        dto.setPinyin(getStringValue(dataItem, "pinyin"));
        dto.setDoseFormName(getStringValue(dataItem, "doseFormName"));
        dto.setLargePackageUnit(getStringValue(dataItem, "largePackageUnit"));
        dto.setRetailPrice(getBigDecimalValue(dataItem, "retailPrice"));
        dto.setStatus(getLongValue(dataItem, "status"));
        return dto;
    }
    private List<ServiceSLTDContactsResDTO> parseContacts(List<?> contactsList) {
        List<ServiceSLTDContactsResDTO> contacts = new ArrayList<>();
@@ -955,6 +1194,16 @@
        return value instanceof Number ? new BigDecimal(value.toString()).toPlainString() : value.toString();
    }
    private BigDecimal getBigDecimalValue(Map<String, Object> map, String key) {
        Object value = map.get(key);
        if (value == null) {
            return null;
        }
        // 只处理数字类型,避免科学计数法
        return new BigDecimal(value.toString());
    }
    private Long getLongValue(Map<String, Object> map, String key) {
        Object value = map.get(key);
        if (value == null) return null;