| | |
| | | import com.ruoyi.common.core.domain.entity.SysUserDept; |
| | | import com.ruoyi.common.core.domain.entity.SysUserRole; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.smartor.common.enums.EmergencyLevelEnum; |
| | | import com.smartor.common.enums.ImportFlagEnum; |
| | | import com.ruoyi.common.utils.http.HttpUtils; |
| | | import com.smartor.common.DistinctByProperty; |
| | | import com.smartor.domain.*; |
| | |
| | | private SysUserRole2Mapper sysUserRoleMapper; |
| | | |
| | | @Autowired |
| | | private MedicationItemMapper medicationItemMapper; |
| | | |
| | | @Autowired |
| | | private MedicationDoseInfoMapper medicationDoseInfoMapper; |
| | | |
| | | @Autowired |
| | | private RedisTemplate<String, String> redisTemplate; |
| | | |
| | | @Value("${sltd_pub_path}") |
| | |
| | | @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); |
| | |
| | | } catch (Exception e) { |
| | | log.error("【queryHealthcareRecordList】调用省立同德健康记录查询接口异常,请求参数:{}", reqVO, e); |
| | | throw new RuntimeException("调用省立同德健康记录查询接口失败:" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | /** |
| | | * 查询药品信息列表 |
| | | * @return 返回实际获取到的药品数据条数,如果出错则返回 null |
| | | */ public Integer 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); |
| | | log.info("【queryMedicationItemList】共获取到{}条药品数据", dataList.size()); |
| | | int successCount = 0; |
| | | int failCount = 0; |
| | | for (Map<String, Object> dataItem : dataList) { |
| | | try { |
| | | MedicationItem medicationItem = convertToMedication(dataItem); |
| | | log.info("准备插入药品数据:itemName={}, itemCode={}", medicationItem.getItemName(), medicationItem.getItemCode()); |
| | | medicationItem.setCreateTime(new Date()); |
| | | medicationItemMapper.insertMedicationItem(medicationItem); |
| | | |
| | | // 如果插入成功且返回了自增 ID,则插入子表 |
| | | if (medicationItem.getId() != null) { |
| | | List<MedicationDoseInfo> doseInfoList = medicationItem.getDoseInfoList(); |
| | | if (CollectionUtils.isNotEmpty(doseInfoList)) { |
| | | for (MedicationDoseInfo doseInfo : doseInfoList) { |
| | | try { |
| | | doseInfo.setMedicationItemId(medicationItem.getId()); |
| | | medicationDoseInfoMapper.insertMedicationDoseInfo(doseInfo); |
| | | log.debug("插入剂量信息成功:itemId={}, doseUnit={}", medicationItem.getId(), doseInfo.getDoseUnit()); |
| | | } catch (Exception e) { |
| | | log.warn("插入剂量信息失败:itemId={}, doseUnit={}, 错误:{}", medicationItem.getId(), doseInfo.getDoseUnit(), e.getMessage(), e); |
| | | failCount++; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | successCount++; |
| | | log.info("✓ 药品数据插入成功:{}", medicationItem.getItemName()); |
| | | } catch (Exception e) { |
| | | log.warn("【queryMedicationItemList】单条药品数据插入失败:itemName={}, itemCode={}, 错误:{}", dataItem.get("itemName"), dataItem.get("itemCode"), e.getMessage(), e); |
| | | failCount++; |
| | | // 继续处理下一条数据,不中断整个循环 |
| | | } |
| | | } |
| | | log.info("【queryMedicationItemList】批量插入完成,总数:{}, 成功:{}, 失败:{}", dataList.size(), successCount, failCount); |
| | | // 返回实际获取到的药品数据条数,用于分页判断是否还有更多数据 |
| | | return dataList.size(); |
| | | } catch (Exception e) { |
| | | log.error("【queryMedicationItemList】调用省立同德药品信息查询接口异常,请求参数:{}", reqVO, e); |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | |
| | | 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(); |
| | |
| | | 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(); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 采集医院用户信息 |
| | |
| | | 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"))) { |
| | |
| | | } |
| | | |
| | | 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; |
| | | } |
| | |
| | | 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()); |
| | |
| | | |
| | | 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; |
| | |
| | | } |
| | | } |
| | | |
| | | 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")) { |
| | |
| | | } |
| | | |
| | | 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); |
| | |
| | | log.info("【parseResponseData】门急诊数据已处理,跳过 type={}", type); |
| | | } |
| | | break; |
| | | case "FH0109.26": |
| | | case "FH0109.24": |
| | | log.info("【parseResponseData】解析住院数据"); |
| | | inHospitalDate(resultList, cry); |
| | | break; |
| | |
| | | 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) { |
| | |
| | | patMedInhosp.setSerialnum(dto.getHealthcareRecordNo()); |
| | | patMedInhosp.setInhospno(dto.getHealthcareRecordNo()); |
| | | patMedInhosp.setFuflag("1"); |
| | | |
| | | |
| | | if (StringUtils.isNotEmpty(patArchive.getNotrequiredFlag()) && patArchive.getNotrequiredFlag().equals("1")) |
| | | patMedInhosp.setFuflag("0"); |
| | |
| | | setDischargeInfo(patMedInhosp, dto); |
| | | } else { |
| | | setAdmissionInfo(patMedInhosp, dto); |
| | | patMedInhosp.setEncounterSourceId(dto.getEncounterSourceId() == null ? "" : dto.getEncounterSourceId()); |
| | | if (StringUtils.isNotEmpty(dto.getEncounterSourceId())) { |
| | | //根据 encounterSourceId 获取 importanceFlagCode emergencyLevelCode |
| | | Map<String, String> applyInfo = hospitalizedApply(dto.getEncounterSourceId(), dto.getOrgId()); |
| | | patMedInhosp.setImportanceFlagCode(applyInfo.get("importanceFlagCode")); |
| | | patMedInhosp.setEmergencyLevelCode(applyInfo.get("emergencyLevelCode")); |
| | | } |
| | | } |
| | | |
| | | patMedInhosp.setDrname(dto.getDoctorName()); |
| | |
| | | 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() + ";不生成之子、之女、之婴问卷"); |
| | | } |
| | | } |
| | | |
| | | if (active.equals("nhfy") || active.equals("sltd")) { |
| | | Map<String, String> drugInfoMap = queryMedicalOrders(dto); |
| | | if (drugInfoMap != null && !drugInfoMap.isEmpty()) { |
| | | patMedInhosp.setMedicalName(drugInfoMap.get("drugItemNames")); |
| | | patMedInhosp.setMedicalCode(drugInfoMap.get("drugItemIds")); |
| | | patMedInhosp.setMedicalCompany(drugInfoMap.get("drugManufacturerNames")); |
| | | |
| | | log.info("获取药品信息成功:名称={}, 编码={}, 厂家={}", drugInfoMap.get("drugItemNames"), drugInfoMap.get("drugItemIds"), drugInfoMap.get("drugManufacturerNames")); |
| | | } |
| | | } |
| | | return patMedInhosp; |
| | | } |
| | | |
| | | /** |
| | | * 查询医嘱信息并拼接药品信息 |
| | | * |
| | | * @param dto 健康记录请求对象 |
| | | * @return 返回包含三个字段 Map: |
| | | * - drugItemNames: 药品名称列表(逗号分隔) |
| | | * - drugItemIds: 药品编码列表(逗号分隔) |
| | | * - drugManufacturerNames: 药品厂家列表(逗号分隔) |
| | | * <p> |
| | | * 规则: |
| | | * 1. 三个字段顺序位置保持一致 |
| | | * 2. 如果三个字段都为空,则跳过该记录 |
| | | * 3. 如果至少有一个字段有值,则其他两个为空用空字符串代替 |
| | | */ |
| | | private Map<String, String> queryMedicalOrders(ServiceSLTDInhospResDTO dto) { |
| | | Map<String, String> result = new HashMap<>(); |
| | | List<String> itemNames = new ArrayList<>(); |
| | | List<String> itemIds = new ArrayList<>(); |
| | | List<String> manufacturerNames = new ArrayList<>(); |
| | | |
| | | try { |
| | | // 获取患者的医嘱信息 |
| | | Map<String, Object> medicineInfoReq = new HashMap<>(); |
| | | medicineInfoReq.put("orgId", dto.getOrgId()); |
| | | medicineInfoReq.put("patientId", dto.getPatientId()); |
| | | medicineInfoReq.put("campusId", dto.getCampusId()); |
| | | medicineInfoReq.put("medicalRecordNo", dto.getMedicalRecordNo()); |
| | | log.info("【queryMedicalOrders】请求参数:{}", medicineInfoReq); |
| | | Map<String, String> headers = buildRequestHeaders(); |
| | | String resultStr = HttpUtils.sendPostByHeader(sltdPubPath + "/osj/hbos-thirdparty-integration/standard/common/doctorOrder/queryDoctorOrderList", new Gson().toJson(medicineInfoReq), headers); |
| | | |
| | | if (StringUtils.isEmpty(resultStr)) { |
| | | log.warn("【queryMedicalOrders】接口返回为空,patientId={}", dto.getPatientId()); |
| | | return result; |
| | | } |
| | | |
| | | // 解析返回数据 |
| | | Gson gson = new Gson(); |
| | | Type mapType = new TypeToken<Map<String, Object>>() { |
| | | }.getType(); |
| | | Map<String, Object> responseMap = gson.fromJson(resultStr, mapType); |
| | | |
| | | // 检查返回码 |
| | | Object codeObj = responseMap.get("code"); |
| | | if (codeObj != null) { |
| | | String code = BigDecimal.valueOf(((Number) codeObj).longValue()).toPlainString(); |
| | | if (!"200".equals(code)) { |
| | | log.error("【queryMedicalOrders】接口返回失败,code={}, message={}", code, responseMap.get("message")); |
| | | return result; |
| | | } |
| | | } |
| | | |
| | | // 获取 data 数组 |
| | | Object dataObj = responseMap.get("data"); |
| | | if (dataObj instanceof List) { |
| | | List<?> dataList = (List<?>) dataObj; |
| | | |
| | | // 遍历医嘱列表,提取药品信息 |
| | | Set<String> processedItemIds = new HashSet<>(); // 用于去重(只根据 itemId 去重) |
| | | |
| | | for (Object item : dataList) { |
| | | if (item instanceof Map) { |
| | | Map<String, Object> itemMap = (Map<String, Object>) item; |
| | | |
| | | // 只处理药品相关的医嘱(itemDomain 为 FH0134.01 表示药品) |
| | | Object itemDomainObj = itemMap.get("itemDomain"); |
| | | if (itemDomainObj == null || !"FH0134.01".equals(itemDomainObj.toString())) { |
| | | continue; |
| | | } |
| | | |
| | | // 获取三个字段 |
| | | Object itemNameObj = itemMap.get("itemName"); |
| | | Object itemIdObj = itemMap.get("itemId"); |
| | | Object manufacturerNameObj = itemMap.get("manufacturerName"); |
| | | |
| | | // 判断是否都为空 |
| | | boolean allEmpty = (itemNameObj == null || StringUtils.isEmpty(itemNameObj.toString())) && (itemIdObj == null || StringUtils.isEmpty(itemIdObj.toString())) && (manufacturerNameObj == null || StringUtils.isEmpty(manufacturerNameObj.toString())); |
| | | |
| | | // 如果三个都为空,则跳过 |
| | | if (allEmpty) { |
| | | continue; |
| | | } |
| | | |
| | | // 至少有一个有值,处理每个字段 |
| | | String itemName = (itemNameObj != null && StringUtils.isNotEmpty(itemNameObj.toString())) ? itemNameObj.toString() : ""; |
| | | |
| | | // itemId 特殊处理:避免科学计数法(Gson 可能将数字解析为 Double) |
| | | String itemId = ""; |
| | | if (itemIdObj != null && StringUtils.isNotEmpty(itemIdObj.toString())) { |
| | | if (itemIdObj instanceof Number) { |
| | | // 如果是数值类型,转换为整数字符串,避免科学计数法 |
| | | itemId = String.valueOf(((Number) itemIdObj).longValue()); |
| | | } else { |
| | | itemId = itemIdObj.toString(); |
| | | } |
| | | } |
| | | |
| | | String manufacturerName = (manufacturerNameObj != null && StringUtils.isNotEmpty(manufacturerNameObj.toString())) ? manufacturerNameObj.toString() : ""; |
| | | |
| | | // 只根据 itemId 去重(同一编码的药品只保留一个) |
| | | if (StringUtils.isNotEmpty(itemId)) { |
| | | if (processedItemIds.contains(itemId)) { |
| | | log.info("【queryMedicalOrders】跳过重复药品(相同编码):名称={}, 编码={}", itemName, itemId); |
| | | continue; |
| | | } |
| | | processedItemIds.add(itemId); |
| | | } else { |
| | | // itemId 为空时,使用 itemName 作为去重依据 |
| | | if (processedItemIds.contains(itemName)) { |
| | | log.info("【queryMedicalOrders】跳过重复药品(相同名称):名称={}", itemName); |
| | | continue; |
| | | } |
| | | processedItemIds.add(itemName); |
| | | } |
| | | |
| | | // 添加到列表 |
| | | itemNames.add(itemName); |
| | | itemIds.add(itemId); |
| | | manufacturerNames.add(manufacturerName); |
| | | |
| | | log.info("【queryMedicalOrders】提取药品信息:名称={}, 编码={}, 厂家={}", itemName, itemId, manufacturerName); |
| | | } |
| | | } |
| | | } else { |
| | | log.info("【queryMedicalOrders】data 不是数组类型,patientId={}", dto.getPatientId()); |
| | | } |
| | | |
| | | // 将列表拼接成逗号分隔的字符串 |
| | | if (!itemNames.isEmpty()) { |
| | | result.put("drugItemNames", String.join(",", itemNames)); |
| | | result.put("drugItemIds", String.join(",", itemIds)); |
| | | result.put("drugManufacturerNames", String.join(",", manufacturerNames)); |
| | | } |
| | | |
| | | log.info("【queryMedicalOrders】成功提取{}条药品信息,patientId={}", itemNames.size(), dto.getPatientId()); |
| | | |
| | | } catch (Exception e) { |
| | | log.error("【queryMedicalOrders】查询医嘱信息失败,patientId={}", dto.getPatientId(), e); |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | |
| | | private void setDischargeInfo(PatMedInhosp patMedInhosp, ServiceSLTDInhospResDTO dto) { |
| | |
| | | patMedInhosp.setHospitaldistrictname(dto.getAreaName()); |
| | | } |
| | | |
| | | /** |
| | | * 根据入院申请单ID查询入院申请单详情 |
| | | * 只提取 importanceFlagCode(importanceFlagCodeList逗号拼接)和 emergencyLevelCode 两个值 |
| | | */ |
| | | private Map<String, String> hospitalizedApply(String encounterSourceId, String orgid) { |
| | | Map<String, String> applyInfo = new HashMap<>(); |
| | | Map<String, String> headers = buildRequestHeaders(); |
| | | log.info("院申请单ID查询入院申请单:{},appKey:{}", sltdPubPath + "/sf/hospitalizedApply/query", APP_KEY); |
| | | //设置入参 |
| | | Map<String, Object> requestParams = new HashMap<>(); |
| | | requestParams.put("applyId", encounterSourceId); |
| | | requestParams.put("orgId", orgid); |
| | | |
| | | String result = null; |
| | | if (StringUtils.isNotEmpty(encounterSourceId) && StringUtils.isNotEmpty(orgid)) |
| | | result = HttpUtils.sendPostByHeader(sltdPubPath + "/sf/hospitalizedApply/query", new Gson().toJson(requestParams), headers); |
| | | |
| | | if (StringUtils.isEmpty(result)) { |
| | | log.error("【hospitalizedApply】接口返回为空,applyId={}", encounterSourceId); |
| | | return applyInfo; |
| | | } |
| | | try { |
| | | Gson gson = new Gson(); |
| | | Type mapType = new TypeToken<Map<String, Object>>() { |
| | | }.getType(); |
| | | Map<String, Object> responseMap = gson.fromJson(result, mapType); |
| | | Object dataObj = responseMap == null ? null : responseMap.get("data"); |
| | | if (dataObj instanceof Map) { |
| | | Map<String, Object> data = (Map<String, Object>) dataObj; |
| | | //重要性标记编码,接口返回是数组,需要转换为字典名称 |
| | | Object importanceFlagCodeListObj = data.get("importanceFlagCodeList"); |
| | | if (importanceFlagCodeListObj instanceof List) { |
| | | List<?> importanceFlagCodeList = (List<?>) importanceFlagCodeListObj; |
| | | // 过滤掉 null 值 |
| | | List<String> nonNullList = importanceFlagCodeList.stream().filter(Objects::nonNull).map(Object::toString).filter(StringUtils::isNotEmpty).collect(Collectors.toList()); |
| | | |
| | | if (!nonNullList.isEmpty()) { |
| | | String importanceFlagLabel; |
| | | if (nonNullList.size() == 1) { |
| | | // 只有一个值,直接通过枚举获取描述 |
| | | importanceFlagLabel = ImportFlagEnum.getDescByCode(nonNullList.get(0)); |
| | | } else { |
| | | // 多个值,用逗号拼接枚举描述 |
| | | StringBuilder labelBuilder = new StringBuilder(); |
| | | for (String code : nonNullList) { |
| | | String label = ImportFlagEnum.getDescByCode(code); |
| | | if (StringUtils.isNotEmpty(label)) { |
| | | labelBuilder.append(label).append(","); |
| | | } |
| | | } |
| | | importanceFlagLabel = StringUtils.stripEnd(labelBuilder.toString(), ","); |
| | | } |
| | | |
| | | if (StringUtils.isNotEmpty(importanceFlagLabel)) { |
| | | applyInfo.put("importanceFlagCode", importanceFlagLabel); |
| | | } |
| | | } |
| | | } |
| | | //紧急程度编码,通过枚举转换描述 |
| | | Object emergencyLevelCodeObj = data.get("emergencyLevelCode"); |
| | | if (emergencyLevelCodeObj != null) { |
| | | String emergencyLevelLabel = EmergencyLevelEnum.getDescByCode(emergencyLevelCodeObj.toString()); |
| | | if (StringUtils.isNotEmpty(emergencyLevelLabel)) { |
| | | applyInfo.put("emergencyLevelCode", emergencyLevelLabel); |
| | | } |
| | | } |
| | | } else { |
| | | log.error("【hospitalizedApply】接口返回data不是对象,applyId={},result:{}", encounterSourceId, result); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("【hospitalizedApply】解析入院申请单详情失败,applyId={}", encounterSourceId, e); |
| | | } |
| | | log.info("【hospitalizedApply】applyId={},importanceFlagCode={},emergencyLevelCode={}", encounterSourceId, applyInfo.get("importanceFlagCode"), applyInfo.get("emergencyLevelCode")); |
| | | return applyInfo; |
| | | } |
| | | |
| | | /** |
| | | * 处理患者档案(新增或更新) |
| | | * 使用 Redis 分布式锁防止并发重复插入 |
| | | */ |
| | | private PatArchive processPatientArchive(ServiceSLTDInhospResDTO dto) { |
| | | // 构建锁的 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 一致) |
| | |
| | | PatArchive queryByPatientNo = new PatArchive(); |
| | | queryByPatientNo.setPatientno(patientno); |
| | | existingArchives = patArchiveService.selectPatArchiveList(queryByPatientNo); |
| | | log.debug("【processPatientArchive】按patientno查询,patientno={}, 结果数量={}", patientno, existingArchives.size()); |
| | | } |
| | | |
| | | // 第二步:按 patientno 查不到时,按 idcardno 查重(分步OR,避免AND条件漏查) |
| | |
| | | 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)) { |
| | | try { |
| | | //再查一次,确保不会有重复的 |
| | | PatArchive queryByIdCard = new PatArchive(); |
| | | if(StringUtils.isNotEmpty(dto.getIdCardNo())) queryByIdCard.setIdcardno(dto.getIdCardNo().trim()); |
| | | if(StringUtils.isNotEmpty(dto.getMedicalRecordNo())) queryByIdCard.setPatientno(dto.getMedicalRecordNo()); |
| | | List<PatArchive> archivesByIdCard = patArchiveService.selectPatArchiveList(queryByIdCard); |
| | | // 最终确认查询(防御性编程:防止Redis锁失效等极端情况) |
| | | PatArchive finalQuery = new PatArchive(); |
| | | if (StringUtils.isNotEmpty(dto.getIdCardNo())) { |
| | | finalQuery.setIdcardno(dto.getIdCardNo().trim()); |
| | | } |
| | | if (StringUtils.isNotEmpty(dto.getMedicalRecordNo())) { |
| | | finalQuery.setPatientno(dto.getMedicalRecordNo()); |
| | | } |
| | | |
| | | if (CollectionUtils.isEmpty(archivesByIdCard)) patArchiveService.insertPatArchive(patArchive); |
| | | log.info("【processPatientArchive】新增患者档案,患者编号:{}", patArchive.getPatientno()); |
| | | 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.error("【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 { |
| | |
| | | patArchive.setNotrequiredFlag(existingArchives.get(0).getNotrequiredFlag()); |
| | | patArchive.setNotrequiredreason(existingArchives.get(0).getNotrequiredreason()); |
| | | patArchiveService.updateArchive(patArchive); |
| | | log.info("【processPatientArchive】更新患者档案,患者编号:{}", patArchive.getPatientno()); |
| | | log.info("【processPatientArchive】✓ 更新患者档案,patientno={}, id={}", patArchive.getPatientno(), patArchive.getId()); |
| | | } |
| | | |
| | | return patArchive; |
| | |
| | | dto.setCostCategoryCode(getStringValue(dataItem, "costCategoryCode")); |
| | | dto.setCostNatureName(getStringValue(dataItem, "costNatureName")); |
| | | dto.setCostNatureCode(getStringValue(dataItem, "costNatureCode")); |
| | | dto.setEncounterSourceId(getStringValue(dataItem, "encounterSourceId")); |
| | | dto.setFurtherConsultationStatus(getIntegerValue(dataItem, "furtherConsultationStatus")); |
| | | Object mainDiagObj = dataItem.get("mainDischargeDiagnosis"); |
| | | if (mainDiagObj instanceof Map) { |
| | |
| | | |
| | | 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<>(); |
| | |
| | | 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; |