Explorar o código

Merge branch 'shaoyf/dev' into shaoyf/master

rengb %!s(int64=5) %!d(string=hai) anos
pai
achega
dec4584a03

+ 87 - 0
dbanaly/src/main/java/com/lantone/qc/dbanaly/facade/comsis/DataExtractFacade.java

@@ -0,0 +1,87 @@
+package com.lantone.qc.dbanaly.facade.comsis;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.lantone.qc.dbanaly.facade.changx.CxXmlUtil;
+import com.lantone.qc.dbanaly.facade.taizhou.TzXmlUtil;
+import com.lantone.qc.dbanaly.lt.entity.MedicalRecord;
+import com.lantone.qc.dbanaly.lt.entity.MedicalRecordContent;
+import com.lantone.qc.dbanaly.lt.service.impl.MedicalRecordContentServiceImpl;
+import com.lantone.qc.dbanaly.lt.service.impl.MedicalRecordServiceImpl;
+import com.lantone.qc.pub.util.EncrypDES;
+import com.lantone.qc.pub.util.FileUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Description:
+ * @author: rengb
+ * @time: 2020/8/26 9:56
+ */
+@Component
+public class DataExtractFacade {
+    @Autowired
+    private MedicalRecordServiceImpl medicalRecordService;
+    @Autowired
+    private MedicalRecordContentServiceImpl medicalRecordContentService;
+
+    public void extractCrfNeedData() throws Exception {
+        EncrypDES encrypDES = new EncrypDES();
+
+        long hospid = 3l;
+        long modid = 1l;
+        QueryWrapper<MedicalRecord> medicalRecordQueryWrapper = new QueryWrapper<>();
+        medicalRecordQueryWrapper.eq("hospital_id", hospid);
+        medicalRecordQueryWrapper.eq("mode_id", 1l);
+        medicalRecordQueryWrapper.select("rec_id,behospital_code");
+        List<MedicalRecord> medicalRecordList = medicalRecordService.list(medicalRecordQueryWrapper);
+
+        for (MedicalRecord medicalRecord : medicalRecordList) {
+            QueryWrapper<MedicalRecordContent> medicalRecordContentQueryWrapper = new QueryWrapper<>();
+            medicalRecordContentQueryWrapper.eq("hospital_id", hospid);
+            medicalRecordContentQueryWrapper.eq("rec_id", medicalRecord.getRecId());
+            medicalRecordContentQueryWrapper.select("xml_text");
+            MedicalRecordContent medicalRecordContent = medicalRecordContentService.getOne(medicalRecordContentQueryWrapper);
+            if (medicalRecordContent != null && StringUtil.isNotBlank(medicalRecordContent.getXmlText())) {
+                String dexml = encrypDES.decryptor(medicalRecordContent.getXmlText());
+                if (StringUtil.isNotBlank(dexml)) {
+                    Map<String, String> sourceMap = TzXmlUtil.getXmlToMapForTZ(dexml);
+                    String result = sourceMap.get("专科检查");
+                    if (StringUtil.isNotBlank(result)) {
+                        FileUtil.fileWrite("C:\\Users\\Administrator\\Desktop\\专科检查\\台州", medicalRecord.getBehospitalCode(), result);
+                    }
+                }
+            }
+        }
+    }
+
+    private String concatString(String item) {
+        if (StringUtil.isBlank(item)) {
+            return "";
+        } else {
+            return item + "。";
+        }
+    }
+
+    private String concatSpecialCheck(Map<String, String> sourceMap) {
+        return concatString(sourceMap.get("一般情况")) +
+                concatString(sourceMap.get("皮肤情况")) +
+                concatString(sourceMap.get("淋巴")) +
+                concatString(sourceMap.get("头部检查")) +
+                concatString(sourceMap.get("颈部")) +
+                concatString(sourceMap.get("胸部检查")) +
+                concatString(sourceMap.get("肺部检查")) +
+                concatString(sourceMap.get("心脏检查")) +
+                concatString(sourceMap.get("血管")) +
+                concatString(sourceMap.get("腹部检查")) +
+                concatString(sourceMap.get("外生殖器")) +
+                concatString(sourceMap.get("直肠肛门")) +
+                concatString(sourceMap.get("四肢脊柱检查")) +
+                concatString(sourceMap.get("神经系统检查")) +
+                concatString(sourceMap.get("其他说明"));
+    }
+
+}

+ 6 - 0
dbanaly/src/main/resources/application-debug.yml

@@ -48,5 +48,11 @@ CRF:
 Similarity:
   url: http://192.168.2.234:3456/api/mr_info_ex/similarity
 
+NewSimilarity:
+  url: http://192.168.3.150:23232/api/similarity
+
+NewBatchSimilarity:
+  url: http://192.168.3.150:23232/api/similarity_batch
+
 ChiefPresentSimilarity:
   url: http://192.168.2.234:3456/api/mr_info_ex/chief_present_similarity

+ 6 - 0
dbanaly/src/main/resources/application-dev.yml

@@ -49,5 +49,11 @@ CRF:
 Similarity:
   url: http://192.168.2.234:3456/api/mr_info_ex/similarity
 
+NewSimilarity:
+  url: http://192.168.3.150:23232/api/similarity
+
+NewBatchSimilarity:
+  url: http://192.168.3.150:23232/api/similarity_batch
+
 ChiefPresentSimilarity:
   url: http://192.168.2.234:3456/api/mr_info_ex/chief_present_similarity

+ 7 - 1
dbanaly/src/main/resources/application-local.yml

@@ -49,5 +49,11 @@ CRF:
 Similarity:
   url: http://192.168.2.234:3456/api/mr_info_ex/similarity
 
+NewSimilarity:
+  url: http://192.168.3.150:23232/api/similarity
+
+NewBatchSimilarity:
+  url: http://192.168.3.150:23232/api/similarity_batch
+
 ChiefPresentSimilarity:
