From 60ade5154522a042c816abaa1840751011ae0371 Mon Sep 17 00:00:00 2001
From: liusheng <337615773@qq.com>
Date: 星期二, 29 九月 2026 19:15:03 +0800
Subject: [PATCH] 1.省立同德满度问题处理 2.门急诊数据采集优化

---
 smartor/src/main/java/com/smartor/service/impl/ServiceSLTDHealthcareRecordServiceImpl.java |  202 ++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 186 insertions(+), 16 deletions(-)

diff --git a/smartor/src/main/java/com/smartor/service/impl/ServiceSLTDHealthcareRecordServiceImpl.java b/smartor/src/main/java/com/smartor/service/impl/ServiceSLTDHealthcareRecordServiceImpl.java
index d2d357c..258cbe8 100644
--- a/smartor/src/main/java/com/smartor/service/impl/ServiceSLTDHealthcareRecordServiceImpl.java
+++ b/smartor/src/main/java/com/smartor/service/impl/ServiceSLTDHealthcareRecordServiceImpl.java
@@ -93,6 +93,9 @@
     @Autowired
     private PatMedInhospMapper patMedInhospMapper;
 
+    @Autowired
+    private PatMedOuthospErrorMapper patMedOuthospErrorMapper;
+
     @Override
     public List<ServiceSLTDInhospResDTO> queryHealthcareRecordList(ServiceSLTDInhospReqVO reqVO) {
         try {
@@ -503,7 +506,12 @@
             log.info("銆恜arseResponseData銆戞垚鍔熻В鏋恉ataList:{}鏉″仴搴疯褰曟暟鎹�", dataList.size());
             List<ServiceSLTDInhospResDTO> resultList = new ArrayList<>();
             for (Map<String, Object> dataItem : dataList) {
-                resultList.add(convertToDTO(dataItem));
+                try {
+                    resultList.add(convertToDTO(dataItem));
+                } catch (Exception e) {
+                    // 鍗曟潯鏁版嵁杞崲澶辫触涓嶅啀璁╂暣椤靛け璐ワ細鍐欓敊璇〃浜ょ粰浜哄伐澶勭悊锛屽叾浣欒褰曠収甯稿叆搴�
+                    saveOuthospError(dataItem, "CONVERT", e.getMessage(), new Gson().toJson(dataItem), e);
+                }
             }
             log.info("銆恜arseResponseData銆戞垚鍔熻В鏋恟esultList:{}鏉″仴搴疯褰曟暟鎹�", resultList.size());
 
@@ -613,34 +621,184 @@
     }
 
     private Boolean outHospitalDate(List<ServiceSLTDInhospResDTO> resultList) {
-        List<PatMedOuthosp> batchList = new ArrayList<>();
-
+        // 闂ㄦ�ヨ瘖鍦� HIS 渚у彧鑳芥寜澶╂煡锛岄噰闆嗕换鍔℃瘡鍗婂皬鏃堕兘浼氭妸褰撳ぉ涓婁竾涓瘖鐤楄褰曢噸鏂版媺涓�閬嶏紝
+        // 鍏朵腑缁濆ぇ澶氭暟涓婁竴杞凡缁忓叆搴撱�傝繖閲屽厛鏁撮〉鎵归噺鏌ラ噸锛屾妸宸插叆搴撶殑鐩存帴璺宠繃锛�
+        // 鍙鏂板璁板綍鍋�"妗f澶勭悊 + 鍏ュ簱"锛屽惁鍒欐瘡鏉¢噸澶嶆暟鎹兘瑕佽蛋涓�閬�
+        // Redis鍔犻攣 + 妗f鏌ラ噸 + 妗f鏇存柊 + countBySerialnum + insert锛屼竴涓囨潯灏辨槸鍑犱竾娆� SQL锛屽崐灏忔椂璺戜笉瀹屻��
+        Set<String> pageSerialnums = new HashSet<>();
+        List<ServiceSLTDInhospResDTO> uniqueList = new ArrayList<>();
+        List<ServiceSLTDInhospResDTO> noSerialnumList = new ArrayList<>();
+        Map<String, List<String>> serialnumsByDate = new LinkedHashMap<>();
         for (ServiceSLTDInhospResDTO dto : resultList) {
             if (Objects.isNull(dto)) {
                 continue;
             }
-            PatArchive patArchive = processPatientArchive(dto);
-            PatMedOuthosp patMedOuthosp = buildPatMedOuthosp(dto, patArchive);
-            batchList.add(patMedOuthosp);
+            String serialnum = dto.getHealthcareRecordNo();
+            if (StringUtils.isEmpty(serialnum)) {
+                // 娌℃湁璇婄枟璁板綍鍙峰氨娌℃硶鏌ラ噸锛屼繚鎸佸師鏈夎涓虹収甯稿鐞嗭紙鍏ュ簱鐜妭杩樹細鍐嶅厹涓�娆★級
+                log.warn("銆恛utHospitalDate銆戣瘖鐤楄褰曞彿涓虹┖锛屾棤娉曟煡閲嶏紝鎸夋柊澧炲鐞嗭細patientName={}", dto.getPatientName());
+                noSerialnumList.add(dto);
+                continue;
+            }
+            if (!pageSerialnums.add(serialnum)) {
+                // 鍚屼竴椤靛唴閲嶅鐨勮褰曪紝鍙鐞嗕竴鏉�
+                continue;
+            }
+            uniqueList.add(dto);
+            // 鎸夊氨璇婃棩鏈熷垎缁勶紙璺ㄩ浂鐐规椂鏈�澶氫袱涓棩鏈燂級锛屼繚璇佹煡閲嶇殑鍒嗚〃鍜屽叆搴撴椂鍒嗚〃璺敱涓�鑷�
+            String admitDateStr = formatAdmitDate(dto.getLastEncounterTime());
+            serialnumsByDate.computeIfAbsent(admitDateStr == null ? "" : admitDateStr, k -> new ArrayList<>()).add(serialnum);
         }
+
+        // 涓�娆� SQL 鏌ュ嚭杩欎竴椤甸噷宸茬粡鍏ュ簱鐨� serialnum锛堝彇浠i�愭潯 countBySerialnum锛�
+        Set<String> existingSerialnums = new HashSet<>();
+        for (Map.Entry<String, List<String>> entry : serialnumsByDate.entrySet()) {
+            try {
+                existingSerialnums.addAll(patMedOuthospService.selectExistingSerialnums(entry.getKey(), entry.getValue()));
+            } catch (Exception e) {
+                // 鎵归噺鏌ラ噸澶辫触涓嶅奖鍝嶆纭�э細涓嬮潰鍏ュ簱鏃舵瘡鏉¤繕浼氬啀鏌ヤ竴娆¢噸锛屽彧鏄參涓�浜�
+                log.error("銆恛utHospitalDate銆戞壒閲忔煡閲嶅け璐ワ紝閫�鍖栦负閫愭潯鏌ラ噸锛屽氨璇婃棩鏈燂細{}", entry.getKey(), e);
+            }
+        }
+
+        List<PatMedOuthosp> batchList = new ArrayList<>();
+        int existSkipCount = 0;
+        for (ServiceSLTDInhospResDTO dto : uniqueList) {
+            if (existingSerialnums.contains(dto.getHealthcareRecordNo())) {
+                existSkipCount++;
+                continue;
+            }
+            PatMedOuthosp patMedOuthosp = buildNewOuthosp(dto);
+            if (patMedOuthosp != null) {
+                batchList.add(patMedOuthosp);
+            }
+        }
+        for (ServiceSLTDInhospResDTO dto : noSerialnumList) {
+            PatMedOuthosp patMedOuthosp = buildNewOuthosp(dto);
+            if (patMedOuthosp != null) {
+                batchList.add(patMedOuthosp);
+            }
+        }
+        log.info("銆恛utHospitalDate銆戞湰椤祘}鏉★紝鍘婚噸鍚巤}鏉★紝宸插叆搴撹烦杩噞}鏉★紝寰呭叆搴搟}鏉�",
+                resultList.size(), uniqueList.size(), existSkipCount, batchList.size());
 
         // 鎵归噺鎻掑叆锛岃嚜鍔ㄥ拷鐣ラ噸澶�
         if (CollectionUtils.isNotEmpty(batchList)) {
-            try {
-                //杩欓噷鐢ㄨ嚜鍔ㄥ拷鐣ラ噸澶嶄細鏈夐棶棰橈紝濡傛灉琛ㄩ噸鏂板缓锛宻erialnum绱㈠紩浼氫涪澶便�傚氨鏃犳硶鍘婚噸锛屾墍浠ヨ繕鏄渶瑕佸唴瀛橀噷鍘婚噸
-                batchList = DistinctByProperty.distinctByProperty(batchList, PatMedOuthosp::getSerialnum);
-                Integer insertCount = 0;
-                for (PatMedOuthosp patMedOuthosp : batchList) {
-                    insertCount += patMedOuthospService.insertPatMedOuthosp(patMedOuthosp);
+            //杩欓噷鐢ㄨ嚜鍔ㄥ拷鐣ラ噸澶嶄細鏈夐棶棰橈紝濡傛灉琛ㄩ噸鏂板缓锛宻erialnum绱㈠紩浼氫涪澶便�傚氨鏃犳硶鍘婚噸锛屾墍浠ヨ繕鏄渶瑕佸唴瀛橀噷鍘婚噸
+            batchList = DistinctByProperty.distinctByProperty(batchList, PatMedOuthosp::getSerialnum);
+            int insertCount = 0;
+            int skipCount = 0;
+            List<String> failSerialnums = new ArrayList<>();
+            for (PatMedOuthosp patMedOuthosp : batchList) {
+                try {
+                    int inserted = patMedOuthospService.insertPatMedOuthosp(patMedOuthosp);
+                    if (inserted > 0) {
+                        insertCount += inserted;
+                    } else {
+                        // 杩斿洖0琛ㄧず宸插瓨鍦紙閲嶅閲囬泦锛夋垨灏辫瘖鏃堕棿涓虹┖锛屽睘浜庢甯歌烦杩囷紝涓嶇畻澶辫触
+                        skipCount++;
+                    }
+                } catch (Exception e) {
+                    // 鍗曟潯鍏ュ簱澶辫触涓嶅啀涓柇閲囬泦锛氳惤閿欒琛ㄤ氦缁欎汉宸ュ鐞嗭紝閲囬泦鏂偣鐓у父鎺ㄨ繘
+                    failSerialnums.add(patMedOuthosp.getSerialnum());
+                    saveOuthospError(null, patMedOuthosp, "INSERT", e.getMessage(), new Gson().toJson(patMedOuthosp), e);
                 }
+            }
+            log.info("鎵归噺鎻掑叆闂ㄦ�ヨ瘖璁板綍锛屾�绘暟锛歿}, 瀹為檯鎻掑叆锛歿}, 璺宠繃锛堝凡瀛樺湪/鏃犲氨璇婃椂闂达級锛歿}, 钀介敊璇〃锛歿}",
+                    batchList.size(), insertCount, skipCount, failSerialnums.size());
 
-                log.info("鎵归噺鎻掑叆闂ㄦ�ヨ瘖璁板綍锛屾�绘暟锛歿}, 瀹為檯鎻掑叆锛歿}", batchList.size(), insertCount);
-
-            } catch (Exception e) {
-                log.error("鎵归噺鎻掑叆闂ㄦ�ヨ瘖璁板綍澶辫触", e);
+            if (!failSerialnums.isEmpty()) {
+                // 澶辫触鏄庣粏宸查�愭潯鍐欒繘 pat_med_outhosp_error锛岃繖閲屽彧鎻愮ず锛屼笉鍐嶆姏寮傚父闃绘柇閲囬泦
+                log.error("闂ㄦ�ヨ瘖璁板綍鍏ュ簱澶辫触 {} 鏉★紝宸插啓鍏� pat_med_outhosp_error 绛変汉宸ュ鐞嗭紝serialnum锛歿}",
+                        failSerialnums.size(), failSerialnums);
             }
         }
         return true;
+    }
+
+    /**
+     * 澶勭悊鍗曟潯鏂板璁板綍鐨勬偅鑰呮。妗堝苟鏋勫缓闂ㄦ�ヨ瘖璁板綍锛�
+     * 澶辫触鏃跺啓閿欒琛ㄤ氦缁欎汉宸ュ鐞嗗苟杩斿洖 null锛屼笉褰卞搷鍚屼竴椤甸噷鍏朵粬璁板綍
+     */
+    private PatMedOuthosp buildNewOuthosp(ServiceSLTDInhospResDTO dto) {
+        try {
+            PatArchive patArchive = processPatientArchive(dto);
+            return buildPatMedOuthosp(dto, patArchive);
+        } catch (Exception e) {
+            saveOuthospError(dto, null, "ARCHIVE", e.getMessage(), new Gson().toJson(dto), e);
+            return null;
+        }
+    }
+
+    /** 閲囬泦澶辫触鐨勫師濮嬭褰曟潵鑷帴鍙h繑鍥炵殑 Map锛堟暟鎹浆鎹㈠け璐ユ椂杩樻病鏈� DTO锛� */
+    private void saveOuthospError(Map<String, Object> dataItem, String errorType, String errorMsg,
+                                  String rawData, Throwable cause) {
+        PatMedOuthospError error = new PatMedOuthospError();
+        error.setSerialnum(getStringValue(dataItem, "healthcareRecordNo"));
+        error.setOuthospno(getStringValue(dataItem, "healthcareRecordNo"));
+        error.setPatname(getStringValue(dataItem, "patientName"));
+        error.setPatno(getStringValue(dataItem, "medicalRecordNo"));
+        error.setCampusid(getStringValue(dataItem, "campusId"));
+        error.setOrgid(getStringValue(dataItem, "orgId"));
+        doSaveOuthospError(error, errorType, errorMsg, rawData, cause);
+    }
+
+    /** 閲囬泦澶辫触鐨勫師濮嬭褰曟潵鑷� DTO / 寰呭叆搴撶殑 PatMedOuthosp */
+    private void saveOuthospError(ServiceSLTDInhospResDTO dto, PatMedOuthosp patMedOuthosp, String errorType,
+                                  String errorMsg, String rawData, Throwable cause) {
+        PatMedOuthospError error = new PatMedOuthospError();
+        if (dto != null) {
+            error.setSerialnum(dto.getHealthcareRecordNo());
+            error.setOuthospno(dto.getHealthcareRecordNo());
+            error.setPatname(dto.getPatientName());
+            error.setPatno(dto.getMedicalRecordNo());
+            error.setCampusid(dto.getCampusId());
+            error.setOrgid(dto.getOrgId());
+            error.setAdmitdate(parseDate(dto.getLastEncounterTime()));
+        }
+        if (patMedOuthosp != null) {
+            if (StringUtils.isEmpty(error.getSerialnum())) {
+                error.setSerialnum(patMedOuthosp.getSerialnum());
+            }
+            error.setOuthospno(patMedOuthosp.getOuthospno());
+            error.setPatname(patMedOuthosp.getPatname());
+            error.setPatno(patMedOuthosp.getPatno());
+            error.setCampusid(patMedOuthosp.getCampusid());
+            error.setOrgid(patMedOuthosp.getOrgid());
+            error.setAdmitdate(patMedOuthosp.getAdmitdate());
+        }
+        doSaveOuthospError(error, errorType, errorMsg, rawData, cause);
+    }
+
+    /**
+     * 鍐欓棬鎬ヨ瘖閲囬泦澶辫触璁板綍琛紝浜ょ粰浜哄伐澶勭悊銆�
+     * 杩欓噷鍏滀綇涓�鍒囧紓甯革細杩為敊璇〃閮藉啓涓嶈繘鍘绘椂鍙墦鏃ュ織锛堝甫鍘熷鏁版嵁锛夛紝缁濅笉鍥犱负鍐欓敊璇〃澶辫触鑰屼腑鏂噰闆�
+     */
+    private void doSaveOuthospError(PatMedOuthospError error, String errorType, String errorMsg,
+                                    String rawData, Throwable cause) {
+        error.setErrorType(errorType);
+        error.setErrorMsg(truncate(errorMsg == null || errorMsg.isEmpty() ? String.valueOf(cause) : errorMsg, 1000));
+        error.setRawData(rawData);
+        error.setFailCount(1);
+        error.setHandleStatus("0");
+        error.setGatherDate(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
+        error.setCreateTime(DateUtils.getNowDate());
+        try {
+            patMedOuthospErrorMapper.insertPatMedOuthospError(error);
+            log.error("銆愰棬鎬ヨ瘖閲囬泦銆憑} 澶辫触锛屽凡鍐欏叆 pat_med_outhosp_error 绛変汉宸ュ鐞嗭紝serialnum={}锛屾偅鑰�={}锛屽師鍥�={}",
+                    errorType, error.getSerialnum(), error.getPatname(), error.getErrorMsg(), cause);
+        } catch (Exception ex) {
+            log.error("銆愰棬鎬ヨ瘖閲囬泦銆憑} 澶辫触锛屼笖鍐欏叆閿欒琛ㄤ篃澶辫触锛宻erialnum={}锛屽師濮嬫暟鎹細{}",
+                    errorType, error.getSerialnum(), rawData, ex);
+        }
+    }
+
+    /** 鎴柇瓒呴暱鏂囨湰锛岄伩鍏嶈秴鍑洪敊璇〃瀛楁闀垮害瀵艰嚧钀借〃澶辫触 */
+    private String truncate(String text, int maxLength) {
+        if (text == null) {
+            return null;
+        }
+        return text.length() <= maxLength ? text : text.substring(0, maxLength);
     }
 
     private PatMedOuthosp buildPatMedOuthosp(ServiceSLTDInhospResDTO dto, PatArchive patArchive) {
@@ -681,6 +839,18 @@
         }
     }
 
+    /**
+     * 鍙栧氨璇婃棩鏈熺殑 yyyy-MM-dd 閮ㄥ垎锛屼笌 buildPatMedOuthosp 閲岀殑 admitdate 淇濇寔瀹屽叏涓�鑷寸殑瑙f瀽瑙勫垯锛�
+     * 淇濊瘉鎵归噺鏌ラ噸鐢ㄧ殑鍒嗚〃鍜屽叆搴撴椂璺敱鍒扮殑鍒嗚〃鏄悓涓�寮�
+     */
+    private String formatAdmitDate(String lastEncounterTime) {
+        Date admitDate = parseDate(lastEncounterTime);
+        if (admitDate == null) {
+            return null;
+        }
+        return new SimpleDateFormat("yyyy-MM-dd").format(admitDate);
+    }
+
     private Boolean inHospitalDate(List<ServiceSLTDInhospResDTO> resultList, String cry) {
         for (ServiceSLTDInhospResDTO dto : resultList) {
             if (Objects.isNull(dto)) continue;

--
Gitblit v1.9.3