-  url: http://192.168.2.234:3456/api/mr_info_ex/chief_present_similarity
+  url: http://192.168.2.234:3456/api/mr_info_ex/similarity

+ 6 - 0
dbanaly/src/main/resources/application-master.yml

@@ -48,5 +48,11 @@ CRF:
 Similarity:
   url: http://192.168.2.234:3456/api/mr_info_ex/similarity
 
+NewSimilarity:
+  url: http://192.168.3.150:23232/api/similarity
+
+NewBatchSimilarity:
+  url: http://192.168.3.150:23232/api/similarity_batch
+
 ChiefPresentSimilarity:
   url: http://192.168.2.234:3456/api/mr_info_ex/chief_present_similarity

+ 6 - 0
dbanaly/src/main/resources/application-test.yml

@@ -48,5 +48,11 @@ CRF:
 Similarity:
   url: http://192.168.2.234:3456/api/mr_info_ex/similarity
 
+NewSimilarity:
+  url: http://192.168.3.150:23232/api/similarity
+
+NewBatchSimilarity:
+  url: http://192.168.3.150:23232/api/similarity_batch
+
 ChiefPresentSimilarity:
   url: http://192.168.2.234:3456/api/mr_info_ex/chief_present_similarity

+ 9 - 3
kernel/src/main/java/com/lantone/qc/kernel/catalogue/behospitalized/BEH0011.java

@@ -21,7 +21,13 @@ import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
@@ -263,7 +269,7 @@ public class BEH0011 extends QCCatalogue {
         }
         long diabetes = initDiags.stream().filter(x -> x.contains("糖尿病")).count();
         for (String diabetesDrug : diabetesDrugs) {
-            if (checkText.contains(diabetesDrug) && diabetes == 0) {
+            if (checkText.contains(diabetesDrug) && checkText.contains("糖尿病") && diabetes == 0) {
                 if (StringUtil.isBlank(info.get()) || !info.get().contains("糖尿病")) {
                     info.set(CatalogueUtil.concatInfo(info.get(), "糖尿病"));
                     status.set("-1");
@@ -274,7 +280,7 @@ public class BEH0011 extends QCCatalogue {
         }
         long hypertension = initDiags.stream().filter(x -> x.contains("高血压")).count();
         for (String feritinDrug : feritinDrugs) {
-            if (checkText.contains(feritinDrug) && hypertension == 0) {
+            if (checkText.contains(feritinDrug) && checkText.contains("高血压") && hypertension == 0) {
                 if (StringUtil.isBlank(info.get()) || !info.get().contains("高血压")) {
                     info.set(CatalogueUtil.concatInfo(info.get(), "高血压"));
                     status.set("-1");

+ 3 - 3
kernel/src/main/java/com/lantone/qc/kernel/catalogue/behospitalized/BEH0019.java

@@ -35,10 +35,10 @@ public class BEH0019 extends QCCatalogue {
             Clinical clinical = clinicals.get(0);
             String clinicalName = clinical.getName();
             if (StringUtil.isNotBlank(clinicalName)) {
-                long start = System.currentTimeMillis();
+//                long start = System.currentTimeMillis();
                 Clinic clinic = clinicFacade.clinicCache(clinicalName);
-                long end = System.currentTimeMillis();
-                System.out.println("取kl_clinic缓存时间:" + (end-start));
+//                long end = System.currentTimeMillis();
+//                System.out.println("取kl_clinic缓存时间:" + (end-start));
                 if (clinic != null && clinic.getHasDegree() == 1) {
                     Degree degree = clinical.getDegree();
                     if (degree == null) {

+ 3 - 3
kernel/src/main/java/com/lantone/qc/kernel/catalogue/threelevelward/THR02985.java

@@ -74,13 +74,13 @@ public class THR02985 extends QCCatalogue {
             String startDateStr = adviceDocStructureMap.get("医嘱开始时间");
             if (StringUtil.isNotBlank(drugCategory) && drugCategory.contains("抗生素")) {
                 if (StringUtil.isNotBlank(name)) {
+                    if (Arrays.asList(KSS).contains(name)) {
+                        continue;
+                    }
                     name = name.replaceAll("[针]", "");
                     if (name.contains(" ")) {
                         name = name.split(" ")[0];
                     }
-                    if (Arrays.asList(KSS).contains(name)) {
-                        continue;
-                    }
                     Date startDate = StringUtil.parseDateTime(startDateStr);
                     if (startDate != null) {
                         startDate = DateUtil.dateZeroClear(startDate);

+ 234 - 80
kernel/src/main/java/com/lantone/qc/kernel/catalogue/threelevelward/THR02986.java

@@ -4,24 +4,26 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.lantone.qc.kernel.catalogue.QCCatalogue;
 import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.kernel.util.SimilarityUtil;
 import com.lantone.qc.pub.model.InputInfo;
 import com.lantone.qc.pub.model.OutputInfo;
-import com.lantone.qc.pub.model.doc.BeHospitalizedDoc;
-import com.lantone.qc.pub.model.doc.DoctorAdviceDoc;
-import com.lantone.qc.pub.model.doc.FirstCourseRecordDoc;
-import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
+import com.lantone.qc.pub.model.doc.*;
+import com.lantone.qc.pub.model.doc.consultation.ConsultationDoc;
+import com.lantone.qc.pub.model.doc.consultation.ConsultationResultsDoc;
 import com.lantone.qc.pub.model.doc.operation.OperationDiscussionDoc;
 import com.lantone.qc.pub.model.doc.operation.OperationDoc;
 import com.lantone.qc.pub.model.doc.operation.OperationRecordDoc;
+import com.lantone.qc.pub.model.entity.Drug;
+import com.lantone.qc.pub.model.label.ThreeLevelWardLabel;
+import com.lantone.qc.pub.util.DateUtil;
 import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 /**
  * @ClassName : THR02986
@@ -32,12 +34,16 @@ import java.util.regex.Pattern;
  */
 @Component
 public class THR02986 extends QCCatalogue {
+    @Autowired
+    SimilarityUtil similarityUtil;
     public void start(InputInfo inputInfo, OutputInfo outputInfo) {
         List<DoctorAdviceDoc> doctorAdviceDocs = inputInfo.getDoctorAdviceDocs();
         List<ThreeLevelWardDoc> threeLevelWardDocs = inputInfo.getThreeLevelWardDocs();
         FirstCourseRecordDoc firstCourseRecordDoc = inputInfo.getFirstCourseRecordDoc();
         BeHospitalizedDoc beHospitalizedDoc = inputInfo.getBeHospitalizedDoc();
         List<OperationDoc> operationDocs = inputInfo.getOperationDocs();
+        LeaveHospitalDoc leaveHospitalDoc = inputInfo.getLeaveHospitalDoc();
+        List<ConsultationDoc> consultationDocs = inputInfo.getConsultationDocs();
         if (doctorAdviceDocs.size() == 0 || threeLevelWardDocs.size() == 0) {
             status.set("0");
             return;
@@ -47,8 +53,7 @@ public class THR02986 extends QCCatalogue {
             status.set("0");
             return;
         }
-        Map<Date, String> doctorAdviceDrugMap = new HashMap<>();
-        String regex = "[()*+-]";
+        Map<Date, String> doctorAdviceDrugMap = Maps.newLinkedHashMap();
         for (DoctorAdviceDoc adviceDoc : doctorAdviceDocs) {
             Map<String, String> adviceDocStructureMap = adviceDoc.getStructureMap();
             String name = adviceDocStructureMap.get("医嘱项目名称");
@@ -56,84 +61,82 @@ public class THR02986 extends QCCatalogue {
             String startDateStr = adviceDocStructureMap.get("医嘱开始时间");
             if (StringUtil.isNotBlank(drugCategory) && drugCategory.contains("激素")) {
                 if (StringUtil.isNotBlank(name)) {
+                    if (Arrays.asList(KSS).contains(name)) {
+                        continue;
+                    }
+                    name = name.replaceAll("[针]", "");
                     if (name.contains(" ")) {
                         name = name.split(" ")[0];
                     }
-                    doctorAdviceDrugMap.put(StringUtil.parseDateTime(startDateStr), name);
+                    Date startDate = StringUtil.parseDateTime(startDateStr);
+                    if (startDate != null) {
+                        startDate = DateUtil.dateZeroClear(startDate);
+                        doctorAdviceDrugMap.put(startDate, name);
+                    }
                 }
             }
         }
 
-        //入院记录中找药
-        String behospContent = null, firstCourseContent = null, operContent = null, afterOperContent = null;
-        Date behospDate = null, firstCourseDate = null, operDate = null, afterOperDate = null;
+        Map<String, Date> info = Maps.newLinkedHashMap();
+        //入院记录中获取信息
         if (beHospitalizedDoc != null) {
-            behospContent = CatalogueUtil.structureMapJoin(beHospitalizedDoc.getStructureMap(), Lists.newArrayList("治疗计划"));
-            String recordDateStr = firstCourseRecordDoc.getStructureMap().get("入院日期");
-            if (StringUtil.isNotBlank(recordDateStr)) {
-                behospDate = StringUtil.parseDateTime(recordDateStr);
-            }
+            Map<String, String> structureMap = beHospitalizedDoc.getStructureMap();
+            getInfo(info, structureMap, "入院记录", "入院日期", "治疗计划");
         }
-        //从首程治疗计划中找药
+        //从首程治疗计划中获取信息
         if (firstCourseRecordDoc != null) {
-            firstCourseContent = firstCourseRecordDoc.getStructureMap().get("治疗计划");
-            String recordDateStr = firstCourseRecordDoc.getStructureMap().get("记录时间");
-            if (StringUtil.isNotBlank(recordDateStr)) {
-                firstCourseDate = StringUtil.parseDateTime(recordDateStr);
-            }
+            Map<String, String> structureMap = firstCourseRecordDoc.getStructureMap();
+            getInfo(info, structureMap, "首次病程录", "记录时间", "治疗计划");
         }
 
-        Map<String, Date> operInfo = Maps.newHashMap();
+        //从手术记录中获取信息
         if (operationDocs.size() > 0) {
-            for (OperationDoc oDoc : operationDocs) {
-                OperationRecordDoc operationRecordDoc = oDoc.getOperationRecordDoc();
-                if (operationRecordDoc != null) {
-                    operContent = operationRecordDoc.getStructureMap().get("手术经过");
-                    String operDateStr = operationRecordDoc.getStructureMap().get("手术日期");
-                    if (StringUtil.isNotBlank(operDateStr)) {
-                        operDate = StringUtil.parseDateTime(operDateStr);
-                    }
-                    if (StringUtil.isNotBlank(operContent) && operDate != null) {
-                        operInfo.put(operContent, operDate);
-                    }
-                }
-                OperationDiscussionDoc operationDiscussionDoc = oDoc.getOperationDiscussionDoc();
-                if (operationDiscussionDoc != null) {
-                    afterOperContent = operationDiscussionDoc.getStructureMap().get("手术经过");
-                    String operDateStr = operationDiscussionDoc.getStructureMap().get("手术日期");
-                    if (StringUtil.isNotBlank(operDateStr)) {
-                        afterOperDate = StringUtil.parseDateTime(operDateStr);
-                    }
-                    if (StringUtil.isNotBlank(afterOperContent) && afterOperDate != null) {
-                        operInfo.put(afterOperContent, afterOperDate);
-                    }
-                }
-            }
+            //手术记录
+            List<Map<String, String>> operationRecordStructMap = operationDocs
+                    .stream()
+                    .map(OperationDoc::getOperationRecordDoc)
+                    .filter(Objects::nonNull)
+                    .map(OperationRecordDoc::getStructureMap)
+                    .collect(Collectors.toList());
+            operationRecordStructMap.forEach(x -> getInfo(info, x, "手术记录", "病历日期", "手术经过"));
+            //术后首程
+            List<Map<String, String>> operationDiscussionStructMap = operationDocs
+                    .stream()
+                    .map(OperationDoc::getOperationDiscussionDoc)
+                    .filter(Objects::nonNull)
+                    .map(OperationDiscussionDoc::getStructureMap)
+                    .collect(Collectors.toList());
+            operationDiscussionStructMap.forEach(x -> getInfo(info, x, "术后首程", "记录日期", "手术经过", "治疗计划和措施"));
+        }
+
+        //从会诊记录中获取信息
+        if (consultationDocs.size() > 0) {
+            List<Map<String, String>> consultationResultStructMap = consultationDocs
+                    .stream()
+                    .map(ConsultationDoc::getConsultationResultsDoc)
+                    .filter(Objects::nonNull)
+                    .map(ConsultationResultsDoc::getStructureMap)
+                    .collect(Collectors.toList());
+            consultationResultStructMap.forEach(x -> getInfo(info, x, "会诊结果单", "会诊日期及时间", "会诊意见"));
+        }
+
+        //从出院小结中获取信息
+        if (leaveHospitalDoc != null) {
+            Map<String, String> structureMap = leaveHospitalDoc.getStructureMap();
+            getInfo(info, structureMap, "出院小结", "出院时间", "诊治经过");
         }
 
         String infoStr = "";
         for (Map.Entry<Date, String> doctorAdviceDrug : doctorAdviceDrugMap.entrySet()) {
             Date doctorAdviceDate = doctorAdviceDrug.getKey();
             String drugs = doctorAdviceDrug.getValue();
-            String[] drugArr = drugs.split(regex);
+            drugs = removeBracket(drugs);
+            Set<String> splitDrugs = CatalogueUtil.getRegexWords(drugs, "[((\\[][^\\[\\]()()]+[\\]))]")
+                    .stream().filter(x -> !x.equals("合资") && !x.equals("进口") && !x.equals("国产")).collect(Collectors.toSet());
             String missDrug = "";
-            //入院记录中找药
-            if (StringUtil.isNotBlank(behospContent) && behospDate != null) {
-                missDrug = getMissDrug(behospContent, behospDate, doctorAdviceDate, drugArr, 2, missDrug);
-                if (StringUtil.isBlank(missDrug)) {//文本中已找到该激素
-                    continue;
-                }
-            }
-            //从首程治疗计划中找药
-            if (StringUtil.isNotBlank(firstCourseContent) && firstCourseDate != null) {
-                missDrug = getMissDrug(firstCourseContent, firstCourseDate, doctorAdviceDate, drugArr, 2, missDrug);
-                if (StringUtil.isBlank(missDrug)) {
-                    continue;
-                }
-            }
-            for (Map.Entry<String, Date> info : operInfo.entrySet()) {
-                missDrug = getMissDrug(info.getKey(), info.getValue(), doctorAdviceDate, drugArr, 2, missDrug);
-                //当前激素药(drugs)在手术记录或术后首次病程录中已找到,直接跳出当前循环
+            for (Map.Entry<String, Date> map : info.entrySet()) {
+                missDrug = getMissDrug(map.getKey(), map.getValue(), doctorAdviceDate, splitDrugs, 2, missDrug);
+                //当前激素药(drugs)在info中已找到,直接跳出当前循环
                 if (StringUtil.isBlank(missDrug)) {
                     break;
                 }
@@ -141,32 +144,76 @@ public class THR02986 extends QCCatalogue {
             if (StringUtil.isBlank(missDrug)) {
                 continue;
             }
+            boolean modelFind = false;
+            int wardNum = 0;
             for (ThreeLevelWardDoc threeLevelWardDoc : allDoctorWradDocs) {
+                /*****************纯文本匹配******************/
                 Map<String, String> wardDocStructureMap = threeLevelWardDoc.getStructureMap();
                 String wardDateStr = wardDocStructureMap.get("查房日期");
                 String content = wardDocStructureMap.get("病情记录") + wardDocStructureMap.get("治疗计划和措施");
                 Date wardDate = StringUtil.parseDateTime(wardDateStr);
-                missDrug = getMissDrug(content, wardDate, doctorAdviceDate, drugArr, 2, missDrug);
+                missDrug = getMissDrug(content, wardDate, doctorAdviceDate, splitDrugs, 2, missDrug);
                 //当前激素药(drugs)在查房记录中已找到,直接跳出当前查房记录的循环
-                if (StringUtil.isBlank(missDrug)) {
+                /*****************药品相似度模型******************/
+                List<ThreeLevelWardLabel> label = threeLevelWardDoc.getThreeLevelWardLabel();
+                if (label.size() > 0) {
+                    List<Drug> drugList = label.get(0).getDrugs();
+                    for (Drug drug : drugList) {
+                        for (String adDrug : splitDrugs) {
+                            if (compareStandard(drug.getName(), adDrug)) {
+                                modelFind = true;
+                                break;
+                            }
+                        }
+                        if (modelFind) {
+                            break;
+                        }
+                    }
+                }
+                if (StringUtil.isNotBlank(missDrug) && !modelFind) {//missDrug不为空,只有两种可能:1.确实是缺失的药    2.字符串为“时间不匹配”
+                    wardNum++;                                      //当前所有查房记录都没找到药,该医嘱时间再与系统当前时间对比,若超过48小时则提示该药缺失
+                }
+                if (StringUtil.isBlank(missDrug) || modelFind) {
                     break;
                 }
             }
+            //如果目前所有查房记录都没有
+            if (wardNum == allDoctorWradDocs.size() && CatalogueUtil.compareTime(doctorAdviceDate, new Date(), 48 * 60L)) {
+                infoStr = CatalogueUtil.concatInfo(infoStr, splitDrugs.toString().replaceAll("[\\[\\]]", "") + "(" + DateUtil.formatDate(doctorAdviceDate) + ")");
+                continue;
+            }
 
-            if (StringUtil.isNotBlank(missDrug) && !"时间不匹配".equals(missDrug)) {
-                infoStr = CatalogueUtil.concatInfo(infoStr, missDrug);
+            if (StringUtil.isNotBlank(missDrug) && !"时间不匹配".equals(missDrug) && !modelFind) {
+                infoStr = CatalogueUtil.concatInfo(infoStr, missDrug + "(" + DateUtil.formatDate(doctorAdviceDate) + ")");
             }
         }
         if (StringUtil.isNotBlank(infoStr)) {
-            status.set("-1");
-            info.set(infoStr);
+            this.status.set("-1");
+            this.info.set(infoStr);
         } else {
-            status.set("0");
+            this.status.set("0");
         }
     }
 
     /**
-     * 从文本中找药
+     * 获取各模块信息<入院记录、首次病程录、手术记录、术后首程、会诊结果单、查房记录、出院小结>
+     *
+     * @param structureMap
+     * @param info
+     */
+    private void getInfo(Map<String, Date> info, Map<String, String> structureMap, String modelType, String dateKey, String... contentKey) {
+        String content = CatalogueUtil.structureMapJoin(structureMap, Lists.newArrayList(contentKey));
+        String recordDateStr = structureMap.get(dateKey);
+        if (StringUtil.isNotBlank(recordDateStr)) {
+            Date date = StringUtil.parseDateTime(recordDateStr);
+            if (StringUtil.isNotBlank(content) && date != null) {
+                info.put(modelType + "->" + content, date);
+            }
+        }
+    }
+
+    /**
+     * 核心:从文本中找药
      *
      * @param content          文本
      * @param wardDate
@@ -175,18 +222,21 @@ public class THR02986 extends QCCatalogue {
      * @param days
      * @return 如果文本中找到该药,则返回空字符串
      */
-    private String getMissDrug(String content, Date wardDate, Date doctorAdviceDate, String[] drugs, int days, String missDrug) {
+    private String getMissDrug(String content, Date wardDate, Date doctorAdviceDate, Set<String> drugs, int days, String missDrug) {
         if ("时间不匹配".equals(missDrug)) {
             missDrug = "";//初始化缺失药物
         }
-        if (doctorAdviceDate.before(wardDate) && !CatalogueUtil.compareTime(doctorAdviceDate, wardDate, days * 24 * 60L)) {
+        //开医嘱时间起,昨天今天明天记录内查找药
+        if ((doctorAdviceDate.before(wardDate) && !CatalogueUtil.compareTime(doctorAdviceDate, wardDate, days * 24 * 60L))
+                || (wardDate.before(doctorAdviceDate) && !CatalogueUtil.compareTime(wardDate, doctorAdviceDate, 24 * 60L))) {
             boolean findDrug = false;
             for (String drug : drugs) {
                 if (StringUtil.isBlank(drug)) {
                     continue;
                 }
                 if (content.contains(drug.replaceAll("[^\\u4e00-\\u9fa5]", ""))
-                        || regexFind(content, "继续", "治疗") || regexFind(content, "维持", "治疗")) {
+                        || regexFind(content, "继续", "治疗") || regexFind(content, "维持", "治疗")
+                        || regexFind(content, "继续", "抗感染") || regexFind(content, "治疗", "同前")) {
                     findDrug = true;
                     break;
                 } else {
@@ -194,7 +244,7 @@ public class THR02986 extends QCCatalogue {
                 }
             }
             if (findDrug) {
-                missDrug = "";//如果找到一种素药,就把报错信息置为空
+                missDrug = "";//如果找到一种抗生素药,就把报错信息置为空
             }
         } else {
             if (StringUtil.isBlank(missDrug)) {
@@ -225,4 +275,108 @@ public class THR02986 extends QCCatalogue {
         Matcher m = p.matcher(content);
         return m.find();
     }
+
+    /**
+     * 比较两个抗生素标准词是否一致
+     *
+     * @param firstWord
+     * @param secordWord
+     * @return
+     */
+    private boolean compareStandard(String firstWord, String secordWord) {
+        if (StringUtil.isBlank(firstWord) || StringUtil.isBlank(secordWord)) {
+            return false;
+        }
+        String drugStandardWord1 = similarityUtil.getDrugStandardWord(firstWord);
+        String drugStandardWord2 = similarityUtil.getDrugStandardWord(secordWord);
+        if (drugStandardWord1 == null || drugStandardWord2 == null) {
+            return firstWord.equals(secordWord) || firstWord.contains(secordWord) || secordWord.contains(firstWord);
+        }
+        return drugStandardWord1.equals(drugStandardWord2);
+    }
+
+    /**
+     * 如果文本包含中括号([海正]美罗培南针),取括号之后的文字
+     *
+     * @param str
+     * @return
+     */
+    private String removeBracket(String str) {
+        if (str.contains("]") && str.indexOf("]") != str.length() - 1) {
+            return str.substring(str.indexOf("]") + 1);
+        }
+        return str;
+    }
+
+    private static final String[] KSS = {
+            "瑞格列奈片",
+            "西格列汀片",
+            "维格列汀片",
+            "伏格列波糖片",
+            "[合资]二甲双胍片",
+            "[进口]硫辛酸针",
+            "[合资]阿卡波糖片",
+            "格列齐特缓释片",
+            "达格列净片",
+            "[合资]格列美脲片",
+            "[绿叶]阿卡波糖胶囊",
+            "[海汇]格列美脲片",
+            "格列吡嗪缓释胶囊",
+            "[国产]阿卡波糖片",
+            "格列吡嗪控释片",
+            "[国产]二甲双胍片",
+            "吡格列酮二甲双胍片",
+            "沙格列汀片",
+            "[艾可拓]吡格列酮片",
+            "阿仑膦酸钠维D3片",
+            "[卡司平]吡格列酮片",
+            "[国产]硫辛酸针",
+            "格列喹酮片",
+            "[国产]阿仑膦酸钠肠溶片",
+            "那格列奈片",
+            "[自备]格列齐特-II片",
+            "[特]门冬胰岛素针",
+            "[预填充]甘精胰岛素针",
+            "[优泌乐50]精蛋白锌赖脯胰岛素针",
+            "[特30]门冬胰岛素30针",
+            "左旋甲状腺素片",
+            "胰岛素针",
+            "[进口]奥曲肽针",
+            "[优泌乐25]精蛋白锌赖脯胰岛素针",
+            "[国产]生长抑素针",
+            "[国产]特利加压素针",
+            "[国产]奥曲肽针",
+            "[诺和灵30R]精蛋白生物合成人胰岛素针",
+            "谷赖胰岛素针",
+            "地特胰岛素针",
+            "[进口]生长抑素针",
+            "甲巯咪唑片",
+            "降钙素针",
+            "[优泌乐]赖脯胰岛素针",
+            "利拉鲁肽针",
+            "重组甘精胰岛素针",
+            "[70/30]精蛋白锌重组人胰岛素针",
+            "[预灌封优泌乐50]精蛋白锌赖脯胰岛素针",
+            "黄体酮针",
+            "地屈孕酮片",
+            "50/50混合重组人胰岛素针",
+            "炔诺酮片",
+            "[进口]特利加压素针",
+            "戊酸雌二醇片",
+            "4.5iu生长激素针",
+            "生物合成人胰岛素针",
+            "米非司酮片",
+            "[进口]黄体酮软胶囊",
+            "十一酸睾酮胶囊",
+            "[芯中效]精蛋白锌重组人胰岛素针",
+            "[国产]丙硫氧嘧啶片",
+            "[国产]黄体酮胶囊",
+            "[芯常规]重组人胰岛素针",
+            "[自备]重组甘精胰岛素针",
+            "[密盖息]降钙素鼻喷剂",
+            "甲羟孕酮片",
+            "替勃龙片",
+            "[金尔力]降钙素鼻喷剂",
+            "雷洛昔芬片"
+    };
 }

+ 212 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/threelevelward/THR03076.java

@@ -0,0 +1,212 @@
+package com.lantone.qc.kernel.catalogue.threelevelward;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.kernel.util.SimilarityUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.DoctorAdviceDoc;
+import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
+import com.lantone.qc.pub.model.entity.Drug;
+import com.lantone.qc.pub.model.label.ThreeLevelWardLabel;
+import com.lantone.qc.pub.util.DateUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/**
+ * @author HUJING
+ * @create 2020-08-26 10:51
+ * @desc 医嘱与病程记录抗生素剂量不一致
+ **/
+@Component
+public class THR03076 extends QCCatalogue {
+    @Autowired
+    SimilarityUtil similarityUtil;
+
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        List<DoctorAdviceDoc> doctorAdviceDocs = inputInfo.getDoctorAdviceDocs();
+        List<ThreeLevelWardDoc> threeLevelWardDocs = inputInfo.getThreeLevelWardDocs();
+        if (doctorAdviceDocs.size() == 0 || threeLevelWardDocs.size() == 0) {
+            return;
+        }
+        List<Map<String, String>> docAdvStruct = doctorAdviceDocs
+                .stream()
+                .filter(Objects::nonNull)
+                .map(DoctorAdviceDoc::getStructureMap)
+                .filter(x -> StringUtil.isNotBlank(x.get("药品类型")) && x.get("药品类型").contains("抗生素") && StringUtil.isNotBlank(x.get("医嘱单次剂量")))
+                .collect(Collectors.toList());
+
+        //抗生素及开医嘱时间 <抗生素名,<抗生素用量,[抗生素使用时间...]>>
+        Map<String, Map<Double, List<String>>> antibioticInfo = Maps.newLinkedHashMap();
+        String drugName = null, value = null, startDateStr = null;
+        for (Map<String, String> structMap : docAdvStruct) {
+            drugName = structMap.get("医嘱项目名称");
+            value = structMap.get("医嘱单次剂量");
+            startDateStr = structMap.get("医嘱开始时间");
+            drugName = removeBracket(drugName);
+            String drugStandardWord = similarityUtil.getDrugStandardWord(drugName);
+            if (StringUtil.isNotBlank(drugStandardWord)) {
+                drugName = drugStandardWord;
+            }
+            collectAntibioticInfo(antibioticInfo, drugName, value, startDateStr);
+        }
+
+        //抗生素及开医嘱时间 <抗生素名,<抗生素用量,[抗生素使用时间...]>>
+        Map<String, Map<Double, List<String>>> antibioticWardInfo = Maps.newLinkedHashMap();
+        List<ThreeLevelWardDoc> allDoctorWradDocs = threeLevelWardDocs.get(0).getAllDoctorWradDocs();
+        for (ThreeLevelWardDoc doc : allDoctorWradDocs) {
+            if (doc.getThreeLevelWardLabel().size() == 0) {
+                continue;
+            }
+            ThreeLevelWardLabel label = doc.getThreeLevelWardLabel().get(0);
+            List<Drug> drugs = label.getDrugs();
+            for (Drug drug : drugs) {
+                String wardDrug = drug.getName();
+                wardDrug = removeBracket(wardDrug);
+                String drugStandardWord = similarityUtil.getDrugStandardWord(wardDrug);
+                if (StringUtil.isNotBlank(drugStandardWord)) {
+                    wardDrug = drugStandardWord;
+                }
+                if (drug.getConsumption() != null) {
+                    String consumption = drug.getConsumption().getName();
+                    collectAntibioticInfo(antibioticWardInfo, wardDrug, consumption, doc.getStructureMap().get("查房日期"));
+                }
+            }
+        }
+
+        /**
+         * 1.医嘱中开了抗生素,查房记录中没有该抗生素,则医嘱中该抗生素出现过的所有时间都会提示出来
+         * 2.医嘱中开了抗生素,查房记录中有该抗生素:
+         *      2.1 医嘱中该抗生素某使用量(如50),查房记录中没有该使用量(如只有100),则医嘱中该抗生素使用量出现过的所有时间都会提示出来
+         *      2.2 医嘱中该抗生素某使用量(如50),查房记录中也有该使用量,对比这两个时间,若医嘱时间两天内的查房记录没有该使用量,则该医嘱时间会提示出来
+         */
+        StringBuffer sb = new StringBuffer();
+        String drugKey = null;
+        for (Map.Entry<String, Map<Double, List<String>>> ai : antibioticInfo.entrySet()) {
+            drugKey = ai.getKey();
+            if (!antibioticWardInfo.containsKey(drugKey)) {
+                for (Map.Entry<Double, List<String>> ad : ai.getValue().entrySet()) {
+                    for (String date : ad.getValue()) {
+                        infoAppend(sb, drugKey, ad.getKey(), date);
+                    }
+                }
+            } else {
+                Map<Double, List<String>> adValueDate = ai.getValue();
+                Map<Double, List<String>> wardValueDate = antibioticWardInfo.get(drugKey);
+                for (Map.Entry<Double, List<String>> adMap : adValueDate.entrySet()) {
+                    Double adUsage = adMap.getKey();
+                    List<String> adDateList = adMap.getValue();
+                    if (wardValueDate.containsKey(adUsage)) {
+                        int num = 0;
+                        List<String> wardDateList = wardValueDate.get(adUsage);
+                        for (String adDate : adDateList) {
+                            for (String wardDate : wardDateList) {
+                                if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(adDate), StringUtil.parseDateTime(wardDate), 48 * 60L)) {
+                                    //如果医嘱中该药使用量的医嘱时间,两天内的查房记录中也有该用量,则找到,num+1
+                                    num++;
+                                }
+                            }
+                            if (num == 0) {
+                                infoAppend(sb, drugKey, adUsage, adDate);
+                            }
+                        }
+                    } else {
+                        //遗嘱中该抗生素使用量在查房记录中没出现过,全部提示出来药品名+时间
+                        for (String adDate : adDateList) {
+                            infoAppend(sb, drugKey, adUsage, adDate);
+                        }
+                    }
+                }
+            }
+        }
+
+        if (sb.toString().length() > 0) {
+            status.set("-1");
+            info.set(sb.toString().substring(0, sb.toString().length() - 1));
+        }
+    }
+
+    /**
+     * 拼接提示信息
+     *
+     * @param sb
+     * @param drugKey
+     * @param date
+     */
+    private void infoAppend(StringBuffer sb, String drugKey, double value, String date) {
+        sb.append(drugKey).append("->").append(value)
+                .append("(").append(DateUtil.formatDate(StringUtil.parseDateTime(date))).append(")").append(",");
+    }
+
+    /**
+     * 收集抗生素各种信息
+     *
+     * @param antibioticInfo 抗生素使用量及所有时间
+     * @param drugName       抗生素名称
+     * @param value          抗生素用量
+     * @param startDateStr   抗生素使用时间(医嘱开始时间或查房时间)
+     */
+    private void collectAntibioticInfo(Map<String, Map<Double, List<String>>> antibioticInfo, String drugName, String value, String startDateStr) {
+        Map<Double, List<String>> antibioticValueList = null;
+        double v = -1;
+        try {
+            v = Double.parseDouble(getNumber(value));
+        } catch (Exception e) {
+            System.out.println("THR03076:       " + drugName + ":" + value + "解析异常");
+        }
+        if (v < 0) {
+            return;
+        }
+        if (!antibioticInfo.containsKey(drugName)) {
+            //存该抗生素使用第1个值
+            antibioticValueList = Maps.newLinkedHashMap();
+            antibioticValueList.put(v, Lists.newArrayList(startDateStr));
+            antibioticInfo.put(drugName, antibioticValueList);
+        } else {
+            antibioticValueList = antibioticInfo.get(drugName);
+            //存该抗生素使用量第n个时间
+            if (antibioticValueList.containsKey(v)) {
+                antibioticValueList.get(v).add(startDateStr);
+            } else {
+                //存该抗生素使用量第1个时间
+                antibioticValueList.put(v, Lists.newArrayList(startDateStr));
+            }
+        }
+    }
+
+    public static String getNumber(String content) {
+        String group = "";
+        String compile = "([1-9]\\d*\\.?\\d*)|(0\\.\\d*[1-9]|\\.\\d*[1-9]|0)";
+        Pattern p = Pattern.compile(compile);
+        Matcher matcher = p.matcher(content);
+        if (matcher.find()) {
+            group = matcher.group(0);
+        }
+        return group;
+    }
+
+    /**
+     * 如果文本包含中括号([海正]美罗培南针),取括号之后的文字
+     *
+     * @param str
+     * @return
+     */
+    private String removeBracket(String str) {
+        if (str.contains("]") && str.indexOf("]") != str.length() - 1) {
+            return str.substring(str.indexOf("]") + 1);
+        }
+        return str;
+    }
+
+}

+ 23 - 0
kernel/src/main/java/com/lantone/qc/kernel/client/NewSimilarityBatchServiceClient.java

@@ -0,0 +1,23 @@
+package com.lantone.qc.kernel.client;
+
+
+import com.alibaba.fastjson.JSONArray;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+
+/**
+ * @Description: 调用新文本相似度服务
+ * @author: 胡敬
+ * @time: 2020/08/26 13:43
+ */
+@FeignClient(value = "Similarity-new-batch-service", url="${NewBatchSimilarity.url}")
+public interface NewSimilarityBatchServiceClient {
+
+    @PostMapping(value = "")
+    String getAnnotation(@RequestBody JSONArray similarityVo);
+}
+
+
+

+ 23 - 0
kernel/src/main/java/com/lantone/qc/kernel/client/NewSimilarityServiceClient.java

@@ -0,0 +1,23 @@
+package com.lantone.qc.kernel.client;
+
+
+import com.alibaba.fastjson.JSONObject;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+
+/**
+ * @Description: 调用文本相似度服务
+ * @author: 胡敬
+ * @time: 2020/08/26 13:43
+ */
+@FeignClient(value = "Similarity-new-service", url="${NewSimilarity.url}")
+public interface NewSimilarityServiceClient {
+
+    @PostMapping(value = "")
+    String getAnnotation(@RequestBody JSONObject similarityVo);
+}
+
+
+

+ 79 - 8
kernel/src/main/java/com/lantone/qc/kernel/util/SimilarityUtil.java

@@ -3,13 +3,18 @@ package com.lantone.qc.kernel.util;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
-import com.lantone.qc.kernel.client.SimilarityServiceClient;
-import com.lantone.qc.pub.model.vo.SimilarityVo;
+import com.google.common.collect.Maps;
+import com.lantone.qc.kernel.client.NewSimilarityBatchServiceClient;
+import com.lantone.qc.kernel.client.NewSimilarityServiceClient;
 import com.lantone.qc.pub.util.StringUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Component;
 
+import java.util.List;
+import java.util.Map;
+
 /**
  * @Description:
  * @author: rengb
@@ -20,7 +25,10 @@ import org.springframework.stereotype.Component;
 public class SimilarityUtil {
 
     @Autowired
-    private SimilarityServiceClient similarityServiceClient;
+    private NewSimilarityServiceClient newSimilarityServiceClient;
+
+    @Autowired
+    private NewSimilarityBatchServiceClient newSimilarityBatchServiceClient;
 
     /**
      * 根据相似度,获取药品标准词
@@ -28,6 +36,7 @@ public class SimilarityUtil {
      * @param drugWord
      * @return
      */
+    @Cacheable(value = "drugCache", key = "#drugWord", unless = "#result == null")
     public String getDrugStandardWord(String drugWord) {
         String ret = null;
         try {
@@ -58,15 +67,11 @@ public class SimilarityUtil {
         }
         JSONArray ret = null;
         try {
-            JSONArray similarContent = new JSONArray();
             JSONObject detailContent = new JSONObject();
             detailContent.put("word_type", word_type);
             detailContent.put("word", word);
             detailContent.put("number", number);
-            similarContent.add(detailContent);
-            SimilarityVo similarityVo = new SimilarityVo();
-            similarityVo.setData(similarContent);
-            String similarJson = similarityServiceClient.getAnnotation(similarityVo);
+            String similarJson = newSimilarityServiceClient.getAnnotation(detailContent);
             JSONObject similarJsonObject = JSON.parseObject(similarJson);
             if (similarJsonObject.getBooleanValue("status")) {
                 ret = similarJsonObject.getJSONArray("standard_words");
@@ -77,4 +82,70 @@ public class SimilarityUtil {
         return ret;
     }
 
+    /**
+     * 根据相似度,获取药品标准词
+     *
+     * @param input
+     * @param wordType
+     * @return
+     */
+    public Map<String, String> getDrugStandardWordBatch(List<String> input, String wordType) {
+        Map<String, String> wordMap = Maps.newHashMap();
+        JSONArray inputData = new JSONArray();
+        JSONObject micro = null;
+        JSONObject similarJsonObject = null;
+        JSONArray ret = null;
+        try {
+            for (String word : input) {
+                micro = new JSONObject();
+                micro.put("word_type", wordType);
+                micro.put("word", word);
+                micro.put("number", 1);
+                inputData.add(micro);
+            }
+            if (inputData.size() > 0) {
+                JSONObject data = similarityBatchRequest(inputData);
+                JSONObject wordTypeJson = data.getJSONObject(wordType);
+                for (String word : input) {
+                    similarJsonObject = wordTypeJson.getJSONObject(word);
+                    if (similarJsonObject != null && similarJsonObject.getBooleanValue("status")) {
+                        ret = similarJsonObject.getJSONArray("standard_words");
+                        if (ret != null && ret.size() == 1) {
+                            JSONObject standardWord = ret.getJSONObject(0);
+                            if (standardWord.getDoubleValue("rate") > 0.8) {
+                                String result = standardWord.getString("standard_word");
+                                wordMap.put(word, result);
+                            }
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+        return wordMap;
+    }
+
+    /**
+     * 发送相似度批量请求
+     *
+     * @param jsonArray 全部需要查询的标准词封装后的集合
+     * @return 返回具体数据集合
+     */
+    public JSONObject similarityBatchRequest(JSONArray jsonArray) {
+        if (jsonArray.size() == 0) {
+            return null;
+        }
+        JSONObject ret = null;
+        try {
+            String similarJson = newSimilarityBatchServiceClient.getAnnotation(jsonArray);
+            JSONObject similarJsonObject = JSON.parseObject(similarJson);
+            if (similarJsonObject.getBooleanValue("status")) {
+                ret = similarJsonObject.getJSONObject("data");
+            }
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+        return ret;
+    }
 }