فهرست منبع

合并:义乌妇保、义乌中心医院、厦门规则初步并入北仑

rengb 4 سال پیش
والد
کامیت
5c81d8a2e6
100فایلهای تغییر یافته به همراه9609 افزوده شده و 0 حذف شده
  1. 84 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaiyiyi/behospitalized/BEH0372.java
  2. 117 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaiyiyi/crisisvaluereport/CRI0382.java
  3. 229 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaiyiyi/threelevelward/THR0128.java
  4. 69 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0005.java
  5. 53 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0015.java
  6. 43 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0016.java
  7. 64 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0017.java
  8. 70 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0043.java
  9. 110 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0058.java
  10. 219 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH02980.java
  11. 37 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH03091.java
  12. 79 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0372.java
  13. 96 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0378.java
  14. 34 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0411.java
  15. 75 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0414.java
  16. 79 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0441.java
  17. 74 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0442.java
  18. 69 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0443.java
  19. 77 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0444.java
  20. 74 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0445.java
  21. 45 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0446.java
  22. 62 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/clinicalblood/CLI0305.java
  23. 97 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/clinicalblood/CLI03063.java
  24. 61 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/clinicalblood/CLI0309.java
  25. 41 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/clinicalblood/CLI0568.java
  26. 56 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/consultation/CON0382.java
  27. 111 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/crisisvaluereport/CRI0382.java
  28. 37 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/deathcasediscuss/DEAC0098.java
  29. 37 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/deathcasediscuss/DEAC0109.java
  30. 33 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/deathrecord/DEAR0337.java
  31. 91 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/dutyshiftsystem/DUT0598.java
  32. 71 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/firstcourserecord/FIRC0082.java
  33. 67 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/firstcourserecord/FIRC0092.java
  34. 43 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/firstcourserecord/FIRC02910.java
  35. 80 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/firstpagerecord/FIRP0161.java
  36. 66 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/leavehospital/LEA0148.java
  37. 98 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/leavehospital/LEA0149.java
  38. 86 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/leavehospital/LEA02987.java
  39. 50 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/operationdiscussion/OPE0322.java
  40. 146 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/operationdiscussion/OPE0369.java
  41. 57 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/operationdiscussion/OPE0647.java
  42. 139 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/preoperativediscussion/PRE0328.java
  43. 48 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0122.java
  44. 165 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0125.java
  45. 184 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0126.java
  46. 203 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0127.java
  47. 229 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0128.java
  48. 76 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0134.java
  49. 77 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0139.java
  50. 113 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0144.java
  51. 134 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR02900.java
  52. 68 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR02967.java
  53. 518 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR02985.java
  54. 77 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR03015.java
  55. 56 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR03017.java
  56. 342 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR03076.java
  57. 603 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR03077.java
  58. 150 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0588.java
  59. 133 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0601.java
  60. 41 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0698.java
  61. 87 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0001.java
  62. 114 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0006.java
  63. 67 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0009.java
  64. 225 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0011.java
  65. 73 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0013.java
  66. 118 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0014.java
  67. 59 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0022.java
  68. 60 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0024.java
  69. 80 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0025.java
  70. 65 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0026.java
  71. 59 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0028.java
  72. 90 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0029.java
  73. 71 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0030.java
  74. 78 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0031.java
  75. 47 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0032.java
  76. 54 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0034.java
  77. 54 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0035.java
  78. 59 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0039.java
  79. 42 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0041.java
  80. 70 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0043.java
  81. 57 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0044.java
  82. 54 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0045.java
  83. 60 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0048.java
  84. 56 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0050.java
  85. 75 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0053.java
  86. 64 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0054.java
  87. 82 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0056.java
  88. 108 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0058.java
  89. 54 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0068.java
  90. 71 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0070.java
  91. 68 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0072.java
  92. 75 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0073.java
  93. 47 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0075.java
  94. 96 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH02902.java
  95. 65 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH02903.java
  96. 70 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH02966.java
  97. 192 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH02980.java
  98. 83 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0372.java
  99. 117 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0375.java
  100. 0 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0376.java

+ 84 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaiyiyi/behospitalized/BEH0372.java

@@ -0,0 +1,84 @@
+package com.lantone.qc.kernel.catalogue.hospital.ninghaiyiyi.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.MaritalStatus;
+import com.lantone.qc.pub.model.label.MaritalLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+/**
+ * @Description: 婚姻状况前后不一致
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0372 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+
+        String basicInfoStatus = inputInfo.getBeHospitalizedDoc().getStructureMap().get("婚育史");
+        String bhbasicInfoStatus = inputInfo.getBeHospitalizedDoc().getStructureMap().get("婚姻状况");
+        if (StringUtil.isBlank(bhbasicInfoStatus)) {
+            bhbasicInfoStatus = inputInfo.getBeHospitalizedDoc().getStructureMap().get("婚姻");
+        }
+        if (StringUtil.isBlank(basicInfoStatus) || StringUtil.isBlank(bhbasicInfoStatus)) {
+            status.set("0");
+            return;
+        }
+
+        if (bhbasicInfoStatus.equals("未婚") && basicInfoStatus.contains("结婚")) {
+            return;
+        }
+
+        if (bhbasicInfoStatus.equals("未婚") && basicInfoStatus.contains("未婚")) {
+            status.set("0");
+            return;
+        }
+
+        if (StringUtil.isNotBlank(bhbasicInfoStatus) && basicInfoStatus.equals("其他")) {
+            status.set("0");
+            return;
+        }
+
+        if (bhbasicInfoStatus.equals("丧偶") &&
+                (basicInfoStatus.contains("已故") || basicInfoStatus.contains("丧偶") || basicInfoStatus.contains("去世") ||
+                        basicInfoStatus.contains("亡故") || basicInfoStatus.contains("已逝"))) {
+            status.set("0");
+            return;
+        }
+
+        if ((bhbasicInfoStatus.equals("离婚") || bhbasicInfoStatus.equals("离异")) &&
+                (basicInfoStatus.contains("离异") || bhbasicInfoStatus.equals("离婚"))) {
+            status.set("0");
+            return;
+        }
+
+        if (bhbasicInfoStatus.equals("已婚") && (basicInfoStatus.contains("结婚") || basicInfoStatus.contains("再婚") || basicInfoStatus.contains("已婚") )) {
+            status.set("0");
+            return;
+        }
+
+        MaritalStatus mts = inputInfo.getBeHospitalizedDoc().getMaritalLabel().getMaritalStatus();
+        if (mts != null && StringUtil.isNotBlank(mts.getName())) {
+            String maritalStatus = mts.getName();
+            if (basicInfoStatus.equals(maritalStatus)) {
+                status.set("0");
+                return;
+            }
+        }
+
+        //无婚育史
+        MaritalLabel maritalLabel = inputInfo.getBeHospitalizedDoc().getMaritalLabel();
+        if (maritalLabel == null || maritalLabel.getText() == null) {
+            status.set("0");
+        }
+    }
+
+}

+ 117 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaiyiyi/crisisvaluereport/CRI0382.java

@@ -0,0 +1,117 @@
+package com.lantone.qc.kernel.catalogue.hospital.ninghaiyiyi.crisisvaluereport;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.CrisisInfoDoc;
+import com.lantone.qc.pub.model.doc.CrisisValueReportDoc;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @Description: 接到危急值报告后6小时内无病程记录
+ * @author: rengb
+ * @time: 2020/3/19 19:54
+ */
+@Component
+public class CRI0382 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        //无危急值结构化信息
+        List<CrisisInfoDoc> crisisInfoDocs = inputInfo.getCrisisInfoDocs();
+        if (crisisInfoDocs == null || crisisInfoDocs.size() == 0) {
+            return;
+        }
+        //有结构化信息但无危急值文书,如果报告时间都未超过6小时 允许无文书
+        boolean isOutTime = false;
+        Date currentDate = new Date();
+        int timeCha = 21600000;
+        String[] dateFormats = new String[]{"yyyy年MM月dd日HH时mm分", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm"};
+        for (CrisisInfoDoc crisisInfoDoc : crisisInfoDocs) {
+            String reptTime = crisisInfoDoc.getStructureMap().get("报告时间");
+            if (StringUtils.isNotEmpty(reptTime)) {
+                if (currentDate.getTime() - StringUtil.parseDateTime(reptTime, dateFormats).getTime() > timeCha) {
+                    isOutTime = true;
+                }
+            }
+        }
+        ;
+        if (isOutTime == false) {   //所有文书都未超过6小时,规则直接通过
+            return;
+        }
+
+        List<CrisisValueReportDoc> crisisValueReportDocs = inputInfo.getCrisisValueReportDocs();
+        //如果有危急值结构化数据 但无文书则直接提醒无危急值报告
+        if (crisisValueReportDocs == null || crisisValueReportDocs.size() == 0) {
+            status.set("-1");
+            return;
+        }
+        List<String> findCrisises = new ArrayList<>();
+        List<String> allCrisises = new ArrayList<>();
+        crisisInfoDocs.forEach(crisisInfoDoc -> {
+            String reptTime = crisisInfoDoc.getStructureMap().get("报告时间");
+            String crisisName = crisisInfoDoc.getStructureMap().get("危急结果值");
+            String crisisNm = "";
+            String companyNum = "";
+            if (crisisName.contains("项目为")) {
+                crisisName = crisisName.substring(crisisName.indexOf("项目为") + 3);
+            }
+            if (crisisName.contains(",结果:")) {
+                crisisNm = crisisName.split(",结果:")[0];
+                companyNum = crisisName.split(",结果:")[1];
+                if (StringUtil.isNotBlank(companyNum) && companyNum.contains("单位:")) {
+                    companyNum = companyNum.replaceAll("单位:", "");
+                }
+            }
+            allCrisises.add(reptTime);
+            if (StringUtils.isNotEmpty(reptTime)) {
+                //当前时间和报告时间未超过6小时,规则通过
+                if (currentDate.getTime() - StringUtil.parseDateTime(reptTime, dateFormats).getTime() < timeCha) {
+                    findCrisises.add(reptTime);
+                } else {
+                    for (CrisisValueReportDoc crisisValueReportDoc : crisisValueReportDocs) {
+                        String recordTimeStr = crisisValueReportDoc.getStructureMap().get("病历日期");
+                        String docReptContent = crisisValueReportDoc.getStructureMap().get("病情分析及处理");
+                        if ((StringUtil.parseDateTime(recordTimeStr, dateFormats).getTime() - StringUtil.parseDateTime(reptTime, dateFormats).getTime()) < timeCha
+                                && (StringUtil.removeBlank(docReptContent).contains(StringUtil.removeBlank(crisisName)) ||
+                                (StringUtil.isNotBlank(crisisNm) && StringUtil.isNotBlank(companyNum)
+                                        && StringUtil.removeBlank(docReptContent).contains(StringUtil.removeBlank(crisisNm))
+                                        && StringUtil.removeBlank(docReptContent).contains(StringUtil.removeBlank(companyNum))
+                                ))) {
+                            findCrisises.add(reptTime);
+                            break;
+                        }
+                    }
+                }
+            }
+        });
+        // (StringUtil.parseDateTime(recordTimeStr, dateFormats).getTime() - StringUtil.parseDateTime(reptTime, dateFormats).getTime()) > 0
+        //                                &&
+        if (findCrisises.size() != allCrisises.size()) {
+            status.set("-1");
+            allCrisises.forEach(reptTime -> {
+                String criticalValueName = "";
+                if (!findCrisises.contains(reptTime) && !info.get().contains(reptTime)) {
+                    for (CrisisInfoDoc crisisInfoDoc : crisisInfoDocs) {
+                        if (reptTime.equals(crisisInfoDoc.getStructureMap().get("报告时间"))) {
+                            criticalValueName = crisisInfoDoc.getStructureMap().get("危急值名称");
+                        }
+                    }
+                    if (StringUtils.isEmpty(info.get())) {
+                        info.set(reptTime + " 危急值名称(" + criticalValueName + ")");
+                    } else {
+                        info.set(info.get() + "; " + reptTime + " 危急值名称(" + criticalValueName + ")");
+                    }
+                }
+            });
+        }
+    }
+
+}

+ 229 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaiyiyi/threelevelward/THR0128.java

@@ -0,0 +1,229 @@
+package com.lantone.qc.kernel.catalogue.hospital.ninghaiyiyi.threelevelward;
+
+import com.lantone.qc.dbanaly.util.KernelConstants;
+import com.lantone.qc.dbanaly.util.SpecialStorageUtil;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.Content;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.FirstCourseRecordDoc;
+import com.lantone.qc.pub.model.doc.MedicalRecordInfoDoc;
+import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
+import com.lantone.qc.pub.model.doc.operation.OperationDoc;
+import com.lantone.qc.pub.model.doc.ward.AttendingDoctorWardDoc;
+import com.lantone.qc.pub.util.DateUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : THR0128
+ * @Description : 每周无3次主治医师查房记录
+ * @Author : 胡敬
+ * @Date: 2020-03-19 16:52
+ */
+@Component
+public class THR0128 extends QCCatalogue {
+    @Autowired
+    private SpecialStorageUtil specialStorageUtil;
+
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        MedicalRecordInfoDoc medicalRecordInfoDoc = inputInfo.getMedicalRecordInfoDoc();
+        if (medicalRecordInfoDoc != null && medicalRecordInfoDoc.getStructureMap() != null) {
+            //入院日期
+            String admisTime = medicalRecordInfoDoc.getStructureMap().get("behospitalDate");
+            //出院日期
+            String dischargeTime = medicalRecordInfoDoc.getStructureMap().get("leaveHospitalDate");
+            if (CatalogueUtil.isEmpty(admisTime)) {
+                return;
+            }
+            String presentTime = DateUtil.nowString();
+            //如果如果入院未超过7天则不判断该条规则
+            if (!CatalogueUtil.isEmpty(admisTime) && !CatalogueUtil.isEmpty(presentTime)) {
+                if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(presentTime), (long) (7 * 24 * 60))) {
+                    return;
+                }
+            }
+            //如果住院天数小于7天则不判断该条规则
+            if (!CatalogueUtil.isEmpty(admisTime) && !CatalogueUtil.isEmpty(dischargeTime)) {
+                if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(dischargeTime), (long) (7 * 24 * 60))) {
+                    return;
+                }
+            } else {
+                if (inputInfo.getThreeLevelWardDocs().size() == 0) {
+                    status.set("-1");
+                    return;
+                }
+            }
+
+            if (inputInfo.getBeHospitalizedDoc() != null && inputInfo.getThreeLevelWardDocs().size() > 0) {
+                if (CatalogueUtil.isEmpty(admisTime)) {
+                    return;
+                }
+                //开始时间(入院时间)
+                Date beginDate = StringUtil.parseDateTime(admisTime);
+                if (beginDate == null) {
+                    return;
+                }
+
+                ThreeLevelWardDoc threeLevelWardDoc = inputInfo.getThreeLevelWardDocs().get(0);
+                List<ThreeLevelWardDoc> allDoctorWradDocs = threeLevelWardDoc.getAllDoctorWradDocs();
+                if (allDoctorWradDocs.size() == 0) {
+                    status.set("0");
+                    return;
+                }
+                Date lastRecordDate = getLastRecordDate(allDoctorWradDocs);
+                if (lastRecordDate == null) {
+                    return;
+                }
+                int hoursPerWeek = 7 * 24 * 60;
+                String roundRecordThisWeek = "";
+                List<String> roundRecordEveryWeek = new ArrayList<>();
+                beginDate = DateUtil.dateZeroClear(beginDate);//从入院记录当天天0点开始算
+                int i = 1;
+                //长兴首次病程算一次主治查房,所以第一周只需要两次主治查房就可以
+                int rounds = 0;//主治查房次数
+                Date firstWeek = DateUtil.addDate(beginDate, 7);
+                for (AttendingDoctorWardDoc attendingDoctorWardDoc : threeLevelWardDoc.getAttendingDoctorWardDocs()) {//循环筛选主治,找出地日在第一周的个数
+                    String recordTime = attendingDoctorWardDoc.getStructureMap().get("查房日期");
+                    Date recordDate = StringUtil.parseDateTime(recordTime);
+                    if (recordDate.before(firstWeek)) {
+                        rounds = rounds + 1;
+                    }
+                }
+                if (rounds >= 2) {
+                    return;
+                }
+                String lastWardDateRange = "";
+                List<String> lastWardDateRangeList = new ArrayList<>();
+                //每周的病历记录
+                while (i >= 1) {
+                    roundRecordThisWeek = extractWardRecord(inputInfo, allDoctorWradDocs, beginDate, hoursPerWeek, lastRecordDate);
+                    if (CatalogueUtil.isEmpty(roundRecordThisWeek)) {
+                        break;
+                    }
+                    //如果6天后日期大于出院日期,跳过
+                    if (StringUtil.isBlank(dischargeTime)) {
+                        dischargeTime = presentTime;
+                    }
+                    Date sixDate = DateUtil.addDate(beginDate, 7);
+                    if (StringUtil.parseDateTime(dischargeTime).before(sixDate)) {
+                        break;
+                    }
+                    lastWardDateRange = DateUtil.formatDate(beginDate) + "    ->    " + DateUtil.formatDate(sixDate);
+                    lastWardDateRangeList.add(lastWardDateRange);
+                    roundRecordEveryWeek.add(roundRecordThisWeek);
+                    beginDate = DateUtil.addDate(beginDate, 7);
+                    i++;
+                }
+                if (roundRecordEveryWeek.size() == 0) {
+                    status.set("0");
+                    return;
+                }
+                boolean firstRecordAttendExist = findfirstRecordAttend(inputInfo);
+                List<String> resultInfos = new ArrayList<>();
+                for (int j = 0; j < roundRecordEveryWeek.size(); j++) {
+                    int indicationsNum = CatalogueUtil.appearNumber(roundRecordEveryWeek.get(j).split(","), Content.attend);
+                    //三级医师查房算一次主治查房
+                    int threeDoctorNum = CatalogueUtil.appearNumber(roundRecordEveryWeek.get(j).split(","), "三级");
+                    if (j == 0 && firstRecordAttendExist) { //如果首程中医师签名为主治医师,第一周查房记录也要加上
+                        indicationsNum += 1;
+                    }
+                    if (indicationsNum + threeDoctorNum < 3) {
+                        //每周无3次主治医师查房记录
+                        status.set("-1");
+                        resultInfos.add(lastWardDateRangeList.get(j));
+                    }
+                }
+
+                if (resultInfos.size() > 0) {
+                    info.set(StringUtils.join(resultInfos.toArray(), ";"));
+                }
+            }
+        }
+    }
+
+    private Date getLastRecordDate(List<ThreeLevelWardDoc> allDoctorWradDocs) {
+        ThreeLevelWardDoc threeLevelWardDoc = allDoctorWradDocs.get(allDoctorWradDocs.size() - 1);
+        Map<String, String> lastWardDocStructureMap = threeLevelWardDoc.getStructureMap();
+        String wardDateStr = lastWardDocStructureMap.get("查房日期");
+        if (StringUtil.isNotBlank(wardDateStr)) {
+            return StringUtil.parseDateTime(wardDateStr);
+        }
+        return null;
+    }
+
+
+    /**
+     * 抽取duration分钟内所有查房标题
+     * 抽取一周内所有查房标题,若一周内记录少于6天,则返回""
+     *
+     * @param threeLevelWardDocs
+     * @param admisDate
+     * @param duration
+     * @return
+     */
+    private static String extractWardRecord(InputInfo inputInfo, List<ThreeLevelWardDoc> threeLevelWardDocs, Date admisDate, int duration, Date maxRecordDate) {
+        String recordTime = "", recordTitle = "", title = "";
+        List<Date> dateList = new ArrayList();
+        for (ThreeLevelWardDoc threeLevelWardDoc : threeLevelWardDocs) {
+            Map<String, String> threeLevelWardStructureMap = threeLevelWardDoc.getStructureMap();
+            recordTime = threeLevelWardStructureMap.get("查房日期");
+            title = threeLevelWardStructureMap.get("查房标题");
+            if (StringUtil.isBlank(recordTime) || StringUtil.isBlank(title)) {
+                continue;
+            }
+            Date recordDate = StringUtil.parseDateTime(recordTime);
+            if (recordDate == null) {
+                continue;
+            }
+            /* 替换查房标题中主刀/一助的职称 */
+            List<OperationDoc> operationDocs = inputInfo.getOperationDocs();
+            if (title.contains("主刀") || title.contains("术后第")) {
+                String doctorTitle = CatalogueUtil.getDoctorTitle(operationDocs, recordDate, "主刀医师");
+                title = title.replace("主刀", doctorTitle).replace("术后第", doctorTitle);
+            } else if (title.contains("一助")) {
+                String doctorTitle = CatalogueUtil.getDoctorTitle(operationDocs, recordDate, "一助");
+                title = title.replace("一助", doctorTitle);
+            }
+            if (admisDate.before(recordDate) && !CatalogueUtil.compareTime(admisDate, DateUtil.dateZeroClear(recordDate), (long) duration)) {
+                recordTitle += title + ",";
+                dateList.add(recordDate);
+            }
+        }
+        if (dateList.size() > 0) {
+            //dateList.sort(Date::compareTo);
+            if (!maxRecordDate.equals(dateList.get(dateList.size() - 1)) || CatalogueUtil.compareTime(admisDate, dateList.get(dateList.size() - 1), Long.valueOf(6 * 24 * 60))) {
+                return recordTitle;
+            }
+        }
+        return "";
+    }
+
+    private boolean findfirstRecordAttend(InputInfo inputInfo) {
+        FirstCourseRecordDoc firstCourseRecordDoc = inputInfo.getFirstCourseRecordDoc();
+        if (firstCourseRecordDoc == null) {
+            return false;
+        }
+        Map<String, Map<String, Object>> hospitalDoctorMap = specialStorageUtil.getJsonStringValue(KernelConstants.HOSPITAL_DOCTOR_MAP);
+        String doctorSign = firstCourseRecordDoc.getStructureMap().get("医师签名");
+        if (hospitalDoctorMap == null || StringUtil.isBlank(doctorSign)) {
+            return false;
+        }
+        if (hospitalDoctorMap.containsKey(doctorSign)) {
+            Object professor = hospitalDoctorMap.get(doctorSign).get("professor");
+            if (professor != null) {
+                return professor.toString().contains("主治") || professor.toString().contains("主任");
+            }
+        }
+        return false;
+    }
+}

+ 69 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0005.java

@@ -0,0 +1,69 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.behospitalized;
+
+import com.google.common.collect.Lists;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.PD;
+import com.lantone.qc.pub.model.label.ChiefLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * @ClassName : BEH0005
+ * @Description :主诉症状时间描述前后不合理
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class BEH0005 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            return;
+        }
+        List<Integer> timeIndex = new ArrayList<>();
+        ChiefLabel chiefLabel = inputInfo.getBeHospitalizedDoc().getChiefLabel();
+        if (chiefLabel == null) {
+            return;
+        }
+        List<PD> pds = chiefLabel.getPds();
+        String chiefText = chiefLabel.getText();
+        if (StringUtil.isNotBlank(chiefText)) {
+            chiefText = chiefText.replace("月经", "");/* 月经这个词会影响逻辑判断,这里把月经这个词去除 */
+            if (chiefText.contains("检查") || chiefText.contains("术后") || chiefText.contains("药物")) {
+                return;
+            } else {
+                List<String> words = Lists.newArrayList("年", "月", "周", "天", "日", "时", "分");
+                String name;
+                for (PD pd : pds) {
+                    name = pd.getName();
+                    if (StringUtil.isBlank(name)) {
+                        continue;
+                    }
+                    for (String word : words) {
+                        if (name.contains(word)) {
+                            timeIndex.add(chiefText.indexOf(name));
+                            break;
+                        }
+                    }
+                }
+            }
+            if (timeIndex.size() > 0) {
+                int min = timeIndex.get(0);
+                for (Integer data : timeIndex) {
+                    if (data < min) {
+                        min = data;
+                    }
+                }
+                if (min != timeIndex.get(0)) {
+                    status.set("-1");
+                }
+            }
+        }
+    }
+}

+ 53 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0015.java

@@ -0,0 +1,53 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.behospitalized;
+
+import com.lantone.qc.dbanaly.util.KernelConstants;
+import com.lantone.qc.dbanaly.util.SpecialStorageUtil;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.BodyPart;
+import com.lantone.qc.pub.model.entity.Clinical;
+import com.lantone.qc.pub.model.label.PresentLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+
+/**
+ * @ClassName : BEH0015
+ * @Description :  现病史症状缺少部位,只判断现病史中的第一个症状
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class BEH0015 extends QCCatalogue {
+    @Autowired
+    private SpecialStorageUtil specialStorageUtil;
+
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            return;
+        }
+        PresentLabel presentLabel = inputInfo.getBeHospitalizedDoc().getPresentLabel();
+        if (presentLabel == null || StringUtil.isBlank(presentLabel.getText())) {
+            status.set("0");
+            return;
+        }
+        List<String> clinicalList = (List<String>) specialStorageUtil.getJsonStringValue(KernelConstants.CONCEPT_CLINIC_BODYPART_PROPERTIES_LIST);
+        List<Clinical> clinicals = presentLabel.getClinicals();
+        if (clinicals.size() > 0) {
+            Clinical clinical = clinicals.get(0);
+            if (clinicalList.contains(clinical.getName())) {
+                BodyPart bodyPart = clinical.getBodyPart();
+                if (bodyPart == null) {
+                    status.set("-1");
+                    info.set(clinical.getName());
+                }
+            }
+
+        }
+    }
+}

+ 43 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0016.java

@@ -0,0 +1,43 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Clinical;
+import com.lantone.qc.pub.model.entity.Property;
+import com.lantone.qc.pub.model.label.PresentLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+
+/**
+ * @ClassName : BEH0016
+ * @Description :  现病史症状缺少性质
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class BEH0016 extends QCCatalogue {
+
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            return;
+        }
+        PresentLabel presentLabel = inputInfo.getBeHospitalizedDoc().getPresentLabel();
+        if (presentLabel == null || StringUtil.isBlank(presentLabel.getText())) {
+            return;
+        }
+        List<Clinical> clinicals = inputInfo.getBeHospitalizedDoc().getPresentLabel().getClinicals();
+        if (clinicals.size() > 0) {
+            Clinical clinical = clinicals.get(0);
+            Property property = clinical.getProperty();
+            if (property == null) {
+                info.set(clinical.getName());
+                status.set("-1");
+            }
+        }
+    }
+}

+ 64 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0017.java

@@ -0,0 +1,64 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Clinical;
+import com.lantone.qc.pub.model.entity.PD;
+import com.lantone.qc.pub.model.label.PresentLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+
+/**
+ * @ClassName : BEH0017
+ * @Description :  现病史症状缺少时间描述
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class BEH0017 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        PresentLabel presentLabel = inputInfo.getBeHospitalizedDoc().getPresentLabel();
+        if (presentLabel == null) {
+            status.set("0");
+            return;
+        }
+        String presentText = presentLabel.getText();
+        if (StringUtil.isBlank(presentText) ||
+                (StringUtil.isNotBlank(presentText) && presentText.contains("复查"))) {
+            status.set("0");
+            return;
+        }
+        List<Clinical> clinicals = presentLabel.getClinicals();
+        if (clinicals.size() > 0) {
+            for (Clinical clinical : clinicals) {
+                List<PD> timestamp = clinical.getTimestamp();
+                if (ListUtil.isNotEmpty(timestamp)) {
+                    status.set("0");
+                    return;
+                }
+            }
+            //现病史取第一个症状
+            //            Clinical clinical = clinicals.get(0);
+            //            List<PD> timestamp = clinical.getTimestamp();
+            //            if (timestamp == null) {
+            //                info.set(clinical.getName());
+            //            } else {
+            //                status.set("0");
+            //            }
+        } else {
+            status.set("0");
+        }
+        if (presentLabel.getPds().size() > 0) {
+            status.set("0");
+        }
+    }
+}

+ 70 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0043.java

@@ -0,0 +1,70 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Address;
+import com.lantone.qc.pub.model.label.PersonalLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * @Description: 居住地未描述
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0043 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        //台州结构化
+        Map<String, String> structureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+        if (StringUtils.isNotEmpty(structureMap.get("联系地址")) || StringUtils.isNotEmpty(structureMap.get("现住址"))
+                || StringUtils.isNotEmpty(structureMap.get("家庭住址")) || StringUtils.isNotEmpty(structureMap.get("住址"))) {
+            status.set("0");
+            return;
+        }
+
+        PersonalLabel personalLabel = inputInfo.getBeHospitalizedDoc().getPersonalLabel();
+        if (personalLabel == null) {
+            status.set("0");
+            return;
+        }
+        String text = personalLabel.getText();
+        if (StringUtil.isBlank(text) || text.contains("居住") || text.contains("生长") || text.contains("生活")
+                || text.contains("详见原病历")) {
+            status.set("0");
+            return;
+        }
+        List<Address> addresses = personalLabel.getAddresses();
+        if (ListUtil.isNotEmpty(addresses)) {
+            long count = addresses.stream().filter(i -> {
+                boolean flag = false;
+                if (i != null && StringUtil.isNotBlank(i.getName())) {
+                    if (i.getName().indexOf("居住") > -1) {
+                        flag = true;
+                    } else {
+                        Pattern pattern = Pattern.compile("[\\s\\S]*(居住|生长)[\\s\\S]{0,5}" + i.getName() + "[\\s\\S]*");
+                        flag = pattern.matcher(text).matches();
+                    }
+                }
+                return flag;
+            }).count();
+            if (count > 0) {
+                status.set("0");
+            }
+        }
+    }
+
+}

+ 110 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0058.java

@@ -0,0 +1,110 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.behospitalized;
+
+import com.google.common.collect.Lists;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.Content;
+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.entity.Family;
+import com.lantone.qc.pub.model.entity.Fertility;
+import com.lantone.qc.pub.model.label.MaritalLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * @Description: 子女数量情况未描述
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0058 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        BeHospitalizedDoc beHospitalizedDoc = inputInfo.getBeHospitalizedDoc();
+        //硬规则 匹配未育
+        String marry = beHospitalizedDoc.getStructureMap().get(Content.marry);
+        MaritalLabel maritalLabel = beHospitalizedDoc.getMaritalLabel();
+        if (maritalLabel == null) {
+            status.set("0");
+            return;
+        }
+        Fertility fertility = maritalLabel.getFertility();
+        if (fertility != null) {
+            status.set("0");
+            return;
+        }
+        String maritalText = maritalLabel.getText();
+        if (StringUtil.isBlank(maritalText)) {
+            status.set("0");
+            return;
+        } else {
+            String regex = ".*\\d?子\\d?女.*";
+            boolean flag = maritalText.matches(regex);
+            regex = ".*\\d+-\\d+-\\d+-[1-9].*";
+            boolean matches = maritalText.matches(regex);
+            regex = ".*\\d+,\\d+,\\d+,[1-9].*|.*\\d个.*|.*\\d男.*|.*\\d女.*";
+            boolean isComma = maritalText.matches(regex);
+            if (flag || matches || isComma) {
+                status.set("0");
+                return;
+            }
+        }
+        //硬规则 匹配未育
+        if ("未婚".equals(marry)) {
+            status.set("0");
+            return;
+        }
+        if (StringUtil.isNotBlank(maritalText)) {
+            List<String> words = Lists.newArrayList("未婚", "未育", "未婚育", "未生育", "未生", "0子0女"
+                    , "0-0-0-0", "详见原病历", "0-0-0-0");
+            for (String word : words) {
+                if (maritalText.contains(word)) {
+                    status.set("0");
+                    return;
+                }
+            }
+        }
+        Map<String, String> structureMap = beHospitalizedDoc.getStructureMap();
+        String familyMembersHealth = structureMap.get("家庭成员健康情况");
+        List<Family> familyList = Lists.newArrayList();
+        List<Family> familiesFl = inputInfo.getBeHospitalizedDoc().getFamilyLabel().getFamilies();
+        List<Family> familiesMl = inputInfo.getBeHospitalizedDoc().getMaritalLabel().getFamily();
+        if (ListUtil.isNotEmpty(familiesFl)) {
+            familyList.addAll(familiesFl);
+        }
+        if (ListUtil.isNotEmpty(familiesMl)) {
+            familyList.addAll(familiesMl);
+        }
+        Pattern p = Pattern.compile("[儿子女]");
+        if (StringUtil.isNotBlank(familyMembersHealth)) {
+            if (p.matcher(familyMembersHealth).find()) {
+                status.set("0");
+                return;
+            }
+        }
+        long count = familyList
+                .stream()
+                .filter(
+                        i -> i != null
+                                && StringUtil.isNotBlank(i.getName())
+                                && StringUtil.isContainNumber(i.getName())
+                                && p.matcher(i.getName()).find()
+                )
+                .count();
+        if (count > 0) {
+            status.set("0");
+        }
+    }
+
+}

+ 219 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH02980.java

@@ -0,0 +1,219 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.behospitalized;
+
+import com.alibaba.fastjson.JSONArray;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.client.ChiefPresentSimilarityServiceClient;
+import com.lantone.qc.kernel.structure.ai.ModelAI;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Diag;
+import com.lantone.qc.pub.model.entity.GeneralDesc;
+import com.lantone.qc.pub.model.entity.Negative;
+import com.lantone.qc.pub.model.label.DiagLabel;
+import com.lantone.qc.pub.model.label.PastLabel;
+import com.lantone.qc.pub.model.label.PresentLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * @ClassName : BEH02980
+ * @Description : 病历前后描述不一致
+ * @Author : Mark
+ * @Date: 2020-06-23 11:02
+ */
+@Component
+public class BEH02980 extends QCCatalogue {
+    @Autowired
+    ChiefPresentSimilarityServiceClient chiefPresentSimilarityServiceClient;
+
+    private List<String> containList = Arrays.asList("脑萎缩", "慢性", "纤颤", "高血压", "糖尿", "冠状", "冠心病", "支架", "起搏器", "房颤", "风湿");
+    private List<String> filterList = Arrays.asList("心脏病", "低血糖", "急性", ";");
+
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            return;
+        }
+        PresentLabel presentLabel = inputInfo.getBeHospitalizedDoc().getPresentLabel();
+        DiagLabel initialDiagLabel = inputInfo.getBeHospitalizedDoc().getInitialDiagLabel();
+        PastLabel pastLabel = inputInfo.getBeHospitalizedDoc().getPastLabel();
+
+        List<String> pos_diags = new ArrayList<>();
+        List<String> neg_diags = new ArrayList<>();
+        //现病史需要取一般情况之后疾病
+        if (presentLabel != null) {
+            List<GeneralDesc> generals = presentLabel.getGenerals();
+            if (generals.size() > 0) {
+                String presentText = presentLabel.getText();
+                List<Diag> presentDiags = presentLabel.getDiags();
+                /* 取现病史中一般情况之后的疾病名称 */
+                if (StringUtil.isNotBlank(presentText) && presentDiags.size() > 0) {
+                    String lastGeneral = generals.get(generals.size() - 1).getName();
+                    int lastGeneralIndex = presentText.indexOf(lastGeneral);
+                    for (Diag presentDiag : presentDiags) {
+                        if (presentDiag.getNegative() != null || presentDiag.getHospitalDiagName().contains("否认")) {
+                            continue;
+                        }
+                        /* 现病史中一般情况之后的疾病名称 */
+                        if (presentText.indexOf(presentDiag.getHospitalDiagName()) > lastGeneralIndex) {
+                            if (isContains(presentDiag.getHospitalDiagName()) && !isFilter(presentDiag.getHospitalDiagName())) {
+                                String dgname = presentDiag.getHospitalDiagName();
+                                if (presentDiag.getNegative() == null) {
+                                    if (!pos_diags.contains(dgname)) {
+                                        pos_diags.add(dgname);
+                                    }
+                                } else {
+                                    if (!neg_diags.contains(dgname)) {
+                                        neg_diags.add(dgname);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        if (pastLabel != null && StringUtils.isNotEmpty(pastLabel.getText())) {
+            extract_diags(pastLabel.getDiags(), pos_diags, neg_diags);
+            //否认其他的情况
+            String pasttext=pastLabel.getText();
+            //冠状动脉支架植入术特殊情况,只要出现,就从否认的史中去掉
+            if(neg_diags.contains("冠状动脉支架植入术")){
+                neg_diags.remove("冠状动脉支架植入术");
+            }
+            String neg_diags_first [] = pasttext.split("否认");
+            for (String str1 : neg_diags_first) {
+                String neg_diags_second [] = str1.split("、");
+                for (String str2 : neg_diags_second) {
+                    for (String neg_diag : neg_diags) {
+                        if(str2.contains(neg_diag)){
+                            String str3 = str2.substring(0,str2.indexOf(neg_diag));
+                            if(str3.contains("其它") || str3.contains("其他")) {
+                                int index= neg_diags.indexOf(neg_diag);
+                                neg_diags.set(index,"其它的");
+                            }
+                        }
+                    }
+                }
+            }
+        } else {
+            //例如邵逸夫 台州这种结构化数据,判断高血压 和 糖尿病是否有冲突
+            List<Diag> pastDiags = new ArrayList<>();
+            Map<String, String> structureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+            String a1 = structureMap.get("高血压");
+            Diag diag = new Diag();
+            diag.setName("高血压");
+            diag.setHospitalDiagName("高血压");
+            if (StringUtils.isNotEmpty(a1) && "否认".equals(a1)) {
+                Negative negative = new Negative();
+                negative.setName("否认");
+                pastDiags.add(diag);
+            } else if (StringUtils.isNotEmpty(a1) && !"否认".equals(a1)) {
+                pastDiags.add(diag);
+            }
+
+            a1 = structureMap.get("糖尿病");
+            diag = new Diag();
+            diag.setName("糖尿病");
+            diag.setHospitalDiagName("糖尿病");
+            if (StringUtils.isNotEmpty(a1) && "否认".equals(a1)) {
+                Negative negative = new Negative();
+                negative.setName("否认");
+                pastDiags.add(diag);
+            } else if (StringUtils.isNotEmpty(a1) && !"否认".equals(a1)) {
+                pastDiags.add(diag);
+            }
+
+            extract_diags(pastDiags, pos_diags, neg_diags);
+        }
+        if (initialDiagLabel != null) {
+            extract_diags(initialDiagLabel.getDiags(), pos_diags, neg_diags);
+        }
+
+        String infoStr = "";
+        int matchSum = 0;
+        ModelAI modelAI = new ModelAI();
+        for (String negdiag : neg_diags) {
+            JSONArray jsonArray = modelAI.loadChiefPresentSimilarAI(negdiag, pos_diags, false
+                    , "diagnose", chiefPresentSimilarityServiceClient);
+            if (jsonArray.size() == 2) {
+                /* 相似度最高症状 */
+                String dgname = jsonArray.getString(0);
+                if ("糖尿病".equals(negdiag) && "妊娠期糖尿病".equals(dgname)) {
+                    continue;
+                }
+                if ("高血压史".equals(negdiag) && "高血压病".equals(dgname)) {
+                    matchSum++;
+                    if (StringUtils.isEmpty(infoStr)) {
+                        infoStr = negdiag;
+                    } else {
+                        infoStr = infoStr + "," + negdiag;
+                    }
+                    continue;
+                }
+                /* 相似度分数 */
+                double likeRate = jsonArray.getDoubleValue(1);
+                if (likeRate > 0.99) {
+                    matchSum++;
+                    if (StringUtils.isEmpty(infoStr)) {
+                        infoStr = negdiag;
+                    } else {
+                        infoStr = infoStr + "," + negdiag;
+                    }
+                    continue;
+                }
+            }
+        }
+        if (matchSum > 0) {
+            status.set("-1");
+            info.set(infoStr);
+        }
+    }
+
+    //疾病史
+    private List<String> extract_diags(List<Diag> diags, List<String> pos_diags, List<String> neg_diags) {
+        List<String> dgs = new ArrayList<>();
+        for (Diag dg : diags) {
+            String dgname = dg.getHospitalDiagName();
+            if (dg.getNegative() == null) {
+                if (!pos_diags.contains(dgname)) {
+                    pos_diags.add(dgname);
+                }
+            } else {
+                if (!neg_diags.contains(dgname)) {
+                    neg_diags.add(dgname);
+                    dgs.add(dgname);
+                }
+            }
+        }
+        return dgs;
+    }
+
+    private boolean isContains(String diagName) {
+        for (String c : containList) {
+            if (diagName.contains(c)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isFilter(String diagName) {
+        for (String c : filterList) {
+            if (diagName.contains(c)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}

+ 37 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH03091.java

@@ -0,0 +1,37 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.label.MaritalLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @ClassName : BEH03091
+ * @Description :  婚育史未填写
+ * @Author : wsy
+ * @Date: 2020-06-13 15:51
+ */
+@Component
+public class BEH03091 extends QCCatalogue {
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            return;
+        }
+        MaritalLabel maritalLabel = inputInfo.getBeHospitalizedDoc().getMaritalLabel();
+        if (maritalLabel == null || StringUtil.isBlank(maritalLabel.getText())) {
+            status.set("-1");
+            return;
+        }
+        Map<String, String> beHospitalStructureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+        if (StringUtil.isBlank(beHospitalStructureMap.get("婚育史"))) {
+            status.set("-1");
+            return;
+        }
+    }
+}

+ 79 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0372.java

@@ -0,0 +1,79 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.MaritalStatus;
+import com.lantone.qc.pub.model.label.MaritalLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+/**
+ * @Description: 婚姻状况前后不一致
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0372 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            return;
+        }
+
+        String basicInfoStatus = inputInfo.getBeHospitalizedDoc().getStructureMap().get("婚育史");
+        String bhbasicInfoStatus = inputInfo.getBeHospitalizedDoc().getStructureMap().get("婚姻状况");
+        if (StringUtil.isBlank(bhbasicInfoStatus)) {
+            bhbasicInfoStatus = inputInfo.getBeHospitalizedDoc().getStructureMap().get("婚姻");
+        }
+        if (StringUtil.isBlank(basicInfoStatus) || StringUtil.isBlank(bhbasicInfoStatus)) {
+            return;
+        }
+        if (basicInfoStatus.contains(bhbasicInfoStatus)) {
+            return;
+        }
+        if (bhbasicInfoStatus.equals("未婚") && basicInfoStatus.contains("结婚")) {
+            status.set("-1");
+            return;
+        }
+
+        if (bhbasicInfoStatus.equals("未婚") && basicInfoStatus.contains("未婚")) {
+            return;
+        }
+
+        if (StringUtil.isNotBlank(bhbasicInfoStatus) && basicInfoStatus.equals("其他")) {
+            return;
+        }
+
+        if (bhbasicInfoStatus.equals("丧偶") &&
+                (basicInfoStatus.contains("已故") || basicInfoStatus.contains("丧偶") || basicInfoStatus.contains("亡故") || basicInfoStatus.contains("已逝"))) {
+            return;
+        }
+
+        if ((bhbasicInfoStatus.equals("离婚") || bhbasicInfoStatus.equals("离异")) &&
+                (basicInfoStatus.contains("离异") || bhbasicInfoStatus.equals("离婚"))) {
+            return;
+        }
+
+        if (bhbasicInfoStatus.equals("已婚") && (basicInfoStatus.contains("结婚") || basicInfoStatus.contains("再婚"))) {
+            return;
+        }
+
+        MaritalStatus mts = inputInfo.getBeHospitalizedDoc().getMaritalLabel().getMaritalStatus();
+        if (mts != null && StringUtil.isNotBlank(mts.getName())) {
+            String maritalStatus = mts.getName();
+            if (basicInfoStatus.equals(maritalStatus)) {
+                return;
+            }
+        }
+
+        //无婚育史
+        MaritalLabel maritalLabel = inputInfo.getBeHospitalizedDoc().getMaritalLabel();
+        if (maritalLabel == null || maritalLabel.getText() == null) {
+            return;
+        }
+    }
+
+}

+ 96 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0378.java

@@ -0,0 +1,96 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.behospitalized;
+
+import com.google.common.collect.Lists;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Family;
+import com.lantone.qc.pub.model.label.FamilyLabel;
+import com.lantone.qc.pub.model.label.MaritalLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @Description: 配偶死亡原因未描述
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0378 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            return;
+        }
+        FamilyLabel familyLabel = inputInfo.getBeHospitalizedDoc().getFamilyLabel();
+        MaritalLabel maritalLabel = inputInfo.getBeHospitalizedDoc().getMaritalLabel();
+
+        if (familyLabel == null || maritalLabel == null ||
+                StringUtil.isBlank(familyLabel.getText()) || StringUtil.isBlank(maritalLabel.getText())) {
+            return;
+        }
+        List<Family> familiesFl = null;
+        List<Family> familiesMl = null;
+
+        if (familyLabel != null) {
+            familiesFl = familyLabel.getFamilies();
+            //规则匹配
+            String familyText = familyLabel.getText();
+            if (StringUtil.isNotBlank(familyText) && familyText.contains("自然死亡")) {
+                status.set("0");
+                return;
+            }
+        }
+        if (maritalLabel != null) {
+            familiesMl = maritalLabel.getFamily();
+            for (Family family : familiesMl) {
+                if (family.getDead() != null && family.getName() != null) {
+                    String maritalText = maritalLabel.getText();
+                    int index1 = maritalText.indexOf(family.getDead().getName());
+                    int index2 = maritalText.indexOf(family.getName());
+                    if (0 < index1 && index1 < index2 && maritalText.substring(index1, index2).contains(",")) {
+                        family.setDead(null);
+                    }
+                }
+            }
+        }
+        List<Family> familyList = Lists.newArrayList();
+
+        if (familiesFl != null && familiesFl.size() > 0) {
+            familyList.addAll(familiesFl);
+        }
+        if (familiesMl != null && familiesMl.size() > 0) {
+            familyList.addAll(familiesMl);
+        }
+
+        familyList = familyList
+                .stream()
+                .filter(
+                        i -> i != null
+                                && StringUtil.isNotBlank(i.getName())
+                                && i.getName().contains("配偶")
+                                && i.getDead() != null
+                                && StringUtil.isNotBlank(i.getDead().getName())
+                )
+                .collect(Collectors.toList());
+
+        if (familyList.size() > 0) {
+            status.set("-1");
+            long count = familyList
+                    .stream()
+                    .filter(
+                            i -> (i.getDead().getDeadReason() != null && StringUtil.isNotBlank(i.getDead().getDeadReason().getName()))
+                                    || (i.getDead().getUnknow() != null && StringUtil.isNotBlank(i.getDead().getUnknow().getName()))
+                    )
+                    .count();
+            if (count > 0) {
+                status.set("0");
+            }
+        }
+    }
+}

+ 34 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0411.java

@@ -0,0 +1,34 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+
+/**
+ * @ClassName : BEH0411
+ * @Description :  入院记录记录日期未填写
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class BEH0411 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            return;
+        }
+        Map<String, String> structureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+        if(structureMap != null){
+            String name = structureMap.get("记录日期");
+            if(CatalogueUtil.isEmpty(name)){
+                status.set("-1");
+            }
+        }
+
+    }
+}

+ 75 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0414.java

@@ -0,0 +1,75 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.Content;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+
+/**
+ * @ClassName : BEH0414
+ * @Description :  入院记录年龄填写错误
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class BEH0414 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null
+                && inputInfo.getBeHospitalizedDoc() != null && inputInfo.getBeHospitalizedDoc().getStructureMap() != null) {
+            Map<String, String> firstpageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+            Map<String, String> beHospitalStructureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+            String firstAdmissionAge = firstpageStructureMap.get(Content.age);
+            /* 根据病案首页新生儿出生月数和新生儿出生天数拼接年龄 */
+            String newbornAgeMonths = firstpageStructureMap.get(Content.newbornAgeMonths);
+            String newbornAgeDays = firstpageStructureMap.get(Content.newbornAgeDays);
+            String newbornAgeStr = "";
+            int newbornAge = 0;
+            if (StringUtil.isNotBlank(newbornAgeMonths) && StringUtil.isNotBlank(newbornAgeDays)) {
+                newbornAgeStr = newbornAgeMonths + newbornAgeDays;
+            }
+            if (StringUtil.isNotBlank(newbornAgeStr)) {
+                newbornAge = removalUnit(newbornAgeStr);
+            }
+            String admissionAge = beHospitalStructureMap.get(Content.age);
+            if (StringUtil.isBlank(firstAdmissionAge) || StringUtil.isBlank(admissionAge)) {
+                status.set("0");
+                return;
+            }
+            if (StringUtil.isNotBlank(admissionAge) && admissionAge.contains("岁")) {
+                admissionAge = admissionAge.substring(0, admissionAge.indexOf("岁"));
+            }
+            if (StringUtil.isNotBlank(firstAdmissionAge) && firstAdmissionAge.contains("岁")) {
+                firstAdmissionAge = firstAdmissionAge.substring(0, firstAdmissionAge.indexOf("岁"));
+            }
+            // int firstAdmissionAgeNum = removalUnit(firstAdmissionAge);
+            // int admissionAgeNum = removalUnit(admissionAge);
+            // 只比较年龄前的数值
+            if (!admissionAge.equals(firstAdmissionAge)) {
+                status.set("-1");
+                return;
+            }
+            // if (firstAdmissionAgeNum != admissionAgeNum && newbornAge != admissionAgeNum) {
+            //     status.set("-1");
+            // }
+        }
+    }
+
+    private int removalUnit(String admissionAge) {
+        int age = 0;
+        if (StringUtil.isNotBlank(admissionAge) && admissionAge.contains("岁")) {
+            admissionAge = admissionAge.replaceAll("[岁天]", "");
+        }
+        admissionAge = admissionAge.replaceAll("[^0-9]", "");
+        if (CatalogueUtil.numbersOnly(admissionAge)) {
+            age = Integer.parseInt(admissionAge);
+        }
+        return age;
+    }
+}

+ 79 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0441.java

@@ -0,0 +1,79 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.behospitalized;
+
+import com.google.common.collect.Lists;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.General;
+import com.lantone.qc.pub.model.entity.GeneralDesc;
+import com.lantone.qc.pub.model.label.PresentLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+
+/**
+ * @ClassName : BEH0441
+ * @Description :  现病史缺少发病以来食欲描述
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class BEH0441 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        PresentLabel presentLabel = inputInfo.getBeHospitalizedDoc().getPresentLabel();
+        if (presentLabel == null) {
+            status.set("0");
+            return;
+        }
+        List<String> words = Lists.newArrayList("胃纳", "食纳", "食欲", "未纳", "纳眠", "饮食", "睡眠"
+                , "禁食", "未食", "鼻饲", "饮", "未进食");
+        String presentText = presentLabel.getText();
+        if (StringUtil.isNotBlank(presentText)) {
+            for (String word : words) {
+                if (presentText.contains(word)) {
+                    status.set("0");
+                    return;
+                }
+            }
+        } else {
+            status.set("0");
+            return;
+        }
+        List<GeneralDesc> generals = presentLabel.getGenerals();
+        List<General> gens = presentLabel.getGens();
+
+        if (ListUtil.isEmpty(generals) && ListUtil.isEmpty(gens)) {
+            status.set("0");
+            return;
+        }
+
+        if (ListUtil.isNotEmpty(generals)) {
+            for (GeneralDesc general : generals) {
+                for (String word : words) {
+                    if (general.getName().contains(word)) {
+                        status.set("0");
+                        return;
+                    }
+                }
+            }
+        }
+
+        if (ListUtil.isNotEmpty(gens)) {
+            for (General general : gens) {
+                for (String word : words) {
+                    if (general.getName().contains(word)) {
+                        status.set("0");
+                        return;
+                    }
+                }
+            }
+        }
+    }
+}

+ 74 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0442.java

@@ -0,0 +1,74 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.behospitalized;
+
+import com.google.common.collect.Lists;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.General;
+import com.lantone.qc.pub.model.entity.GeneralDesc;
+import com.lantone.qc.pub.model.label.PresentLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+
+/**
+ * @ClassName : BEH0442
+ * @Description :  现病史缺少发病以来二便描述
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class BEH0442 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        PresentLabel presentLabel = inputInfo.getBeHospitalizedDoc().getPresentLabel();
+        if (presentLabel == null) {
+            status.set("0");
+            return;
+        }
+        String presentText = presentLabel.getText();
+        if (StringUtil.isNotBlank(presentText)) {
+            presentText = presentText.replaceAll("糖尿病|尿片", "");
+            List<String> words = Lists.newArrayList("二便", "大小便", "小便", "大便", "尿", "便秘", "腹泻");
+            for (String word : words) {
+                if (presentText.contains(word)) {
+                    status.set("0");
+                    return;
+                }
+            }
+        } else {
+            status.set("0");
+            return;
+        }
+
+        List<GeneralDesc> generals = presentLabel.getGenerals();
+        List<General> gens = presentLabel.getGens();
+        if (ListUtil.isEmpty(generals) && ListUtil.isEmpty(gens)) {
+            status.set("0");
+            return;
+        }
+
+        if (ListUtil.isNotEmpty(generals)) {
+            for (GeneralDesc general : generals) {
+                if (general.getName().contains("便") || general.getName().contains("尿")) {
+                    status.set("0");
+                    break;
+                }
+            }
+        }
+        if (ListUtil.isNotEmpty(gens)) {
+            for (General general : gens) {
+                if (general.getName().contains("便") || general.getName().contains("尿")) {
+                    status.set("0");
+                    break;
+                }
+            }
+        }
+    }
+}

+ 69 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0443.java

@@ -0,0 +1,69 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+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.entity.General;
+import com.lantone.qc.pub.model.entity.GeneralDesc;
+import com.lantone.qc.pub.model.label.PresentLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+
+/**
+ * @ClassName : BEH0443
+ * @Description :  现病史缺少发病以来体重描述
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class BEH0443 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        BeHospitalizedDoc beHospitalizedDoc = inputInfo.getBeHospitalizedDoc();
+        if (beHospitalizedDoc == null) {
+            status.set("0");
+            return;
+        }
+        PresentLabel presentLabel = beHospitalizedDoc.getPresentLabel();
+        if (presentLabel == null || StringUtil.isBlank(presentLabel.getText())) {
+            status.set("0");
+            return;
+        }
+        if (presentLabel != null) {
+            String presentLabelText = presentLabel.getText();
+            if (StringUtil.isNotBlank(presentLabelText) && (presentLabelText.contains("体重") || presentLabelText.contains("体型"))) {
+                status.set("0");
+                return;
+            }
+            List<GeneralDesc> generals = presentLabel.getGenerals();
+            List<General> gens = presentLabel.getGens();
+
+            if (ListUtil.isEmpty(generals) && ListUtil.isEmpty(gens)) {
+                status.set("0");
+                return;
+            }
+
+            if (ListUtil.isNotEmpty(generals)) {
+                for (GeneralDesc general : generals) {
+                    if (general.getName().contains("体重")) {
+                        status.set("0");
+                        break;
+                    }
+                }
+            }
+
+            if (ListUtil.isNotEmpty(gens)) {
+                for (General general : gens) {
+                    if (general.getName().contains("体重")) {
+                        status.set("0");
+                        break;
+                    }
+                }
+            }
+        }
+    }
+}

+ 77 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0444.java

@@ -0,0 +1,77 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.behospitalized;
+
+import com.google.common.collect.Lists;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+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.entity.General;
+import com.lantone.qc.pub.model.entity.GeneralDesc;
+import com.lantone.qc.pub.model.label.PresentLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+
+/**
+ * @ClassName : BEH0444
+ * @Description :  现病史缺少发病以来精神状态描述
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class BEH0444 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        BeHospitalizedDoc beHospitalizedDoc = inputInfo.getBeHospitalizedDoc();
+        if (beHospitalizedDoc == null) {
+            status.set("0");
+            return;
+        }
+        PresentLabel presentLabel = beHospitalizedDoc.getPresentLabel();
+        if (presentLabel == null || StringUtil.isBlank(presentLabel.getText())) {
+            status.set("0");
+            return;
+        }
+        if (presentLabel != null) {
+            List<String> words = Lists.newArrayList("神志", "神清", "神不清", "意识清", "意识不清", "昏迷", "精神", "意识");
+            String presentLabelText = presentLabel.getText();
+            if (StringUtil.isNotBlank(presentLabelText)) {
+                for (String word : words) {
+                    if (presentLabelText.contains(word)) {
+                        status.set("0");
+                        return;
+                    }
+                }
+            }
+            List<GeneralDesc> generals = presentLabel.getGenerals();
+            List<General> gens = presentLabel.getGens();
+            if (ListUtil.isEmpty(generals) && ListUtil.isEmpty(gens)) {
+                status.set("0");
+                return;
+            }
+            if (ListUtil.isNotEmpty(generals)) {
+                for (GeneralDesc general : generals) {
+                    for (String word : words) {
+                        if (general.getName().contains(word)) {
+                            status.set("0");
+                            return;
+                        }
+                    }
+                }
+            }
+
+            if (ListUtil.isNotEmpty(gens)) {
+                for (General general : gens) {
+                    for (String word : words) {
+                        if (general.getName().contains(word)) {
+                            status.set("0");
+                            return;
+                        }
+                    }
+                }
+            }
+        }
+    }
+}

+ 74 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0445.java

@@ -0,0 +1,74 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.behospitalized;
+
+import com.google.common.collect.Lists;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+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.entity.General;
+import com.lantone.qc.pub.model.entity.GeneralDesc;
+import com.lantone.qc.pub.model.label.PresentLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+
+/**
+ * @ClassName : BEH0445
+ * @Description :  现病史缺少发病以来睡眠描述
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class BEH0445 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        BeHospitalizedDoc beHospitalizedDoc = inputInfo.getBeHospitalizedDoc();
+        if (beHospitalizedDoc == null) {
+            status.set("0");
+            return;
+        }
+        PresentLabel presentLabel = beHospitalizedDoc.getPresentLabel();
+        if (presentLabel == null) {
+            status.set("0");
+            return;
+        }
+        String presentText = presentLabel.getText();
+        if (StringUtil.isNotBlank(presentText)) {
+            List<String> words = Lists.newArrayList("睡眠", "未眠", "未睡", "未入眠", "入睡", "纳眠", "夜眠", "镇静");
+            for (String word : words) {
+                if (presentText.contains(word)) {
+                    status.set("0");
+                    return;
+                }
+            }
+        } else {
+            status.set("0");
+            return;
+        }
+        List<GeneralDesc> generals = presentLabel.getGenerals();
+        List<General> gens = presentLabel.getGens();
+        if (ListUtil.isEmpty(generals) && ListUtil.isEmpty(gens)) {
+            status.set("0");
+            return;
+        }
+        if (ListUtil.isNotEmpty(generals)) {
+            for (GeneralDesc general : generals) {
+                if (general.getName().contains("睡眠") || general.getName().contains("纳眠") || general.getName().contains("入睡")) {
+                    status.set("0");
+                    break;
+                }
+            }
+        }
+
+        if (ListUtil.isNotEmpty(gens)) {
+            for (General general : gens) {
+                if (general.getName().contains("睡眠") || general.getName().contains("纳眠") || general.getName().contains("入睡")) {
+                    status.set("0");
+                    break;
+                }
+            }
+        }
+    }
+}

+ 45 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/behospitalized/BEH0446.java

@@ -0,0 +1,45 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Clinical;
+import com.lantone.qc.pub.model.entity.Degree;
+import com.lantone.qc.pub.model.entity.Modification;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+
+/**
+ * @ClassName : BEH0446
+ * @Description :  现病史症状缺少演变情况
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class BEH0446 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        if (inputInfo.getBeHospitalizedDoc().getPresentLabel() == null ||
+                StringUtil.isBlank(inputInfo.getBeHospitalizedDoc().getPresentLabel().getText())) {
+            status.set("0");
+            return;
+        }
+        List<Clinical> clinicals = inputInfo.getBeHospitalizedDoc().getPresentLabel().getClinicals();
+        if (clinicals.size() > 0) {
+            Clinical clinical = clinicals.get(0);
+            Degree degree = clinical.getDegree();
+            Modification modification = clinical.getModification();
+            if (degree == null && modification == null) {
+                info.set(clinical.getName());
+            } else {
+                status.set("0");
+            }
+        }
+    }
+}

+ 62 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/clinicalblood/CLI0305.java

@@ -0,0 +1,62 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.clinicalblood;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.ClinicalBloodDoc;
+import com.lantone.qc.pub.util.DateUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : CLI0305
+ * @Description : 输血记录未在输注结束后24小时内完成
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class CLI0305 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        Boolean flag = false;
+        List<ClinicalBloodDoc> clinicalBloodDocs = inputInfo.getClinicalBloodDocs();
+        if (clinicalBloodDocs != null && clinicalBloodDocs.size() > 0) {
+            for (ClinicalBloodDoc cliB : clinicalBloodDocs) {
+                Map<String, String> cliBStructureMap = cliB.getStructureMap();
+                String infusionEnd = cliBStructureMap.get("输注结束");
+                String recordDateStr = cliBStructureMap.get("病历日期");
+                if(StringUtil.isNotEmpty(infusionEnd)){
+                    if (!CatalogueUtil.compareTime(
+                            StringUtil.parseDateTime(infusionEnd),
+                            StringUtil.parseDateTime(DateUtil.nowString()),
+                            Long.valueOf(24 * 60))) {//如果输注结束未超过24小时,规则不判断
+                        status.set("0");
+                        return;
+                    }
+                }
+                if (StringUtils.isNotEmpty(infusionEnd) && StringUtils.isNotEmpty(recordDateStr)) {
+                    Date infusionEndDate = StringUtil.parseDateTime(infusionEnd);
+                    Date recordDate = StringUtil.parseDateTime(recordDateStr);
+                    if (infusionEndDate != null && recordDate != null) {
+                        if (infusionEndDate.after(recordDate)) {
+                            continue;
+                        }
+                        if (CatalogueUtil.compareTime(infusionEndDate, recordDate, 24 * 60L)) {
+                            flag = true;
+                            info.set(infusionEnd + " -> " + recordDateStr);
+                        }
+                    }
+                }
+            }
+        }
+        if(flag){
+            status.set("-1");
+        }
+    }
+}

+ 97 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/clinicalblood/CLI03063.java

@@ -0,0 +1,97 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.clinicalblood;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.ClinicBloodEffectDoc;
+import com.lantone.qc.pub.model.doc.ClinicalBloodDoc;
+import com.lantone.qc.pub.util.DateUtil;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * @ClassName : CLI0309
+ * @Description : 输血后效果评价未在24小时完成
+ * @Author : 王宇
+ * @Date: 2020-08-14 10:18
+ */
+@Component
+public class CLI03063 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        List<ClinicalBloodDoc> clinicalBloodDocs = inputInfo.getClinicalBloodDocs();//输血记录
+        List<ClinicBloodEffectDoc> clinicBloodEffectDocs = inputInfo.getClinicBloodEffectDocs();//输血效果评价
+        if (ListUtil.isEmpty(clinicalBloodDocs)) {
+            return;
+        }
+        Iterator<ClinicalBloodDoc> clinicalBloodDocIterator = clinicalBloodDocs.iterator();
+        Iterator<ClinicBloodEffectDoc> clinicBloodEffectDocIterator = clinicBloodEffectDocs.iterator();
+        while (clinicalBloodDocIterator.hasNext()) {
+            if (!CatalogueUtil.compareTime(
+                    StringUtil.parseDateTime(clinicalBloodDocIterator.next().getStructureMap().get("病历日期")),
+                    StringUtil.parseDateTime(DateUtil.nowString()),
+                    Long.valueOf(24 * 60))) {//如果接收未超过24小时,规则不判断
+                clinicalBloodDocIterator.remove();
+            }
+        }
+        while (clinicBloodEffectDocIterator.hasNext()) {
+            if (!CatalogueUtil.compareTime(
+                    StringUtil.parseDateTime(clinicBloodEffectDocIterator.next().getStructureMap().get("病历日期")),
+                    StringUtil.parseDateTime(DateUtil.nowString()),
+                    Long.valueOf(24 * 60))) {//如果接收未超过24小时,规则不判断
+                clinicBloodEffectDocIterator.remove();
+            }
+        }
+        Collections.sort(clinicalBloodDocs, new Comparator<ClinicalBloodDoc>() {
+            public int compare(ClinicalBloodDoc o1, ClinicalBloodDoc o2) {
+                return o1.getStructureMap().get("病历日期")
+                        .compareTo(o2.getStructureMap().get("病历日期"));
+            }
+        });
+        Collections.sort(clinicBloodEffectDocs, new Comparator<ClinicBloodEffectDoc>() {
+            public int compare(ClinicBloodEffectDoc o1, ClinicBloodEffectDoc o2) {
+                return o1.getStructureMap().get("病历日期")
+                        .compareTo(o2.getStructureMap().get("病历日期"));
+            }
+        });
+        if (clinicalBloodDocs.size() != clinicBloodEffectDocs.size()) {
+            status.set("-1");
+            return;
+        }
+        for (ClinicalBloodDoc clinicalBloodDoc : clinicalBloodDocs) {
+            for (ClinicBloodEffectDoc clinicBloodEffectDoc : clinicBloodEffectDocs) {
+                if (CatalogueUtil.compareTime(
+                        StringUtil.parseDateTime(clinicalBloodDoc.getStructureMap().get("病历日期")),
+                        StringUtil.parseDateTime(clinicBloodEffectDoc.getStructureMap().get("病历日期")),
+                        Long.valueOf(1))) {//结果单时间要比申请单大的
+                    if (CatalogueUtil.compareTime(
+                            StringUtil.parseDateTime(clinicalBloodDoc.getStructureMap().get("病历日期")),
+                            StringUtil.parseDateTime(clinicBloodEffectDoc.getStructureMap().get("病历日期")),
+                            Long.valueOf(24 * 60))) {//未超过24小时
+                        status.set("-1");
+                        return ;
+                    }
+                }
+            }
+        }
+        /*
+        if (clinicalBloodDocs != null && clinicalBloodDocs.size() > 0) {
+            for (ClinicBloodEffectDoc cliB : clinicBloodEffectDocs) {
+                Map<String, String> cliBStructureMap = cliB.getStructureMap();
+                if (StringUtils.isEmpty(cliBStructureMap.get("输注后效果评价"))) {
+                    status.set("-1");
+                    break;
+                }
+            }
+        }
+
+         */
+    }
+}

+ 61 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/clinicalblood/CLI0309.java

@@ -0,0 +1,61 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.clinicalblood;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.ClinicBloodEffectDoc;
+import com.lantone.qc.pub.model.doc.ClinicalBloodDoc;
+import com.lantone.qc.pub.util.DateUtil;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : CLI0309
+ * @Description : 无输血或使用血液制品后效果评价
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class CLI0309 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        List<ClinicalBloodDoc> clinicalBloodDocs = inputInfo.getClinicalBloodDocs();//输血记录
+        List<ClinicBloodEffectDoc> clinicBloodEffectDocs = inputInfo.getClinicBloodEffectDocs();//输血效果评价
+        if (ListUtil.isEmpty(clinicalBloodDocs)) {
+            return;
+        }
+        List<Date> clinicalBloodDate = new ArrayList<>();
+        for (ClinicalBloodDoc clinicalBloodDoc : clinicalBloodDocs) {
+            Map<String, String> structureMap = clinicalBloodDoc.getStructureMap();
+            if (StringUtil.isNotBlank(structureMap.get("病历日期"))) {
+                Date date = DateUtil.dateZeroClear(StringUtil.parseDateTime(structureMap.get("病历日期")));
+                if (!clinicalBloodDate.contains(date)) {
+                    clinicalBloodDate.add(date);
+                }
+            }
+        }
+
+        if (clinicalBloodDate.size() > clinicBloodEffectDocs.size()) {
+            status.set("-1");
+            info.set("部分输血记录未找到对应输血后效果评价");
+        }
+        /*
+        if (clinicalBloodDocs != null && clinicalBloodDocs.size() > 0) {
+            for (ClinicBloodEffectDoc cliB : clinicBloodEffectDocs) {
+                Map<String, String> cliBStructureMap = cliB.getStructureMap();
+                if (StringUtils.isEmpty(cliBStructureMap.get("输注后效果评价"))) {
+                    status.set("-1");
+                    break;
+                }
+            }
+        }
+
+         */
+    }
+}

+ 41 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/clinicalblood/CLI0568.java

@@ -0,0 +1,41 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.clinicalblood;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.ClinicalBloodDoc;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : CLI0568
+ * @Description :  输血记录输血记录时间未填写
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class CLI0568 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        List<ClinicalBloodDoc> clinicalBloodDocs = inputInfo.getClinicalBloodDocs();
+        if(clinicalBloodDocs != null && clinicalBloodDocs.size()>0){
+            for (ClinicalBloodDoc cliB:clinicalBloodDocs) {
+                Map<String, String> cliBStructureMap = cliB.getStructureMap();
+                if(cliBStructureMap.containsKey("病历日期")){
+                    if(StringUtils.isEmpty(cliBStructureMap.get("病历日期"))){
+                        status.set("-1");
+                        break;
+                    }
+                }else {
+                    status.set("-1");
+                    break;
+                }
+
+            }
+        }
+
+    }
+}

+ 56 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/consultation/CON0382.java

@@ -0,0 +1,56 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.consultation;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.CrisisValueReportDoc;
+import com.lantone.qc.pub.util.DateUtil;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @Description: 化验结果为危急值的,6小时内危急值记录中没有体现危急值记录
+ * 在没有化验报告单之前,以记录时间和接收时间的比较为准
+ * @author: Mark
+ * @time: 2020/6/19 13:34
+ */
+@Component
+public class CON0382 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        List<CrisisValueReportDoc> crisisValueReportDocs = inputInfo.getCrisisValueReportDocs();
+        if (ListUtil.isNotEmpty(crisisValueReportDocs)) {
+            crisisValueReportDocs.forEach(crisisValueReportDoc -> {
+                if (StringUtil.isBlank(crisisValueReportDoc.getStructureMap().get("危急值记录内容"))) {
+                    String record_time = crisisValueReportDoc.getStructureMap().get("病历日期");
+                    String receive_time = crisisValueReportDoc.getStructureMap().get("接收时间");
+                    if (!CatalogueUtil.compareTime(
+                            StringUtil.parseDateTime(receive_time),
+                            StringUtil.parseDateTime(DateUtil.nowString()),
+                            Long.valueOf(6 * 60))) {//如果接收未超过6小时,规则不判断
+                        return;
+                    }
+                    String crisisVal =null;
+                    if(crisisValueReportDoc.getStructureMap().get("危急值记录内容") != null){
+                        crisisVal = crisisValueReportDoc.getStructureMap().get("危急值记录内容").trim();
+                    }
+                    if(record_time != null && receive_time != null && crisisVal != null){
+                        Date record = StringUtil.parseDateTime(record_time);
+                        Date receive = StringUtil.parseDateTime(receive_time);
+                        if (crisisVal.length()==0 || CatalogueUtil.compareTime(receive, record, 6*60L) ) {
+                            status.set("-1");
+                        }
+                    }
+                }
+            });
+        }
+    }
+
+}

+ 111 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/crisisvaluereport/CRI0382.java

@@ -0,0 +1,111 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.crisisvaluereport;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.CrisisInfoDoc;
+import com.lantone.qc.pub.model.doc.CrisisValueReportDoc;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @Description: 接到危急值报告后6小时内无病程记录
+ * @author: rengb
+ * @time: 2020/3/19 19:54
+ */
+@Component
+public class CRI0382 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        //无危急值结构化信息
+        List<CrisisInfoDoc> crisisInfoDocs = inputInfo.getCrisisInfoDocs();
+        if (crisisInfoDocs == null || crisisInfoDocs.size() == 0) {
+            return;
+        }
+        //有结构化信息但无危急值文书,如果报告时间都未超过6小时 允许无文书
+        boolean isOutTime = false;
+        Date currentDate = new Date();
+        int timeCha = 21600000;
+        String[] dateFormats = new String[]{"yyyy年MM月dd日HH时mm分", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm"};
+        for (CrisisInfoDoc crisisInfoDoc : crisisInfoDocs) {
+            String reptTime = crisisInfoDoc.getStructureMap().get("报告时间");
+            if (StringUtils.isNotEmpty(reptTime)) {
+                if (currentDate.getTime() - StringUtil.parseDateTime(reptTime, dateFormats).getTime() > timeCha) {
+                    isOutTime = true;
+                }
+            }
+        }
+        ;
+        if (isOutTime == false) {   //所有文书都未超过6小时,规则直接通过
+            return;
+        }
+
+        List<CrisisValueReportDoc> crisisValueReportDocs = inputInfo.getCrisisValueReportDocs();
+        //如果有危急值结构化数据 但无文书则直接提醒无危急值报告
+        if (crisisValueReportDocs == null || crisisValueReportDocs.size() == 0) {
+            status.set("-1");
+            return;
+        }
+        List<String> findCrisises = new ArrayList<>();
+        List<String> allCrisises = new ArrayList<>();
+        crisisInfoDocs.forEach(crisisInfoDoc -> {
+            String reptTime = crisisInfoDoc.getStructureMap().get("报告时间");
+            String crisisName = crisisInfoDoc.getStructureMap().get("危急结果值");
+            String crisisNm = "";
+            String companyNum = "";
+            if (crisisName.contains("项目为")) {
+                crisisName = crisisName.substring(crisisName.indexOf("项目为") + 3);
+            }
+            if (crisisName.contains(",结果:")) {
+                crisisNm = crisisName.split(",结果:")[0];
+                companyNum = crisisName.split(",结果:")[1];
+                if (StringUtil.isNotBlank(companyNum) && companyNum.contains("单位:")) {
+                    companyNum = companyNum.replaceAll("单位:", "");
+                }
+            }
+            allCrisises.add(reptTime);
+            if (StringUtils.isNotEmpty(reptTime)) {
+                //当前时间和报告时间未超过6小时,规则通过
+                if (currentDate.getTime() - StringUtil.parseDateTime(reptTime, dateFormats).getTime() < timeCha) {
+                    findCrisises.add(reptTime);
+                } else {
+                    for (CrisisValueReportDoc crisisValueReportDoc : crisisValueReportDocs) {
+                        String recordTimeStr = crisisValueReportDoc.getStructureMap().get("病历日期");
+                        String docReptContent = crisisValueReportDoc.getStructureMap().get("病情分析及处理");
+                        if ((StringUtil.parseDateTime(recordTimeStr, dateFormats).getTime() - StringUtil.parseDateTime(reptTime, dateFormats).getTime()) < timeCha
+                                && (StringUtil.removeBlank(docReptContent).contains(StringUtil.removeBlank(crisisName)) ||
+                                (StringUtil.isNotBlank(crisisNm) && StringUtil.isNotBlank(companyNum)
+                                        && StringUtil.removeBlank(docReptContent).contains(StringUtil.removeBlank(crisisNm))
+                                        && StringUtil.removeBlank(docReptContent).contains(StringUtil.removeBlank(companyNum))
+                                ))) {
+                            findCrisises.add(reptTime);
+                            break;
+                        }
+                    }
+                }
+            }
+        });
+        // (StringUtil.parseDateTime(recordTimeStr, dateFormats).getTime() - StringUtil.parseDateTime(reptTime, dateFormats).getTime()) > 0
+        //                                &&
+        if (findCrisises.size() != allCrisises.size()) {
+            status.set("-1");
+            allCrisises.forEach(reptTime -> {
+                if (!findCrisises.contains(reptTime) && !info.get().contains(reptTime)) {
+                    if (StringUtils.isEmpty(info.get())) {
+                        info.set(reptTime);
+                    } else {
+                        info.set(info.get() + ", " + reptTime);
+                    }
+                }
+            });
+        }
+    }
+
+}

+ 37 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/deathcasediscuss/DEAC0098.java

@@ -0,0 +1,37 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.deathcasediscuss;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * @ClassName : DEAC0098
+ * @Description : 死亡记录未在患者死亡后24小时内完成
+ * @Author : 胡敬
+ * @Date: 2020-03-19 11:08
+ */
+@Component
+public class DEAC0098 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getDeathRecordDoc() != null && inputInfo.getDeathRecordDoc().getStructureMap() != null) {
+            Map<String, String> deathRecordStructureMap = inputInfo.getDeathRecordDoc().getStructureMap();
+            String deceaseTime = deathRecordStructureMap.get("死亡时间");
+            String recordTime = deathRecordStructureMap.get("病历日期");
+            if (CatalogueUtil.isEmpty(deceaseTime) || CatalogueUtil.isEmpty(recordTime)) {
+                return;
+            }
+            Date deceaseDate = StringUtil.parseDateTime(deceaseTime);
+            Date recordDate = StringUtil.parseDateTime(recordTime);
+            if (deceaseDate.before(recordDate) && CatalogueUtil.compareTime(deceaseDate, recordDate, Long.valueOf(24 * 60))) {
+                status.set("-1");
+            }
+        }
+    }
+}

+ 37 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/deathcasediscuss/DEAC0109.java

@@ -0,0 +1,37 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.deathcasediscuss;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * @ClassName : DEAC0109
+ * @Description : 死亡病例讨论记录未在患者死亡1周内完成
+ * @Author : 胡敬
+ * @Date: 2020-03-19 10:45
+ */
+@Component
+public class DEAC0109 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getDeathCaseDiscussDoc() != null && inputInfo.getDeathCaseDiscussDoc().getStructureMap() != null) {
+            Map<String, String> deathCaseDiscussStructureMap = inputInfo.getDeathCaseDiscussDoc().getStructureMap();
+            String deceaseTime = deathCaseDiscussStructureMap.get("死亡时间");
+            String recordTime = deathCaseDiscussStructureMap.get("病历日期");
+            if (CatalogueUtil.isEmpty(deceaseTime) || CatalogueUtil.isEmpty(recordTime)) {
+                return;
+            }
+            Date deceaseDate = StringUtil.parseDateTime(deceaseTime);
+            Date recordDate = StringUtil.parseDateTime(recordTime);
+            if (deceaseDate.before(recordDate) && CatalogueUtil.compareTime(deceaseDate, recordDate, Long.valueOf(7 * 24 * 60))) {
+                status.set("-1");
+            }
+        }
+    }
+}

+ 33 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/deathrecord/DEAR0337.java

@@ -0,0 +1,33 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.deathrecord;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @ClassName : DEAR0337
+ * @Description : 死亡记录未在患者离院前完成
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class DEAR0337 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getDeathRecordDoc() != null && inputInfo.getDeathRecordDoc().getStructureMap() != null
+                && inputInfo.getLeaveHospitalDoc() != null && inputInfo.getLeaveHospitalDoc().getStructureMap() != null) {
+            Map<String, String> deathRecordStructure = inputInfo.getDeathRecordDoc().getStructureMap();
+            Map<String, String> leaveHospitalStructure = inputInfo.getLeaveHospitalDoc().getStructureMap();
+            String recordTime = deathRecordStructure.get("病历日期");
+            String signTime = leaveHospitalStructure.get("签名时间");
+            //如果死亡记录时间比出院小结签名时间晚
+            if(CatalogueUtil.compareDate(recordTime,signTime,-1)){
+                status.set("-1");
+            }
+        }
+    }
+}

+ 91 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/dutyshiftsystem/DUT0598.java

@@ -0,0 +1,91 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.dutyshiftsystem;
+
+import com.google.common.collect.Lists;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.transferrecord.TransferIntoDoc;
+import com.lantone.qc.pub.model.doc.transferrecord.TransferRecordDoc;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.time.DateUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @ClassName : DUT0598
+ * @Description : 接科记录未在24h内完成
+ * @Author : 胡敬
+ * @Date: 2020-03-30 15:06
+ */
+@Component
+public class DUT0598 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        TransferRecordDoc transferRecordDoc = inputInfo.getTransferRecordDocs();
+        if (transferRecordDoc == null) {
+            return;
+        }
+        List<TransferIntoDoc> transferIntoDocs = transferRecordDoc.getTransferIntoDocs();
+        String rollInRecordDateStr = "", recordDateStr = "", removeDate = "";
+        Date rollOutRecordDate = null, recordDate = null;
+        if (transferIntoDocs == null || transferIntoDocs.get(0).getStructureMap() == null) {
+            return;
+        }
+        //转入时间
+        rollInRecordDateStr = transferIntoDocs.get(0).getStructureMap().get("转入时间");
+        if (StringUtil.isBlank(rollInRecordDateStr)) {
+            return;
+        }
+        String[] split = rollInRecordDateStr.replace("[", "").replace("]", "").trim().split(",");
+//        List<String> dateLists = Arrays.asList(split);
+        List<String> dateLists = Lists.newArrayList();
+        for (String date : split) {
+            dateLists.add(date);
+        }
+        dateLists = dateLists.stream().sorted().collect(Collectors.toList());
+        for (TransferIntoDoc transferIntoDoc : transferIntoDocs) {
+            Map<String, Date> maps = new HashMap<>();
+            Map<String, String> transferOutStructureMap = transferIntoDoc.getStructureMap();
+            recordDateStr = transferOutStructureMap.get("病历日期");
+            for (String date : dateLists) {
+                if (CatalogueUtil.isEmpty(date) || CatalogueUtil.isEmpty(recordDateStr)) {
+                    continue;
+                }
+                //转入日期
+                rollOutRecordDate = StringUtil.parseDateTime(date);
+                //记录日期
+                recordDate = StringUtil.parseDateTime(recordDateStr);
+                if (rollOutRecordDate != null && recordDate != null &&
+                        (rollOutRecordDate.before(recordDate) || DateUtils.isSameDay(rollOutRecordDate, recordDate))) {
+                    if (maps.size() == 0) {
+                        removeDate = date;
+                        maps.put("转入时间", rollOutRecordDate);
+                        maps.put("病历日期", recordDate);
+                    } else {
+                        if (recordDate.getTime() - rollOutRecordDate.getTime() < maps.get("病历日期").getTime() - maps.get("转入时间").getTime()) {
+                            removeDate = date;
+                            maps.put("转入时间", rollOutRecordDate);
+                        }
+                    }
+                }
+            }
+
+            if (maps.size() != 0) {
+                boolean compareTime = CatalogueUtil.compareTime(maps.get("转入时间"), maps.get("病历日期"), (long) 24 * 60);
+                boolean sameDay = DateUtils.isSameDay(maps.get("转入时间"), maps.get("病历日期"));
+                dateLists.remove(removeDate);
+                if (compareTime && !sameDay) {
+                    status.set("-1");
+                    return;
+                }
+            }
+        }
+    }
+
+}

+ 71 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/firstcourserecord/FIRC0082.java

@@ -0,0 +1,71 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.firstcourserecord;
+
+import com.lantone.qc.dbanaly.util.KernelConstants;
+import com.lantone.qc.dbanaly.util.SpecialStorageUtil;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.util.SpringContextUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @ClassName : FIRC0082
+ * @Description : 首次病程由非执业医师书写
+ * @Author : rengb
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class FIRC0082 extends QCCatalogue {
+    @Autowired
+    private SpecialStorageUtil specialStorageUtil;
+
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getFirstCourseRecordDoc() == null) {
+            status.set("0");
+            return;
+        }
+
+        String doctorName = inputInfo.getFirstCourseRecordDoc().getStructureMap().get("记录医生");
+        if (StringUtil.isBlank(doctorName)) {
+            status.set("0");
+            return;
+        }
+
+        String occup = getOccup(doctorName);
+        if (StringUtils.isNotEmpty(occup) && "1".equals(occup)) {
+            status.set("0");
+            return;
+        }
+
+        if (doctorName.length() > 1) {
+            doctorName = doctorName.substring(0, doctorName.length() - 1);
+            occup = getOccup(doctorName);
+            if (StringUtils.isNotEmpty(occup) && "1".equals(occup)) {
+                status.set("0");
+                return;
+            }
+        }
+    }
+
+    private String getOccup(String doctorName) {
+        String occup = "";
+        if (StringUtil.isBlank(doctorName)) {
+            return occup;
+        }
+        SpecialStorageUtil specialStorageUtil = SpringContextUtil.getBean("specialStorageUtil");
+        Map<String, Map<String, String>> surgeon = specialStorageUtil.getJsonStringValue(KernelConstants.HOSPITAL_DOCTOR_MAP);
+        if (surgeon != null) {
+            Map<String, String> doctor = (Map) surgeon.get(doctorName);
+            if (doctor != null) {
+                occup = doctor.get("occup");
+            }
+        }
+        return occup;
+    }
+
+}

+ 67 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/firstcourserecord/FIRC0092.java

@@ -0,0 +1,67 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.firstcourserecord;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.FirstCourseRecordDoc;
+import com.lantone.qc.pub.model.label.TreatPlanLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @ClassName : FIRC0092
+ * @Description : 治疗措施不具体
+ * @Author : 胡敬
+ * @Date: 2020-03-24 15:21
+ */
+@Component
+public class FIRC0092 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        FirstCourseRecordDoc firstCourseRecordDoc = inputInfo.getFirstCourseRecordDoc();
+        if (firstCourseRecordDoc == null) {
+            status.set("0");
+            return;
+        }
+        TreatPlanLabel treatPlanLabel = firstCourseRecordDoc.getTreatPlanLabel();
+        if (treatPlanLabel == null) {
+            return;
+        }
+        String text = treatPlanLabel.getText();
+        boolean findText = false;
+        if (StringUtil.isNotBlank(text) && text.contains("护理")) {
+            findText = true;
+        }
+
+        Map<String, String> structureMap = firstCourseRecordDoc.getStructureMap();
+        String structureV = structureMap.get("诊疗计划");
+        if (StringUtil.isBlank(structureV) && StringUtil.isBlank(text)) {
+            status.set("0");
+            return;
+        }
+        if (StringUtil.isNotBlank(structureV) && structureV.contains("护理")) {
+            findText = true;
+        }
+        if(treatPlanLabel.getNursingLevel() != null){
+            if (findText && !treatPlanLabel.getNursingLevel().getName().equals("护理常规") &&
+                    (treatPlanLabel.getMedicine() != null || treatPlanLabel.getTreat().size() > 0
+                            || treatPlanLabel.getPacs().size() > 0)) {
+                status.set("0");
+                return;
+            }
+        }
+        String message = "";
+        if (treatPlanLabel.getNursingLevel() == null || treatPlanLabel.getNursingLevel().getName().equals("护理常规")) {
+            message += "无护理级别;";
+        }
+
+        if (ListUtil.isEmpty(treatPlanLabel.getPacs())) {
+            message += "无化验或辅检;";
+        }
+        if (StringUtil.isNotBlank(message)) {
+            info.set(message);
+        }
+    }
+}

+ 43 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/firstcourserecord/FIRC02910.java

@@ -0,0 +1,43 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.firstcourserecord;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+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.FirstCourseRecordDoc;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * @ClassName : FIRC02910
+ * @Description : 首次病程创建时间早于患者入院时间
+ * @Author : 胡敬
+ * @Date: 2020-06-12 14:12
+ */
+@Component
+public class FIRC02910 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        FirstCourseRecordDoc firstCourseRecordDoc = inputInfo.getFirstCourseRecordDoc();
+        BeHospitalizedDoc beHospitalizedDoc = inputInfo.getBeHospitalizedDoc();
+        if (firstCourseRecordDoc == null || beHospitalizedDoc == null) {
+            return;
+        }
+        Map<String, String> firstRecordMap = firstCourseRecordDoc.getStructureMap();
+        Map<String, String> beHospitalizedMap = beHospitalizedDoc.getStructureMap();
+        String createDateStr = firstRecordMap.get("病历日期");
+        String beHospitalDateStr = beHospitalizedMap.get("入院日期");
+        if (StringUtil.isNotBlank(createDateStr) && StringUtil.isNotBlank(beHospitalDateStr)) {
+            Date createDate = StringUtil.parseDateTime(createDateStr);
+            Date beHospitalDate = StringUtil.parseDateTime(beHospitalDateStr);
+            if (createDate != null && beHospitalDate != null) {
+                if (createDate.before(beHospitalDate)) {
+                    status.set("-1");
+                }
+            }
+        }
+    }
+}

+ 80 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/firstpagerecord/FIRP0161.java

@@ -0,0 +1,80 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.firstpagerecord;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.kernel.util.RegularUtil;
+import com.lantone.qc.pub.Content;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP0161
+ * @Description : 患者年龄与入院记录不一致
+ * @Author : 胡敬
+ * @Date: 2020-03-16 10:00
+ */
+@Component
+public class FIRP0161 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null
+                && inputInfo.getBeHospitalizedDoc() != null && inputInfo.getBeHospitalizedDoc().getStructureMap() != null) {
+            Map<String, String> firstpageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+            Map<String, String> beHospitalStructureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+            String firstAdmissionAge = firstpageStructureMap.get(Content.age);
+            /* 根据病案首页新生儿出生月数和新生儿出生天数拼接年龄 */
+            String newbornAgeMonths = firstpageStructureMap.get(Content.newbornAgeMonths);
+            String newbornAgeDays = firstpageStructureMap.get(Content.newbornAgeDays);
+            String newbornAgeStr = "";
+            int newbornAge = 0;
+            if (StringUtil.isNotBlank(newbornAgeMonths) && StringUtil.isNotBlank(newbornAgeDays)){
+                newbornAgeStr = newbornAgeMonths + newbornAgeDays;
+            }
+            if (StringUtil.isNotBlank(newbornAgeStr)){
+                newbornAge = removalUnit(newbornAgeStr);
+            }
+            String admissionAge = beHospitalStructureMap.get(Content.age);
+            if (StringUtil.isBlank(firstAdmissionAge) || StringUtil.isBlank(admissionAge)) {
+                status.set("0");
+                return;
+            }
+            if (StringUtil.isNotBlank(admissionAge) && admissionAge.contains("岁")) {
+                admissionAge = admissionAge.substring(0, admissionAge.indexOf("岁"));
+            }
+            if (StringUtil.isNotBlank(firstAdmissionAge) && firstAdmissionAge.contains("岁")) {
+                firstAdmissionAge = firstAdmissionAge.substring(0, firstAdmissionAge.indexOf("岁"));
+            }
+            // int firstAdmissionAgeNum = removalUnit(firstAdmissionAge);
+            // int admissionAgeNum = removalUnit(admissionAge);
+            // 只比较年龄前的数值
+            if (!admissionAge.equals(firstAdmissionAge)) {
+                status.set("-1");
+                return;
+            }
+            // int firstAdmissionAgeNum = removalUnit(firstAdmissionAge);
+            // int admissionAgeNum = removalUnit(admissionAge);
+            //
+            // if (firstAdmissionAgeNum != admissionAgeNum && newbornAge != admissionAgeNum) {
+            //     status.set("-1");
+            // }
+        }
+    }
+
+    private int removalUnit(String admissionAge) {
+        int age = 0;
+        if (StringUtil.isNotBlank(admissionAge) && admissionAge.contains("岁")) {
+            admissionAge = admissionAge.replaceAll("[岁天]", "");
+        }
+        // 解决邵逸夫数据,年龄后跟着身份证号码
+        admissionAge = RegularUtil.ClearBracket(admissionAge);
+        admissionAge = admissionAge.replaceAll("[^0-9]","");
+        if (CatalogueUtil.numbersOnly(admissionAge)) {
+            age = Integer.parseInt(admissionAge);
+        }
+        return age;
+    }
+}

+ 66 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/leavehospital/LEA0148.java

@@ -0,0 +1,66 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.leavehospital;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.LeaveHospitalDoc;
+import com.lantone.qc.pub.util.DateUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * @Description: 出院记录未在患者出院前完成
+ * @author: rengb
+ * @time: 2020/3/10 13:53
+ */
+@Component
+public class LEA0148 extends QCCatalogue {
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        LeaveHospitalDoc leaveHospitalDoc = inputInfo.getLeaveHospitalDoc();
+        if (leaveHospitalDoc == null) {
+            status.set("0");
+            return;
+        }
+        if (inputInfo.getDeathRecordDoc() != null || inputInfo.getDeathCaseDiscussDoc() != null) {
+            status.set("0");
+            return;
+        }
+        String timeCy = null;
+        if (inputInfo.getMedicalRecordInfoDoc() != null) {
+            Map<String, String> medicalRecordInfoStructureMap = inputInfo.getMedicalRecordInfoDoc().getStructureMap();
+            timeCy = medicalRecordInfoStructureMap.get("leaveHospitalDate");
+        }
+        String timeQm = leaveHospitalDoc.getStructureMap().get("病历日期");
+        if (StringUtil.isNotBlank(timeQm) && DateUtil.parseDate(timeQm) != null && StringUtil.isNotBlank(timeCy)) {
+            if (!CatalogueUtil.compareTime(
+                    StringUtil.parseDateTime(timeCy),
+                    StringUtil.parseDateTime(DateUtil.nowString()),
+                    Long.valueOf(24 * 60))) {//如果出院未超过24小时,规则不判断
+                status.set("0");
+                return;
+            }
+            Date timeQmDate = StringUtil.parseDateTime(timeQm);
+            Date timeCyDate = StringUtil.parseDateTime(timeCy);
+            if (!CatalogueUtil.compareTime(timeCyDate, timeQmDate, 24 * 60L)) {
+                status.set("0");
+            }
+        } else {
+            if (StringUtil.isNotEmpty(timeCy)) {
+                if (!CatalogueUtil.compareTime(
+                        StringUtil.parseDateTime(timeCy),
+                        StringUtil.parseDateTime(DateUtil.nowString()),
+                        Long.valueOf(24 * 60))) {//如果出院未超过24小时,规则不判断
+                    status.set("0");
+                    return;
+                }
+            }
+            status.set("0");
+            return;
+        }
+    }
+}

+ 98 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/leavehospital/LEA0149.java

@@ -0,0 +1,98 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.leavehospital;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+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.DeathRecordDoc;
+import com.lantone.qc.pub.model.doc.LeaveHospitalDoc;
+import com.lantone.qc.pub.model.label.ChiefLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @Description: 出院记录内容缺主诉
+ * @author: rengb
+ * @time: 2020/3/10 13:53
+ */
+@Component
+public class LEA0149 extends QCCatalogue {
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        LeaveHospitalDoc leaveHospitalDoc = inputInfo.getLeaveHospitalDoc();
+        BeHospitalizedDoc beHospitalizedDoc = inputInfo.getBeHospitalizedDoc();
+        if (leaveHospitalDoc == null || beHospitalizedDoc == null) {
+            status.set("0");
+            return;
+        }
+        DeathRecordDoc deathRecordDoc = inputInfo.getDeathRecordDoc();
+        if (deathRecordDoc != null) {
+            status.set("0");
+            return;
+        }
+        Map<String, String> lhStructureMap = leaveHospitalDoc.getStructureMap();
+        ChiefLabel chiefLabel = beHospitalizedDoc.getChiefLabel();
+        if (lhStructureMap != null && chiefLabel != null) {
+            String bhChief = CatalogueUtil.int2ChineseNum(chiefLabel.getText().replaceAll("[\\p{Punct}\\pP。-]", ""));
+            String leaveChief = lhStructureMap.get("主诉");
+            String bhThings = lhStructureMap.get("病史摘要");
+            String reThings = lhStructureMap.get("入院原因");   //邵逸夫主诉在入院原因内
+            if (StringUtil.isNotBlank(bhThings)) {
+                bhThings = CatalogueUtil.int2ChineseNum(bhThings.replaceAll("[\\p{Punct}\\pP。-]", ""));
+                if (bhThings.contains("\n")) {
+                    bhThings = bhThings.replace("\n", "");
+                }
+            }
+            if (StringUtil.isNotBlank(reThings)) {
+                reThings = CatalogueUtil.int2ChineseNum(reThings.replaceAll("[\\p{Punct}\\pP。-]", ""));
+                if (reThings.contains("\n")) {
+                    reThings = reThings.replace("\n", "");
+                }
+            }
+
+            //如果出院小结结构化数据能取出主诉,则直接用该主诉和入院记录主诉比较
+            if (StringUtil.isNotBlank(leaveChief)) {
+                leaveChief = CatalogueUtil.int2ChineseNum(leaveChief.replaceAll("[\\p{Punct}\\pP。-]", ""));
+                if (bhChief.equals(leaveChief)) {
+                    status.set("0");
+                    return;
+                }
+            }
+            if (StringUtil.isNotBlank(bhThings) && bhThings.replace(" ", "").contains(bhChief.replace(" ", ""))) {
+                status.set("0");
+                return;
+            }
+            //邵逸夫主诉写在入院原因
+            if (StringUtil.isNotBlank(reThings) && reThings.replace(" ", "").contains(bhChief.replace(" ", ""))) {
+                status.set("0");
+                return;
+            }
+            if (StringUtils.isNotBlank(bhThings)) {
+                Pattern compile = Pattern.compile("(?<=2.).*(?=3.体格检查)");
+                Matcher matcher = compile.matcher(bhThings);
+                while (matcher.find()) {
+                    String number = matcher.group(0);
+                    if (CatalogueUtil.isEmpty(number)) {
+                        status.set("-1");
+                    }
+                }
+                //处理台州的
+                if (bhThings.contains("患者因")) {
+                    status.set("0");
+                }
+            }
+
+
+            //                    bhThings = bhThings.replaceAll("[\\p{Punct}\\pP]", "");
+            //                    if (bhThings.indexOf(bhChief) < 0) {
+            //                        status.set("-1");
+            //                    }
+        }
+    }
+}

+ 86 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/leavehospital/LEA02987.java

@@ -0,0 +1,86 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.leavehospital;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.DeathCaseDiscussDoc;
+import com.lantone.qc.pub.model.doc.DeathRecordDoc;
+import com.lantone.qc.pub.model.doc.DoctorAdviceDoc;
+import com.lantone.qc.pub.model.doc.LeaveHospitalDoc;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @ClassName : LEA02987
+ * @Description : 出院带药与医嘱不一致
+ * @Author : 胡敬
+ * @Date: 2020-06-23 10:54
+ */
+@Component
+public class LEA02987 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        List<DoctorAdviceDoc> doctorAdviceDocs = inputInfo.getDoctorAdviceDocs();
+        LeaveHospitalDoc leaveHospitalDoc = inputInfo.getLeaveHospitalDoc();
+        if (doctorAdviceDocs.size() == 0 || leaveHospitalDoc == null) {
+            return;
+        }
+        DeathRecordDoc deathRecordDoc = inputInfo.getDeathRecordDoc();
+        DeathCaseDiscussDoc deathCaseDiscussDoc = inputInfo.getDeathCaseDiscussDoc();
+        if (deathRecordDoc != null || deathCaseDiscussDoc != null) {
+            return;
+        }
+        Map<String, String> structureMap = leaveHospitalDoc.getStructureMap();
+        String dischargeOrder = structureMap.get("病历|出院带药");
+        if (StringUtil.isBlank(dischargeOrder)) {
+            return;
+        }
+        Set<String> drugs = new HashSet<>();
+        for (DoctorAdviceDoc adviceDoc : doctorAdviceDocs) {
+            Map<String, String> adviceDocStructureMap = adviceDoc.getStructureMap();
+            String name = adviceDocStructureMap.get("医嘱项目名称");
+            String type = adviceDocStructureMap.get("医嘱类型判别");
+            if (StringUtil.isNotBlank(type) && type.equals("出院带药")) {
+                if (StringUtil.isNotBlank(name)) {
+                    drugs.add(name);
+                }
+            }
+        }
+
+        String infoStr = "";
+        List<String> notContainsDrugs = new ArrayList<>();
+        for (String drug:drugs) {
+            if (!dischargeOrder.contains(drug)){
+                notContainsDrugs.add(drug);
+            }
+        }
+
+        //没有包含的药品再次查看商品名或化学名在出院医嘱书写
+        for (String drug : notContainsDrugs) {
+            Set<String> splitDrugs = CatalogueUtil.getRegexWords(drug, "[((\\[][^\\[\\]()()]+[\\]))]");
+            boolean isFind = false;
+            for (String sd : splitDrugs) {
+                if (dischargeOrder.contains(sd)){
+                    isFind = true;
+                }
+            }
+            if (!isFind) {
+                infoStr = CatalogueUtil.concatInfo(infoStr, drug);
+            }
+        }
+        if (StringUtil.isNotBlank(infoStr)){
+            status.set("-1");
+            info.set(infoStr);
+        }
+    }
+
+}

+ 50 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/operationdiscussion/OPE0322.java

@@ -0,0 +1,50 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.operationdiscussion;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+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.operation.OperationDoc;
+import org.springframework.stereotype.Component;
+
+import java.text.ParseException;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @Description: 手术患者无手术记录
+ * @author: Mark
+ * @time: 2020/04/04 11:22
+ */
+@Component
+public class OPE0322 extends QCCatalogue {
+
+    @Override
+    protected void start(InputInfo inputInfo, OutputInfo outputInfo) throws ParseException {
+        status.set("0");
+        //先判断医嘱里有无手术
+        List<DoctorAdviceDoc> doctorAdviceDocs = inputInfo.getDoctorAdviceDocs();
+        if (doctorAdviceDocs.size() == 0) {
+            return;
+        }
+        long cou = inputInfo.getOperationDocs().stream().map(OperationDoc::getOperationRecordDoc).filter(Objects::nonNull).count();
+        for (DoctorAdviceDoc dad : doctorAdviceDocs) {
+            String name = dad.getStructureMap().get("医嘱项目名称");
+            String daStartDateStr = dad.getStructureMap().get("医嘱开始时间");
+            if (name.contains("非手术") || name.contains("手术室") || (name.contains("手术") && name.contains("取消")) || (name.contains("暂停") && name.contains("手术")) || name.contains("静脉穿刺置管术") || name.startsWith("停") || name.contains("前一次")
+                    || name.contains("特殊病人手术使用一次性卫生材料") || name.contains("人免疫缺陷病毒抗体检测免费") || name.contains("手术标本") || name.contains("手术科")) {
+                continue;
+            }
+            if (name.contains("手术") && cou == 0) {
+                info.set("医嘱时间" + daStartDateStr);
+                status.set("-1");
+                return;
+            }
+        }
+        /*long cou = inputInfo.getOperationDocs().stream().map(i -> i.getOperationRecordDoc()).filter(i -> i != null).count();
+        if (cou == 0) {
+            status.set("-1");
+        }*/
+    }
+
+}

+ 146 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/operationdiscussion/OPE0369.java

@@ -0,0 +1,146 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.operationdiscussion;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.FirstCourseRecordDoc;
+import com.lantone.qc.pub.model.doc.MedicalRecordInfoDoc;
+import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
+import com.lantone.qc.pub.model.doc.operation.OperationDoc;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Description: 手术患者缺术前主刀医师查房记录
+ * @author: WANGSY
+ * @time: 2020/11/11 11:22
+ */
+@Component
+public class OPE0369 extends QCCatalogue {
+
+    @Override
+    protected void start(InputInfo inputInfo, OutputInfo outputInfo) throws ParseException {
+        status.set("0");
+        MedicalRecordInfoDoc medicalRecordInfoDoc = inputInfo.getMedicalRecordInfoDoc();
+        String admisTime = "";
+        if (medicalRecordInfoDoc != null && medicalRecordInfoDoc.getStructureMap() != null) {
+            //入院日期
+            admisTime = medicalRecordInfoDoc.getStructureMap().get("behospitalDate");
+            if (CatalogueUtil.isEmpty(admisTime)) {
+                return;
+            }
+        }
+        //先判断是否有手术记录
+        List<OperationDoc> operationDocs = inputInfo.getOperationDocs();
+        if (operationDocs == null || operationDocs.size() == 0) {
+            return;
+        }
+        List<ThreeLevelWardDoc> threeLevelWardDocs = inputInfo.getThreeLevelWardDocs();
+        long operationCount = operationDocs.stream().filter(operationDoc -> operationDoc.getOperationRecordDoc() != null).count();
+        //主刀查房次数
+        long operateCount = 0;
+        if (operationCount > 0) {
+            //存在手术记录无查房记录
+            if (ListUtil.isEmpty(threeLevelWardDocs)) {
+                status.set("-1");
+                return;
+            }
+            String operationStartDate = "";
+            String operatorPhysician = "";
+            List<Date> operDateList = new ArrayList<>();
+            for (OperationDoc operationDoc : operationDocs) {
+                if (operationDoc.getOperationRecordDoc() != null) {
+                    Map<String, String> operationDocStructureMap = operationDoc.getOperationRecordDoc().getStructureMap();
+                    String opeStartDate = operationDocStructureMap.get("手术日期");
+                    String opeStartTime = operationDocStructureMap.get("开始时间");
+                    operatorPhysician = operationDocStructureMap.get("主刀医师");
+                    if (StringUtil.isNotBlank(opeStartDate)) {
+                        operationStartDate = opeStartDate;
+                        if (StringUtil.isNotBlank(opeStartTime)) {
+                            operationStartDate = opeStartDate + " " + opeStartTime;
+                        }
+                    }
+                    if (StringUtil.isNotBlank(operationStartDate)) {
+                        if (!CatalogueUtil.compareTime(
+                                StringUtil.parseDateTime(admisTime),
+                                StringUtil.parseDateTime(operationStartDate),
+                                Long.valueOf(30))) {
+                            continue;
+                        }
+                        operDateList.add(StringUtil.parseDateTime(operationStartDate));
+                    } else {//取不到手术时间
+                        return;
+                    }
+                }
+            }
+
+            if (operDateList.size() > 1) {
+                for (int i = 0; i < operDateList.size(); i++) {
+                    if (i + 1 < operDateList.size()) {
+                        if (!CatalogueUtil.compareTime(operDateList.get(i), operDateList.get(i + 1),
+                                Long.valueOf(24 * 60))) {//如果手术记录是同一天,需有一次术前主刀查房
+                            operationCount--;
+                        }
+                    }
+                }
+            }
+
+            //判断是否为急诊手术
+            if (findEmergencyOperation(inputInfo)) {
+                return;
+//                operationCount--;
+            }
+
+            ThreeLevelWardDoc threeLevelWardDoc = threeLevelWardDocs.get(0);
+            List<ThreeLevelWardDoc> allDoctorWradDocs = threeLevelWardDoc.getAllDoctorWradDocs();
+            for (ThreeLevelWardDoc threeLevelWard : allDoctorWradDocs) {
+                Map<String, String> structureMap = threeLevelWard.getStructureMap();
+                String makeTitle = structureMap.get("查房标题");
+                String writTitle = structureMap.get("文书标题");
+                String recordDateStr = structureMap.get("查房日期");
+                if (operDateList.size() > 0) {
+                    for (Date date : operDateList) {
+                        if (StringUtil.isNotBlank(recordDateStr) && date != null
+                                && StringUtil.parseDateTime(recordDateStr).before(date)) {
+                            if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(recordDateStr), date, Long.valueOf(24 * 60))
+                                    && ((makeTitle.contains("主刀") || (StringUtil.isNotBlank(writTitle) && writTitle.contains("主刀")))
+                                    || (makeTitle.contains("术前") || (StringUtil.isNotBlank(writTitle) && writTitle.contains("术前")))
+                                    || (StringUtil.isNotBlank(operatorPhysician) && makeTitle.contains(operatorPhysician))
+                            )) {
+                                operateCount++;
+                            }
+                        }
+                    }
+                } else {//手术开始时间跟入院时间 小于30分钟,规则不判断
+                    return;
+                }
+            }
+        }
+
+        if (operationCount > 0 && operationCount > operateCount) {
+            status.set("-1");
+            return;
+        }
+    }
+
+    private boolean findEmergencyOperation(InputInfo inputInfo) {
+        FirstCourseRecordDoc firstCourseRecordDoc = inputInfo.getFirstCourseRecordDoc();
+        if (firstCourseRecordDoc != null) {
+            String treatPlan = firstCourseRecordDoc.getStructureMap().get("诊疗计划");
+            treatPlan = treatPlan.replace("\r\n", "");
+            if (StringUtil.isNotBlank(treatPlan)) {
+                String regex = ".*急诊.*术.*";
+                return treatPlan.matches(regex);
+            }
+        }
+        return false;
+    }
+}

+ 57 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/operationdiscussion/OPE0647.java

@@ -0,0 +1,57 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.operationdiscussion;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.operation.OperationDoc;
+import com.lantone.qc.pub.model.doc.operation.OperationRecordDoc;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : OPE0647
+ * @Description : 手术记录未在术后24h内完成
+ * @Author : 胡敬
+ * @Date: 2020-03-30 10:22
+ */
+@Component
+public class OPE0647 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        //        boolean isOperativePatient = true;//是手术患者(暂时默认是)
+        //        if (isOperativePatient) {
+        List<OperationDoc> operationDocs = inputInfo.getOperationDocs();
+        if (operationDocs == null || operationDocs.size() == 0) {
+            status.set("0");
+            return;
+        }
+        for (OperationDoc operationDoc : operationDocs) {
+            OperationRecordDoc operationRecordDoc = operationDoc.getOperationRecordDoc();
+            if (operationRecordDoc == null) {
+                continue;
+            }
+            Map<String, String> operationRecordStructureMap = operationRecordDoc.getStructureMap();
+            String operationEndDateStr = operationRecordStructureMap.get("手术结束时间");
+            String operationRecordDateStr = operationRecordStructureMap.get("病历日期");
+            if (CatalogueUtil.isEmpty(operationEndDateStr) || CatalogueUtil.isEmpty(operationRecordDateStr)) {
+                continue;
+            }
+            Date operationEndDate = StringUtil.parseDateTime(operationEndDateStr);
+            Date operationRecordDate = StringUtil.parseDateTime(operationRecordDateStr);
+            if (operationEndDate == null || operationRecordDate == null) {
+                continue;
+            }
+            boolean compareTime = CatalogueUtil.compareTime(operationEndDate, operationRecordDate, 24 * 60L);
+            if (compareTime) {
+                status.set("-1");
+                return;
+            }
+        }
+        //        }
+    }
+}

+ 139 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/preoperativediscussion/PRE0328.java

@@ -0,0 +1,139 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.preoperativediscussion;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+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.operation.OperationDoc;
+import com.lantone.qc.pub.model.doc.operation.OperationRecordDoc;
+import com.lantone.qc.pub.util.DateUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Description: 手术患者无术前讨论记录
+ * @author: rengb
+ * @time: 2020/3/23 15:09
+ */
+@Component
+public class PRE0328 extends QCCatalogue {
+
+    @Override
+    protected void start(InputInfo inputInfo, OutputInfo outputInfo) throws ParseException {
+        /**
+         * 1:如果急诊手术【入院时间-手术开始时间小于30分钟】则可不用写术前小结。
+         * 2:如果入院时间-手术开始时间小于30分钟,则术前讨论、术前小结次数+1。
+         * 3:如果手术记录次数(第一次手术的日期内有其他手术不算次数) 大于 术前讨论、术前小结次数,则出错
+         */
+        status.set("0");
+        List<DoctorAdviceDoc> doctorAdviceDocs = inputInfo.getDoctorAdviceDocs();
+        List<OperationDoc> operationDocs = inputInfo.getOperationDocs();
+        if (operationDocs == null || operationDocs.size() == 0) {
+            return;
+        }
+        boolean emergencyOperation = false;
+        if (inputInfo.getBeHospitalizedDoc() != null) {
+            Map<String, String> beHospitalStructureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+            String admisTime = beHospitalStructureMap.get("入院日期");
+            //取手术记录第一次手术开始时间和入院时间比较,相差30分钟内不报缺陷
+            OperationRecordDoc operationRecordDoc = operationDocs.get(0).getOperationRecordDoc();
+            String startTime = "";
+            if (operationRecordDoc != null) {
+                startTime = operationRecordDoc.getStructureMap().get("手术开始时间");
+            }
+            if (StringUtil.isNotBlank(startTime) && StringUtil.isNotBlank(admisTime) &&
+                    !startTime.contains("年月日")) {
+                if (!CatalogueUtil.compareTime(
+                        StringUtil.parseDateTime(admisTime),
+                        StringUtil.parseDateTime(startTime),
+                        Long.valueOf(30))) {//入院到手术未超过30分钟,则可不用写术前小结
+                    emergencyOperation = true;
+                }
+            }
+        }
+
+        int i = getOperationSum(operationDocs); // 获取手术记录次数
+        int j = 0;  // 获取术前讨论、术前小结次数
+        for (OperationDoc operationDoc : operationDocs) {
+            if (operationDoc.getPreoperativeDiscussionDoc() != null) {
+                j++;
+            }
+        }
+        /* 如果入院时间-手术开始时间小于30分钟,则术前讨论、术前小结次数+1*/
+        if (emergencyOperation) {
+            if (j == 0) {
+                j++;
+            }
+        }
+        //医嘱中包含“冠状动脉造影术”,且无术前讨论.则报规则
+        for (DoctorAdviceDoc doctorAdviceDoc : doctorAdviceDocs) {
+            Map<String, String> doctorAdviceStructuerMap = doctorAdviceDoc.getStructureMap();
+            String advicename = doctorAdviceStructuerMap.get("医嘱项目名称");
+            if (StringUtil.isNotBlank(advicename) && advicename.contains("冠状动脉造影术") && j == 0) {
+                status.set("-1");
+                info.set("手术记录不一致");
+            }
+        }
+
+        if (i > 0 && i > j) {
+            status.set("-1");
+            info.set("手术记录不一致");
+        }
+    }
+
+    /**
+     * 获取手术记录次数
+     *
+     * @param operationDocs
+     * @return
+     */
+    private int getOperationSum(List<OperationDoc> operationDocs) {
+        List<Map<String, Date>> operationDateList = new ArrayList<>();
+        Map<String, Date> operationDate = null;
+        for (OperationDoc operationDoc : operationDocs) {
+            OperationRecordDoc operationRecordDoc = operationDoc.getOperationRecordDoc();
+            if (operationRecordDoc == null) {
+                continue;
+            }
+            Map<String, String> structureMap = operationRecordDoc.getStructureMap();
+            String operationStartDateStr = structureMap.get("手术开始时间");
+            if (StringUtil.isNotBlank(operationStartDateStr) && DateUtil.parseDateTime(operationStartDateStr) != null) {
+                Date operationStartDate = StringUtil.parseDateTime(operationStartDateStr);
+                operationStartDate = DateUtil.dateZeroClear(operationStartDate);
+                if (operationStartDate != null) {
+                    /* 放第一个手术记录的日期到operationDateList */
+                    if (operationDateList.size() == 0) {
+                        operationDate = new HashMap<>();
+                        operationDate.put("手术开始时间", operationStartDate);
+                        operationDateList.add(operationDate);
+                        continue;
+                    }
+                    /* 如果其中一个手术记录的开始时间到结束时间之间还包含另一个手术,就不往operationDateList里加 */
+                    boolean findInnerOperation = false;
+                    for (Map<String, Date> date : operationDateList) {
+                        Date listStartDate = DateUtil.dateZeroClear(date.get("手术开始时间"));
+                        if (listStartDate.equals(operationStartDate)) {
+                            findInnerOperation = true;
+                            break;
+                        }
+                    }
+                    if (!findInnerOperation) {
+                        operationDate = new HashMap<>();
+                        operationDate.put("手术开始时间", operationStartDate);
+                        operationDateList.add(operationDate);
+                    }
+                }
+            }
+        }
+        return operationDateList.size();
+    }
+
+}

+ 48 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0122.java

@@ -0,0 +1,48 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.threelevelward;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.Content;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.util.DateUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @ClassName : THR0122
+ * @Description : 首次病程未在患者入院8小时内完成
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class THR0122 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getBeHospitalizedDoc() != null && inputInfo.getBeHospitalizedDoc().getStructureMap() != null
+                && inputInfo.getFirstCourseRecordDoc() != null && inputInfo.getFirstCourseRecordDoc().getStructureMap() != null) {
+            Map<String, String> beHospitalStructureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+            String admisDate = beHospitalStructureMap.get(Content.admisDate);
+            Map<String, String> firstCourseRecordStructureMap = inputInfo.getFirstCourseRecordDoc().getStructureMap();
+            String recordTime = firstCourseRecordStructureMap.get("病历日期");
+            if (CatalogueUtil.isEmpty(admisDate) || CatalogueUtil.isEmpty(recordTime)) {
+                return;
+            }
+            if (!CatalogueUtil.compareTime(
+                    StringUtil.parseDateTime(admisDate),
+                    StringUtil.parseDateTime(DateUtil.nowString()),
+                    Long.valueOf(8 * 60))) {//如果入院未超过8小时,规则不判断
+                return;
+            }
+            if (CatalogueUtil.compareTime(
+                    StringUtil.parseDateTime(admisDate),
+                    StringUtil.parseDateTime(recordTime),
+                    Long.valueOf(8 * 60))) {
+                status.set("-1");
+            }
+
+        }
+    }
+}

+ 165 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0125.java

@@ -0,0 +1,165 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.threelevelward;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.MedicalRecordInfoDoc;
+import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
+import com.lantone.qc.pub.model.doc.ward.DirectorDoctorWardDoc;
+import com.lantone.qc.pub.util.DateUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : THR0125
+ * @Description : 副主任医师/主任医师查房首次查房记录未在患者入院72h内完成
+ * @Author : 胡敬
+ * @Date: 2020-03-19 13:51
+ */
+@Component
+public class THR0125 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+
+        MedicalRecordInfoDoc medicalRecordInfoDoc = inputInfo.getMedicalRecordInfoDoc();
+        if (medicalRecordInfoDoc != null && medicalRecordInfoDoc.getStructureMap() != null) {
+            //入院日期
+            String admisTime = medicalRecordInfoDoc.getStructureMap().get("behospitalDate");
+            //出院日期
+            String dischargeTime = medicalRecordInfoDoc.getStructureMap().get("leaveHospitalDate");
+            if (CatalogueUtil.isEmpty(admisTime) || CatalogueUtil.isEmpty(dischargeTime)) {
+                status.set("0");
+                return;
+            }
+            if (!CatalogueUtil.compareTime(
+                    StringUtil.parseDateTime(admisTime),
+                    StringUtil.parseDateTime(DateUtil.nowString()),
+                    Long.valueOf(72 * 60))) {//如果入院未超过72小时,规则不判断
+                status.set("0");
+                return;
+            }
+            //如果住院天数小于3天则不判断该条规则
+            if (DateUtil.parseDate(dischargeTime) != null &&
+                    !CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(dischargeTime), (long) (72 * 60))) {
+                status.set("0");
+                return;
+            } else {
+                if (inputInfo.getThreeLevelWardDocs().size() == 0) {
+                    return;
+                }
+            }
+        }
+
+        if (inputInfo.getBeHospitalizedDoc() != null) {
+            Map<String, String> beHospitalStructureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+            String admisTime = beHospitalStructureMap.get("入院日期");
+            if (CatalogueUtil.isEmpty(admisTime)) {
+                status.set("0");
+                return;
+            }
+            if (!CatalogueUtil.compareTime(
+                    StringUtil.parseDateTime(admisTime),
+                    StringUtil.parseDateTime(DateUtil.nowString()),
+                    Long.valueOf(72 * 60))) {//如果入院未超过72小时,规则不判断
+                status.set("0");
+                return;
+            }
+            //开始时间(入院时间)
+            Date beginDate = StringUtil.parseDateTime(admisTime);
+            if (beginDate == null) {
+                status.set("0");
+                return;
+            }
+            ThreeLevelWardDoc threeLevelWardDoc = inputInfo.getThreeLevelWardDocs().get(0);
+            List<DirectorDoctorWardDoc> directorDoctorWardDocs = threeLevelWardDoc.getDirectorDoctorWardDocs();
+            if (directorDoctorWardDocs.size() > 0) {
+                DirectorDoctorWardDoc firstDirector = directorDoctorWardDocs.get(0);
+                String wardDateStr = firstDirector.getStructureMap().get("查房日期");
+                if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(wardDateStr), 72 * 60L)) {
+                    status.set("0");
+                    return;
+                }
+            } else if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), new Date(), 72 * 60L)) {
+                status.set("0");//没有主任医师查房,若入院时间和系统当前时间对比,相差72小时则报错
+                return;
+            }
+
+            /* 如果存在手术记录,判断主刀医生是否为主治医生 */
+//            String operatorName = "";
+//            List<OperationDoc> operationDocs = inputInfo.getOperationDocs();
+//            if (operationDocs != null) {
+//                for (OperationDoc operationDoc : operationDocs) {
+//                    if (operationDoc.getOperationRecordDoc() != null) {
+//                        Map<String, String> operationDocStructureMap = operationDoc.getOperationRecordDoc().getStructureMap();
+//                        if (StringUtil.isBlank(operatorName)) {
+//                            operatorName = operationDocStructureMap.get("主刀医师");
+//                            if (StringUtil.isBlank(operatorName) && StringUtil.isNotBlank(operationDocStructureMap.get("手术者及助手名称"))) {
+//                                operatorName = operationDocStructureMap.get("手术者及助手名称").split("、")[0];
+//                                if (operatorName.contains("主刀:") && operatorName.split(":").length > 1) {
+//                                    operatorName = operatorName.split(":")[1];
+//                                }
+//                            }
+//                        }
+//                    }
+//                }
+//
+//                List<ThreeLevelWardDoc> allDoctorWradDocs = threeLevelWardDoc.getAllDoctorWradDocs();
+//                for (ThreeLevelWardDoc threeLevelWard : allDoctorWradDocs) {
+//                    Map<String, String> structureMap = threeLevelWard.getStructureMap();
+//                    String wardDateStr = structureMap.get("查房日期");
+//                    if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(wardDateStr), 72 * 60L)) {
+//                        String makeTitle = structureMap.get("查房标题");
+//                        String pathography = structureMap.get("病情记录");
+//                        //判断标题
+//                        visitingPhysicianHouse(operatorName, makeTitle);
+//                        //判断病情记录
+//                        visitingPhysicianHouse(operatorName, pathography);
+//                    }
+//                }
+//            }
+//        }
+        }
+    }
+
+//    /**
+//     * 判断查房记录是否含有主任医师查房
+//     *
+//     * @param operatorName     主刀医师
+//     * @param titlePathography 查房标题或病情记录
+//     */
+//    private void visitingPhysicianHouse(String operatorName, String titlePathography) {
+//        if (StringUtil.isNotBlank(titlePathography)) {
+//            if (titlePathography.contains("主任")) {
+//                status.set("0");
+//                return;
+//            } else if (StringUtil.isNotBlank(operatorName) && (titlePathography.contains(operatorName) || titlePathography.contains("主刀"))) {
+//                String operationProfessor = getCourseProfessor(operatorName);
+//                if (operationProfessor.contains("主任")) {
+//                    status.set("0");
+//                    return;
+//                }
+//            }
+//        }
+//    }
+
+//    private String getCourseProfessor(String operatorName) {
+//        String professor = "";
+//        if (StringUtil.isBlank(operatorName)) {
+//            return professor;
+//        }
+//        SpecialStorageUtil specialStorageUtil = SpringContextUtil.getBean("specialStorageUtil");
+//        Map<String, Object> surgeon = specialStorageUtil.getJsonStringValue(KernelConstants.HOSPITAL_DOCTOR_MAP);
+//        if (surgeon != null) {
+//            Map<String, String> doctor = (Map) surgeon.get(operatorName);
+//            if (doctor != null) {
+//                professor = doctor.get("professor");
+//            }
+//
+//        }
+//        return professor;
+//    }
+}

+ 184 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0126.java

@@ -0,0 +1,184 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.threelevelward;
+
+import com.lantone.qc.dbanaly.util.KernelConstants;
+import com.lantone.qc.dbanaly.util.SpecialStorageUtil;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.FirstCourseRecordDoc;
+import com.lantone.qc.pub.model.doc.MedicalRecordInfoDoc;
+import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
+import com.lantone.qc.pub.model.doc.ward.AttendingDoctorWardDoc;
+import com.lantone.qc.pub.util.DateUtil;
+import com.lantone.qc.pub.util.SpringContextUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : THR0126
+ * @Description : 主治医师首次查房未在48小时内完成
+ * @Author : 胡敬
+ * @Date: 2020-03-19 15:50
+ */
+@Component
+public class THR0126 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+
+        MedicalRecordInfoDoc medicalRecordInfoDoc = inputInfo.getMedicalRecordInfoDoc();
+        if (medicalRecordInfoDoc != null && medicalRecordInfoDoc.getStructureMap() != null) {
+            //入院日期
+            String admisTime = medicalRecordInfoDoc.getStructureMap().get("behospitalDate");
+            //出院日期
+            String dischargeTime = medicalRecordInfoDoc.getStructureMap().get("leaveHospitalDate");
+            if (CatalogueUtil.isEmpty(admisTime) || CatalogueUtil.isEmpty(dischargeTime)) {
+                status.set("0");
+                return;
+            }
+            if (!CatalogueUtil.compareTime(
+                    StringUtil.parseDateTime(admisTime),
+                    StringUtil.parseDateTime(DateUtil.nowString()),
+                    Long.valueOf(48 * 60))) {//如果入院未超过48小时,规则不判断
+                status.set("0");
+                return;
+            }
+            //如果住院天数小于2天则不判断该条规则
+            if (DateUtil.parseDate(dischargeTime) != null && StringUtil.isNotEmpty(dischargeTime) &&
+                    !CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(dischargeTime), (long) (48 * 60))) {
+                status.set("0");
+                return;
+            } else {
+                if (inputInfo.getThreeLevelWardDocs().size() == 0) {
+                    return;
+                }
+            }
+        }
+
+        if (inputInfo.getBeHospitalizedDoc() != null) {
+            Map<String, String> beHospitalStructureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+            String admisTime = beHospitalStructureMap.get("入院日期");
+            if (CatalogueUtil.isEmpty(admisTime)) {
+                status.set("0");
+                return;
+            }
+            if (!CatalogueUtil.compareTime(
+                    StringUtil.parseDateTime(admisTime),
+                    StringUtil.parseDateTime(DateUtil.nowString()),
+                    Long.valueOf(48 * 60))) {//如果入院未超过48小时,规则不判断
+                status.set("0");
+                return;
+            }
+            //开始时间(入院时间)
+            Date beginDate = StringUtil.parseDateTime(admisTime);
+            if (beginDate == null) {
+                status.set("0");
+                return;
+            }
+            /* 首次病程录如果是主治或者主任写的,也算主治查房 */
+            FirstCourseRecordDoc firstCourseRecordDoc = inputInfo.getFirstCourseRecordDoc();
+            if (firstCourseRecordDoc != null) {
+                String doctorSign = firstCourseRecordDoc.getStructureMap().get("记录医生");
+                String firstCourseProfessor = getFirstCourseProfessor(doctorSign);
+                if (StringUtil.isNotBlank(firstCourseProfessor) && firstCourseProfessor.contains("主治")) {
+                    String recordDateStr = firstCourseRecordDoc.getStructureMap().get("病历日期");
+                    if (StringUtil.isNotBlank(recordDateStr)) {
+                        if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(recordDateStr), 48 * 60L)) {
+                            status.set("0");
+                            return;
+                        }
+                    }
+                }
+            }
+            ThreeLevelWardDoc threeLevelWardDoc = inputInfo.getThreeLevelWardDocs().get(0);
+            List<AttendingDoctorWardDoc> attendingDoctorWardDocs = threeLevelWardDoc.getAttendingDoctorWardDocs();
+            if (attendingDoctorWardDocs.size() > 0) {
+                AttendingDoctorWardDoc firstAttending = attendingDoctorWardDocs.get(0);
+                String wardDateStr = firstAttending.getStructureMap().get("查房日期");
+                if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(wardDateStr), 48 * 60L)) {
+                    status.set("0");
+                    return;
+                }
+            } else if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), new Date(), 48 * 60L)) {
+                status.set("0");//没有主治医师查房,若入院时间和系统当前时间对比,相差48小时则报错
+                return;
+            }
+
+            /* 如果存在手术记录,判断主刀医生是否为主治医生 */
+//            String operatorName = "";
+//            List<OperationDoc> operationDocs = inputInfo.getOperationDocs();
+//            if (operationDocs != null) {
+//                for (OperationDoc operationDoc : operationDocs) {
+//                    if (operationDoc.getOperationRecordDoc() != null) {
+//                        Map<String, String> operationDocStructureMap = operationDoc.getOperationRecordDoc().getStructureMap();
+//                        if (StringUtil.isBlank(operatorName)) {
+//                            operatorName = operationDocStructureMap.get("主刀医师");
+//                            if (StringUtil.isBlank(operatorName) && StringUtil.isNotBlank(operationDocStructureMap.get("手术者及助手名称"))) {
+//                                operatorName = operationDocStructureMap.get("手术者及助手名称").split("、")[0];
+//                                if (operatorName.contains("主刀:") && operatorName.split(":").length > 1) {
+//                                    operatorName = operatorName.split(":")[1];
+//                                }
+//                            }
+//                        }
+//                    }
+//                }
+//            }
+
+//            List<ThreeLevelWardDoc> allDoctorWradDocs = threeLevelWardDoc.getAllDoctorWradDocs();
+//            for (ThreeLevelWardDoc threeLevelWard : allDoctorWradDocs) {
+//                Map<String, String> structureMap = threeLevelWard.getStructureMap();
+//                String wardDateStr = structureMap.get("查房日期");
+//                if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(wardDateStr), 48 * 60L)) {
+//                    String makeTitle = structureMap.get("查房标题");
+//                    String pathography = structureMap.get("病情记录");
+//                    //判断标题
+//                    visitingPhysicianHouse(operatorName, makeTitle);
+//                    //判断病情记录
+//                    visitingPhysicianHouse(operatorName, pathography);
+//                }
+//            }
+        }
+    }
+
+//    /**
+//     * 判断查房记录是否含有主治医师查房
+//     *
+//     * @param operatorName     主刀医师
+//     * @param titlePathography 查房标题或病情记录
+//     */
+//    private void visitingPhysicianHouse(String operatorName, String titlePathography) {
+//        if (StringUtil.isNotBlank(titlePathography)) {
+//            if (titlePathography.contains("主治")) {
+//                status.set("0");
+//                return;
+//            } else if (StringUtil.isNotBlank(operatorName) && (titlePathography.contains(operatorName) || titlePathography.contains("主刀"))) {
+//                String operationProfessor = getFirstCourseProfessor(operatorName);
+//                if (operationProfessor.contains("主治")) {
+//                    status.set("0");
+//                    return;
+//                }
+//            }
+//        }
+//    }
+//
+    private String getFirstCourseProfessor(String doctorSign) {
+        String professor = "";
+//        String doctorSign = firstCourseRecordDoc.getStructureMap().get("医生签名");
+        if (StringUtil.isBlank(doctorSign)) {
+            return professor;
+        }
+        SpecialStorageUtil specialStorageUtil = SpringContextUtil.getBean("specialStorageUtil");
+        Map<String, Object> surgeon = specialStorageUtil.getJsonStringValue(KernelConstants.HOSPITAL_DOCTOR_MAP);
+        if (surgeon != null) {
+            Map<String, String> doctor = (Map) surgeon.get(doctorSign);
+            if (doctor != null) {
+                professor = doctor.get("professor");
+            }
+
+        }
+        return professor;
+    }
+}

+ 203 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0127.java

@@ -0,0 +1,203 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.threelevelward;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.Content;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.MedicalRecordInfoDoc;
+import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
+import com.lantone.qc.pub.model.doc.operation.OperationDoc;
+import com.lantone.qc.pub.util.DateUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : THR0127
+ * @Description : 每周无2次副主任医师/主任医师查房记录
+ * @Author : 胡敬
+ * @Date: 2020-03-19 15:52
+ */
+@Component
+public class THR0127 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        MedicalRecordInfoDoc medicalRecordInfoDoc = inputInfo.getMedicalRecordInfoDoc();
+        if (medicalRecordInfoDoc != null && medicalRecordInfoDoc.getStructureMap() != null) {
+            //入院日期
+            String admisTime = medicalRecordInfoDoc.getStructureMap().get("behospitalDate");
+            //出院日期
+            String dischargeTime = medicalRecordInfoDoc.getStructureMap().get("leaveHospitalDate");
+            if (CatalogueUtil.isEmpty(admisTime)) {
+                return;
+            }
+            String presentTime = DateUtil.nowString();
+            //如果如果入院未超过7天则不判断该条规则
+            if (!CatalogueUtil.isEmpty(admisTime) && !CatalogueUtil.isEmpty(presentTime)) {
+                if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(presentTime), (long) (7 * 24 * 60))) {
+                    return;
+                }
+            }
+            //如果住院天数小于7天则不判断该条规则
+            if (!CatalogueUtil.isEmpty(admisTime) && !CatalogueUtil.isEmpty(dischargeTime)) {
+                if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(dischargeTime), (long) (7 * 24 * 60))) {
+                    return;
+                }
+            } else {
+                if (inputInfo.getThreeLevelWardDocs().size() == 0) {
+                    status.set("-1");
+                    return;
+                }
+            }
+
+            if (inputInfo.getBeHospitalizedDoc() != null && inputInfo.getThreeLevelWardDocs().size() > 0) {
+                if (CatalogueUtil.isEmpty(admisTime)) {
+                    return;
+                }
+                //开始时间(入院时间)
+                Date beginDate = StringUtil.parseDateTime(admisTime);
+                if (beginDate == null) {
+                    return;
+                }
+
+                ThreeLevelWardDoc threeLevelWardDoc = inputInfo.getThreeLevelWardDocs().get(0);
+                List<ThreeLevelWardDoc> allDoctorWradDocs = threeLevelWardDoc.getAllDoctorWradDocs();
+                if (allDoctorWradDocs.size() == 0) {
+                    status.set("0");
+                    return;
+                }
+                Date lastRecordDate = getLastRecordDate(allDoctorWradDocs);
+                if (lastRecordDate == null) {
+                    return;
+                }
+                int hoursPerWeek = 7 * 24 * 60;
+                String roundRecordThisWeek = "";
+                List<String> roundRecordEveryWeek = new ArrayList<>();
+                beginDate = DateUtil.dateZeroClear(beginDate);//从入院记录当天0点开始算
+                int i = 1;
+                String lastWardDateRange = "";
+                List<String> lastWardDateRangeList = new ArrayList<>();
+                //每周的病历记录
+                while (i >= 1) {
+                    roundRecordThisWeek = extractWardRecord(inputInfo, allDoctorWradDocs, beginDate, hoursPerWeek, lastRecordDate);
+                    if (CatalogueUtil.isEmpty(roundRecordThisWeek)) {
+                        break;
+                    }
+                    //如果6天后日期大于出院日期,跳过
+                    if (StringUtil.isBlank(dischargeTime)) {
+                        dischargeTime = presentTime;
+                    }
+                    Date sixDate = DateUtil.addDate(beginDate, 7);
+                    if (StringUtil.parseDateTime(dischargeTime).before(sixDate)) {
+                        break;
+                    }
+                    lastWardDateRange = DateUtil.formatDate(beginDate) + "    ->    " + DateUtil.formatDate(sixDate);
+                    lastWardDateRangeList.add(lastWardDateRange);
+                    roundRecordEveryWeek.add(roundRecordThisWeek);
+                    beginDate = DateUtil.addDate(beginDate, 7);
+                    i++;
+                }
+                if (roundRecordEveryWeek.size() == 0) {
+                    status.set("0");
+                    return;
+                }
+                List<String> resultInfos = new ArrayList<>();
+                for (int j = 0; j < roundRecordEveryWeek.size(); j++) {
+                    int directorNum = CatalogueUtil.appearNumber(roundRecordEveryWeek.get(j).split(","), Content.director);
+                    int dept_doctorNum = CatalogueUtil.appearNumber(roundRecordEveryWeek.get(j).split(","), Content.dept_doctor);
+                    //多学科联合,三级医师查房算一次主任查房
+                    int threeDoctorNum = CatalogueUtil.appearNumber(roundRecordEveryWeek.get(j).split(","), "多学科联合");
+                    //北仑内分泌科(主任携主任代主治)
+                    int endocrinologyTitleNum = endocrinologyTitleNum(roundRecordEveryWeek.get(j).split(","));
+                    if (directorNum + dept_doctorNum + threeDoctorNum + endocrinologyTitleNum < 1) {
+                        //每周无2次主任医师查房记录/科主任查房记录
+                        status.set("-1");
+                        resultInfos.add(lastWardDateRangeList.get(j));
+                    }
+                }
+                if (resultInfos.size() > 0) {
+                    info.set(StringUtils.join(resultInfos.toArray(), ";"));
+                }
+            }
+        }
+    }
+
+    /**
+     * 北仑内分泌科主任主治处理
+     *
+     * @param srcText
+     * @return
+     */
+    private int endocrinologyTitleNum(String[] srcText) {
+        int count = 0;
+        for (String title : srcText) {
+            String regex = ".*主任.*主任.*主治.*";
+            if (title.matches(regex)) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    private Date getLastRecordDate(List<ThreeLevelWardDoc> allDoctorWradDocs) {
+        ThreeLevelWardDoc threeLevelWardDoc = allDoctorWradDocs.get(allDoctorWradDocs.size() - 1);
+        Map<String, String> lastWardDocStructureMap = threeLevelWardDoc.getStructureMap();
+        String wardDateStr = lastWardDocStructureMap.get("查房日期");
+        if (StringUtil.isNotBlank(wardDateStr)) {
+            return StringUtil.parseDateTime(wardDateStr);
+        }
+        return null;
+    }
+
+    /**
+     * 抽取duration分钟内所有查房标题
+     * 抽取一周内所有查房标题,若一周内记录少于6天,则返回""
+     *
+     * @param threeLevelWardDocs
+     * @param admisDate
+     * @param duration
+     * @return
+     */
+    private static String extractWardRecord(InputInfo inputInfo, List<ThreeLevelWardDoc> threeLevelWardDocs, Date admisDate, int duration, Date maxRecordDate) {
+        String recordTime = "", recordTitle = "", title = "";
+        List<Date> dateList = new ArrayList();
+        for (ThreeLevelWardDoc threeLevelWardDoc : threeLevelWardDocs) {
+            Map<String, String> threeLevelWardStructureMap = threeLevelWardDoc.getStructureMap();
+            recordTime = threeLevelWardStructureMap.get("查房日期");
+            title = threeLevelWardStructureMap.get("查房标题");
+            if (StringUtil.isBlank(recordTime) || StringUtil.isBlank(title)) {
+                continue;
+            }
+            Date recordDate = StringUtil.parseDateTime(recordTime);
+            if (recordDate == null) {
+                continue;
+            }
+            /* 替换查房标题中主刀/一助的职称 */
+            List<OperationDoc> operationDocs = inputInfo.getOperationDocs();
+            if (title.contains("主刀")) {
+                String doctorTitle = CatalogueUtil.getDoctorTitle(operationDocs, recordDate, "主刀医师");
+                title = title.replace("主刀", doctorTitle);
+            } else if (title.contains("一助")) {
+                String doctorTitle = CatalogueUtil.getDoctorTitle(operationDocs, recordDate, "一助");
+                title = title.replace("一助", doctorTitle);
+            }
+            if (admisDate.before(recordDate) && !CatalogueUtil.compareTime(admisDate, recordDate, Long.valueOf(duration))) {
+                recordTitle += title + ",";
+                dateList.add(recordDate);
+            }
+        }
+        if (dateList.size() > 0) {
+            //dateList.sort(Date::compareTo);
+            if (!maxRecordDate.equals(dateList.get(dateList.size() - 1)) || CatalogueUtil.compareTime(admisDate, dateList.get(dateList.size() - 1), Long.valueOf(6 * 24 * 60))) {
+                return recordTitle;
+            }
+        }
+        return "";
+    }
+}

+ 229 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0128.java

@@ -0,0 +1,229 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.threelevelward;
+
+import com.lantone.qc.dbanaly.util.KernelConstants;
+import com.lantone.qc.dbanaly.util.SpecialStorageUtil;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.Content;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.FirstCourseRecordDoc;
+import com.lantone.qc.pub.model.doc.MedicalRecordInfoDoc;
+import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
+import com.lantone.qc.pub.model.doc.operation.OperationDoc;
+import com.lantone.qc.pub.model.doc.ward.AttendingDoctorWardDoc;
+import com.lantone.qc.pub.util.DateUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : THR0128
+ * @Description : 每周无3次主治医师查房记录
+ * @Author : 胡敬
+ * @Date: 2020-03-19 16:52
+ */
+@Component
+public class THR0128 extends QCCatalogue {
+    @Autowired
+    private SpecialStorageUtil specialStorageUtil;
+
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        MedicalRecordInfoDoc medicalRecordInfoDoc = inputInfo.getMedicalRecordInfoDoc();
+        if (medicalRecordInfoDoc != null && medicalRecordInfoDoc.getStructureMap() != null) {
+            //入院日期
+            String admisTime = medicalRecordInfoDoc.getStructureMap().get("behospitalDate");
+            //出院日期
+            String dischargeTime = medicalRecordInfoDoc.getStructureMap().get("leaveHospitalDate");
+            if (CatalogueUtil.isEmpty(admisTime)) {
+                return;
+            }
+            String presentTime = DateUtil.nowString();
+            //如果如果入院未超过7天则不判断该条规则
+            if (!CatalogueUtil.isEmpty(admisTime) && !CatalogueUtil.isEmpty(presentTime)) {
+                if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(presentTime), (long) (7 * 24 * 60))) {
+                    return;
+                }
+            }
+            //如果住院天数小于7天则不判断该条规则
+            if (!CatalogueUtil.isEmpty(admisTime) && !CatalogueUtil.isEmpty(dischargeTime)) {
+                if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(dischargeTime), (long) (7 * 24 * 60))) {
+                    return;
+                }
+            } else {
+                if (inputInfo.getThreeLevelWardDocs().size() == 0) {
+                    status.set("-1");
+                    return;
+                }
+            }
+
+            if (inputInfo.getBeHospitalizedDoc() != null && inputInfo.getThreeLevelWardDocs().size() > 0) {
+                if (CatalogueUtil.isEmpty(admisTime)) {
+                    return;
+                }
+                //开始时间(入院时间)
+                Date beginDate = StringUtil.parseDateTime(admisTime);
+                if (beginDate == null) {
+                    return;
+                }
+
+                ThreeLevelWardDoc threeLevelWardDoc = inputInfo.getThreeLevelWardDocs().get(0);
+                List<ThreeLevelWardDoc> allDoctorWradDocs = threeLevelWardDoc.getAllDoctorWradDocs();
+                if (allDoctorWradDocs.size() == 0) {
+                    status.set("0");
+                    return;
+                }
+                Date lastRecordDate = getLastRecordDate(allDoctorWradDocs);
+                if (lastRecordDate == null) {
+                    return;
+                }
+                int hoursPerWeek = 7 * 24 * 60;
+                String roundRecordThisWeek = "";
+                List<String> roundRecordEveryWeek = new ArrayList<>();
+                beginDate = DateUtil.dateZeroClear(beginDate);//从入院记录当天天0点开始算
+                int i = 1;
+                //长兴首次病程算一次主治查房,所以第一周只需要两次主治查房就可以
+                int rounds = 0;//主治查房次数
+                Date firstWeek = DateUtil.addDate(beginDate, 7);
+                for (AttendingDoctorWardDoc attendingDoctorWardDoc : threeLevelWardDoc.getAttendingDoctorWardDocs()) {//循环筛选主治,找出地日在第一周的个数
+                    String recordTime = attendingDoctorWardDoc.getStructureMap().get("查房日期");
+                    Date recordDate = StringUtil.parseDateTime(recordTime);
+                    if (recordDate.before(firstWeek)) {
+                        rounds = rounds + 1;
+                    }
+                }
+                if (rounds >= 2) {
+                    return;
+                }
+                String lastWardDateRange = "";
+                List<String> lastWardDateRangeList = new ArrayList<>();
+                //每周的病历记录
+                while (i >= 1) {
+                    roundRecordThisWeek = extractWardRecord(inputInfo, allDoctorWradDocs, beginDate, hoursPerWeek, lastRecordDate);
+                    if (CatalogueUtil.isEmpty(roundRecordThisWeek)) {
+                        break;
+                    }
+                    //如果6天后日期大于出院日期,跳过
+                    if (StringUtil.isBlank(dischargeTime)) {
+                        dischargeTime = presentTime;
+                    }
+                    Date sixDate = DateUtil.addDate(beginDate, 7);
+                    if (StringUtil.parseDateTime(dischargeTime).before(sixDate)) {
+                        break;
+                    }
+                    lastWardDateRange = DateUtil.formatDate(beginDate) + "    ->    " + DateUtil.formatDate(sixDate);
+                    lastWardDateRangeList.add(lastWardDateRange);
+                    roundRecordEveryWeek.add(roundRecordThisWeek);
+                    beginDate = DateUtil.addDate(beginDate, 7);
+                    i++;
+                }
+                if (roundRecordEveryWeek.size() == 0) {
+                    status.set("0");
+                    return;
+                }
+                boolean firstRecordAttendExist = findfirstRecordAttend(inputInfo);
+                List<String> resultInfos = new ArrayList<>();
+                for (int j = 0; j < roundRecordEveryWeek.size(); j++) {
+                    int indicationsNum = CatalogueUtil.appearNumber(roundRecordEveryWeek.get(j).split(","), Content.attend);
+                    //多学科联合,三级医师查房算一次主治查房
+                    int threeDoctorNum = CatalogueUtil.appearNumber(roundRecordEveryWeek.get(j).split(","), "多学科联合");
+                    if (j == 0 && firstRecordAttendExist) { //如果首程中医师签名为主治医师,第一周查房记录也要加上
+                        indicationsNum += 1;
+                    }
+                    if (indicationsNum + threeDoctorNum < 2) {
+                        //每周无3次主治医师查房记录
+                        status.set("-1");
+                        resultInfos.add(lastWardDateRangeList.get(j));
+                    }
+                }
+
+                if (resultInfos.size() > 0) {
+                    info.set(StringUtils.join(resultInfos.toArray(), ";"));
+                }
+            }
+        }
+    }
+
+    private Date getLastRecordDate(List<ThreeLevelWardDoc> allDoctorWradDocs) {
+        ThreeLevelWardDoc threeLevelWardDoc = allDoctorWradDocs.get(allDoctorWradDocs.size() - 1);
+        Map<String, String> lastWardDocStructureMap = threeLevelWardDoc.getStructureMap();
+        String wardDateStr = lastWardDocStructureMap.get("查房日期");
+        if (StringUtil.isNotBlank(wardDateStr)) {
+            return StringUtil.parseDateTime(wardDateStr);
+        }
+        return null;
+    }
+
+
+    /**
+     * 抽取duration分钟内所有查房标题
+     * 抽取一周内所有查房标题,若一周内记录少于6天,则返回""
+     *
+     * @param threeLevelWardDocs
+     * @param admisDate
+     * @param duration
+     * @return
+     */
+    private static String extractWardRecord(InputInfo inputInfo, List<ThreeLevelWardDoc> threeLevelWardDocs, Date admisDate, int duration, Date maxRecordDate) {
+        String recordTime = "", recordTitle = "", title = "";
+        List<Date> dateList = new ArrayList();
+        for (ThreeLevelWardDoc threeLevelWardDoc : threeLevelWardDocs) {
+            Map<String, String> threeLevelWardStructureMap = threeLevelWardDoc.getStructureMap();
+            recordTime = threeLevelWardStructureMap.get("查房日期");
+            title = threeLevelWardStructureMap.get("查房标题");
+            if (StringUtil.isBlank(recordTime) || StringUtil.isBlank(title)) {
+                continue;
+            }
+            Date recordDate = StringUtil.parseDateTime(recordTime);
+            if (recordDate == null) {
+                continue;
+            }
+            /* 替换查房标题中主刀/一助的职称 */
+            List<OperationDoc> operationDocs = inputInfo.getOperationDocs();
+            if (title.contains("主刀")) {
+                String doctorTitle = CatalogueUtil.getDoctorTitle(operationDocs, recordDate, "主刀医师");
+                title = title.replace("主刀", doctorTitle);
+            } else if (title.contains("一助")) {
+                String doctorTitle = CatalogueUtil.getDoctorTitle(operationDocs, recordDate, "一助");
+                title = title.replace("一助", doctorTitle);
+            }
+            if (admisDate.before(recordDate) && !CatalogueUtil.compareTime(admisDate, recordDate, (long) duration)) {
+                recordTitle += title + ",";
+                dateList.add(recordDate);
+            }
+        }
+        if (dateList.size() > 0) {
+            //dateList.sort(Date::compareTo);
+            if (!maxRecordDate.equals(dateList.get(dateList.size() - 1)) || CatalogueUtil.compareTime(admisDate, dateList.get(dateList.size() - 1), Long.valueOf(6 * 24 * 60))) {
+                return recordTitle;
+            }
+        }
+        return "";
+    }
+
+    private boolean findfirstRecordAttend(InputInfo inputInfo) {
+        FirstCourseRecordDoc firstCourseRecordDoc = inputInfo.getFirstCourseRecordDoc();
+        if (firstCourseRecordDoc == null) {
+            return false;
+        }
+        Map<String, Map<String, Object>> hospitalDoctorMap = specialStorageUtil.getJsonStringValue(KernelConstants.HOSPITAL_DOCTOR_MAP);
+        String doctorSign = firstCourseRecordDoc.getStructureMap().get("记录医生");
+        if (hospitalDoctorMap == null || StringUtil.isBlank(doctorSign)) {
+            return false;
+        }
+        if (hospitalDoctorMap.containsKey(doctorSign)) {
+            Object professor = hospitalDoctorMap.get(doctorSign).get("professor");
+            if (professor != null) {
+                return professor.toString().contains("主治") || professor.toString().contains("主任");
+            }
+        }
+        return false;
+    }
+}

+ 76 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0134.java

@@ -0,0 +1,76 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.threelevelward;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.ward.AttendingDoctorWardDoc;
+import com.lantone.qc.pub.model.label.ThreeLevelWardLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @ClassName : THR0134
+ * @Description : 上级医师(主治医师)首次查房无初步诊断
+ * @Author : 胡敬
+ * @Date: 2020-03-23 14:16
+ */
+@Component
+public class THR0134 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getThreeLevelWardDocs().size() == 0 || inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        List<AttendingDoctorWardDoc> attendDocs = inputInfo.getThreeLevelWardDocs().get(0).getAttendingDoctorWardDocs();
+        if (attendDocs.size() == 0) {
+            status.set("0");
+            return;
+        }
+        AttendingDoctorWardDoc firstAttendDoc = attendDocs.get(0);
+        //先取结构化数据判断
+        Map<String, String> firstAttendStructureMap = firstAttendDoc.getStructureMap();
+        String admisDateStr = inputInfo.getBeHospitalizedDoc().getStructureMap().get("入院日期");
+        String recordDateStr = firstAttendStructureMap.get("查房日期");
+        String content = firstAttendStructureMap.get("病情记录");
+        if (content.contains("诊断明确") || content.contains("目前诊断") || content.contains("目前考虑") || content.contains("当前诊断") ||
+                content.contains("考虑诊断") || content.contains("诊断考虑") || content.contains("诊断基本明确") || content.contains("初步诊断") ||
+                content.contains("诊断为") || regexFind(content, "诊断", "基本明确")) {
+            status.set("0");
+            return;
+        }
+        if (CatalogueUtil.isEmpty(admisDateStr) || CatalogueUtil.isEmpty(recordDateStr)) {
+            status.set("0");
+            return;
+        }
+        //如果首次查房超过48小时则不判断该条规则
+        if (CatalogueUtil.compareTime(StringUtil.parseDateTime(admisDateStr), StringUtil.parseDateTime(recordDateStr), 48 * 60L)) {
+            status.set("0");
+            return;
+        }
+        ThreeLevelWardLabel firstAttendLabel = firstAttendDoc.getThreeLevelWardLabel();
+        if (firstAttendLabel == null) {
+            return;
+        }
+
+        if (firstAttendLabel.getDiags().size() != 0 || StringUtil.isNotBlank(firstAttendLabel.getDiagText())) {
+            status.set("0");
+        }
+    }
+
+    private boolean regexFind(String content, String... str) {
+        String s = "";
+        for (String word : str) {
+            s += word + ".*";
+        }
+        s = s.substring(0, s.lastIndexOf(".*"));
+        Pattern p = Pattern.compile(s);
+        Matcher m = p.matcher(content);
+        return m.find();
+    }
+}

+ 77 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0139.java

@@ -0,0 +1,77 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.threelevelward;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.ward.DirectorDoctorWardDoc;
+import com.lantone.qc.pub.model.label.ThreeLevelWardLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @ClassName : THR0139
+ * @Description : 上级医师(副主任医师/主任医师)首次查房无补充诊断/初步诊断/修正诊断
+ * @Author : 胡敬
+ * @Date: 2020-03-23 14:16
+ */
+@Component
+public class THR0139 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getThreeLevelWardDocs().size() == 0 || inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        List<DirectorDoctorWardDoc> directorDocs = inputInfo.getThreeLevelWardDocs().get(0).getDirectorDoctorWardDocs();
+        if (directorDocs.size() == 0) {
+            status.set("0");
+            return;
+        }
+        DirectorDoctorWardDoc firstDirectDoc = directorDocs.get(0);
+        //先取结构化数据判断
+        Map<String, String> firstDirectStructureMap = firstDirectDoc.getStructureMap();
+        String admisDateStr = inputInfo.getBeHospitalizedDoc().getStructureMap().get("入院日期");
+        String recordDateStr = firstDirectStructureMap.get("查房日期");
+        String content = firstDirectStructureMap.get("病情记录");
+        if (content.contains("诊断明确") || content.contains("目前诊断") || content.contains("目前考虑") || content.contains("当前诊断") ||
+                content.contains("考虑诊断") || content.contains("诊断考虑") || content.contains("诊断基本明确") || content.contains("初步诊断") ||
+                content.contains("诊断为") || regexFind(content, "诊断", "基本明确")) {
+            status.set("0");
+            return;
+        }
+
+        if (CatalogueUtil.isEmpty(admisDateStr) || CatalogueUtil.isEmpty(recordDateStr)) {
+            status.set("0");
+            return;
+        }
+        //如果首次查房超过72小时则不判断该条规则
+        if (CatalogueUtil.compareTime(StringUtil.parseDateTime(admisDateStr), StringUtil.parseDateTime(recordDateStr), 72 * 60L)) {
+            status.set("0");
+            return;
+        }
+        ThreeLevelWardLabel firstDirectLabel = firstDirectDoc.getThreeLevelWardLabel();
+        if (firstDirectLabel == null) {
+            return;
+        }
+
+        if (firstDirectLabel.getDiags().size() != 0 || StringUtil.isNotBlank(firstDirectLabel.getDiagText())) {
+            status.set("0");
+        }
+    }
+
+    private boolean regexFind(String content, String... str) {
+        String s = "";
+        for (String word : str) {
+            s += word + ".*";
+        }
+        s = s.substring(0, s.lastIndexOf(".*"));
+        Pattern p = Pattern.compile(s);
+        Matcher m = p.matcher(content);
+        return m.find();
+    }
+}

+ 113 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0144.java

@@ -0,0 +1,113 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.threelevelward;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.Content;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.DeathCaseDiscussDoc;
+import com.lantone.qc.pub.model.doc.DeathRecordDoc;
+import com.lantone.qc.pub.model.doc.LeaveHospitalDoc;
+import com.lantone.qc.pub.model.doc.MedicalRecordInfoDoc;
+import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
+import com.lantone.qc.pub.util.DateUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : THR0144
+ * @Description : 患者出院前无上级医师(主治及以上)同意出院的病程记录
+ * @Author : 胡敬
+ * @Date: 2020-03-19 17:20
+ */
+@Component
+public class THR0144 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+
+        MedicalRecordInfoDoc medicalRecordInfoDoc = inputInfo.getMedicalRecordInfoDoc();
+        if (medicalRecordInfoDoc != null && medicalRecordInfoDoc.getStructureMap() != null) {
+            //入院日期
+            String admisTime = medicalRecordInfoDoc.getStructureMap().get("behospitalDate");
+            //出院日期
+            String dischargeTime = medicalRecordInfoDoc.getStructureMap().get("leaveHospitalDate");
+            if (CatalogueUtil.isEmpty(admisTime) || CatalogueUtil.isEmpty(dischargeTime)) {
+                status.set("0");
+                return;
+            }
+            if (!CatalogueUtil.compareTime(
+                    StringUtil.parseDateTime(admisTime),
+                    StringUtil.parseDateTime(DateUtil.nowString()),
+                    Long.valueOf(48 * 60))) {//如果入院未超过48小时,规则不判断
+                status.set("0");
+                return;
+            }
+            //如果住院天数小于2天则不判断该条规则
+            if (DateUtil.parseDate(dischargeTime) != null &&
+                    !CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(dischargeTime), (long) (48 * 60))) {
+                status.set("0");
+                return;
+            } else {
+                if (inputInfo.getThreeLevelWardDocs().size() == 0) {
+                    return;
+                }
+            }
+        }
+
+        LeaveHospitalDoc leaveHospitalDoc = inputInfo.getLeaveHospitalDoc();
+        DeathRecordDoc deathRecordDoc = inputInfo.getDeathRecordDoc();
+        DeathCaseDiscussDoc deathCaseDiscussDoc = inputInfo.getDeathCaseDiscussDoc();
+        /* 如果没有出院小结,就不报         如果有死亡记录、死亡讨论记录,也不报 */
+        if (leaveHospitalDoc == null || deathRecordDoc != null || deathCaseDiscussDoc != null) {
+            status.set("0");
+            return;
+        }
+        List<ThreeLevelWardDoc> allDoctorWradDocs = inputInfo.getThreeLevelWardDocs().get(0).getAllDoctorWradDocs();
+        if (allDoctorWradDocs.size() == 0) {
+            status.set("0");
+            return;
+        }
+        int j = 0; //最后两次查房记录
+        Boolean lastFlag = true;
+        for (int i = allDoctorWradDocs.size() - 1; i >= 0 && j < 2; i--) {
+            j++;
+            ThreeLevelWardDoc lastWardDoc = allDoctorWradDocs.get(i);
+            Map<String, String> structureMap = lastWardDoc.getStructureMap();
+            String conditionRecord = structureMap.get("病情记录");
+            String treatmentPlan = structureMap.get("治疗计划和措施");
+            String title = structureMap.get("查房标题");
+            if (StringUtil.isBlank(title) || title.contains("病理报告")) {
+                continue;
+            }
+            conditionRecord = StringUtil.isBlank(conditionRecord) ? "" : conditionRecord;
+            conditionRecord = conditionRecord.replace(" ", "");
+            treatmentPlan = StringUtil.isBlank(treatmentPlan) ? "" : treatmentPlan;
+            //主任或主治查房 标题需要包含“主任”或“主治”,内容需要包含“出院”
+            if ((conditionRecord.contains("出院") || treatmentPlan.contains("出院") || conditionRecord.contains("转上级医院"))
+                    && (CatalogueUtil.subTitle(title).contains(Content.attend)
+                    || CatalogueUtil.subTitle(title).contains(Content.director)
+                    || CatalogueUtil.subTitle(title).contains("主刀"))) {
+                status.set("0");
+                return;
+            }
+            //普通查房 内容需要包含“上级”和“出院”
+            if (StringUtil.isBlank(title)
+                    || (title.contains("日常查房记录") || title.contains("普通查房记录") || title.contains("日常病程记录"))
+                    && conditionRecord.contains("上级")
+                    && (conditionRecord.contains("出院") || treatmentPlan.contains("出院"))) {
+                status.set("0");
+                return;
+            }
+            // 添加硬规则,最后一个记录包含“医院”或 “离院”就不报错
+            if (lastFlag == true) {
+                if (conditionRecord.contains("医院") || conditionRecord.contains("离院")) {
+                    status.set("0");
+                    return;
+                }
+                lastFlag = false;
+            }
+        }
+    }
+}

+ 134 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR02900.java

@@ -0,0 +1,134 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.threelevelward;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
+import com.lantone.qc.pub.model.doc.operation.OperationDoc;
+import com.lantone.qc.pub.model.doc.operation.OperationRecordDoc;
+import com.lantone.qc.pub.util.DateUtil;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : THR02900
+ * @Description : 术后24小时内无主刀或一助查房记录
+ * @Author : 胡敬
+ * @Date: 2020-05-27 14:23
+ */
+@Component
+public class THR02900 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getOperationDocs().size() == 0) {
+            return;
+        }
+        List<OperationDoc> operationDocs = inputInfo.getOperationDocs();
+        List<ThreeLevelWardDoc> allDoctorWradDocs = new ArrayList<>();
+        if (inputInfo.getThreeLevelWardDocs() != null && inputInfo.getThreeLevelWardDocs().size() > 0) {
+            allDoctorWradDocs = inputInfo.getThreeLevelWardDocs().get(0).getAllDoctorWradDocs();
+        }
+        //标题
+        String allTitle = "";
+        //病情记录
+        String allPathography = "";
+        String[] split = null;
+        //一助或助手
+        String firstAssistant = "";
+        //手术结束时间
+        String opeEndTime = "";
+        for (OperationDoc operationDoc : operationDocs) {
+            OperationRecordDoc operationRecordDoc = operationDoc.getOperationRecordDoc();
+            if (operationRecordDoc == null) {
+                continue;
+            }
+            Map<String, String> structureMap = operationRecordDoc.getStructureMap();
+            String opeAssName = structureMap.get("手术者及助手名称");
+            if (StringUtil.isNotBlank(opeAssName)) {
+                split = opeAssName.split("、");
+                firstAssistant = structureMap.get("助手");
+                opeEndTime = structureMap.get("手术结束时间");
+            } else {
+                firstAssistant = structureMap.get("一助");
+                //取得手术时间截取结束时间(格式 2020-07-24 10:30-2020-07-24 11:45)
+                opeEndTime = structureMap.get("手术日期");
+                if (StringUtil.isBlank(opeEndTime)) {
+                    continue;
+                }
+                String endTime = structureMap.get("结束时间");
+                if (StringUtil.isNotBlank(endTime)) {
+                    if (endTime.length() > 5) {
+                        opeEndTime = opeEndTime.substring(0, Math.min(5, opeEndTime.length())) + endTime;
+                    } else {
+                        opeEndTime = opeEndTime + " " + endTime;
+                    }
+                }
+            }
+            String chiefSurgeon = structureMap.get("主刀医师");
+            Date opeEndDate = CatalogueUtil.parseStringDate(opeEndTime);
+            if (opeEndDate == null) {
+                continue;
+            }
+            if (!CatalogueUtil.compareTime(
+                    StringUtil.parseDateTime(opeEndTime),
+                    StringUtil.parseDateTime(DateUtil.nowString()),
+                    Long.valueOf(24 * 60))) {//如果接收未超过6小时,规则不判断
+                return;
+            } else {
+                if ((StringUtil.isNotEmpty(chiefSurgeon) || StringUtil.isNotEmpty(firstAssistant)) && ListUtil.isEmpty(allDoctorWradDocs)) {
+                    status.set("-1");
+                    return;
+                }
+            }
+            if (ListUtil.isNotEmpty(allDoctorWradDocs)) {
+                for (ThreeLevelWardDoc wardDoc : allDoctorWradDocs) {
+                    Map<String, String> wardStructureMap = wardDoc.getStructureMap();
+                    String recordDateStr = wardStructureMap.get("查房日期");
+                    String recordTitle = wardStructureMap.get("查房标题");
+                    String writTitle = wardStructureMap.get("文书标题");
+                    String pathography = wardStructureMap.get("病情记录");
+                    Date recordDate = CatalogueUtil.parseStringDate(recordDateStr);
+                    if (StringUtil.isBlank(recordTitle) || StringUtil.isBlank(pathography) || recordDate == null) {
+                        continue;
+                    }
+                    if (opeEndDate.before(recordDate) && !CatalogueUtil.compareTime(opeEndDate, recordDate, 24 * 60L)) {
+                        allTitle += recordTitle;
+                        allPathography += pathography;
+                        if (StringUtil.isNotBlank(writTitle)) {
+                            allTitle += writTitle;
+                        }
+                    }
+                }
+            }
+            //查房标题中有主刀
+            if (allTitle.contains("主刀") || allTitle.contains("术后第一天") ||
+                    (StringUtil.isNotBlank(chiefSurgeon) && allTitle.contains(chiefSurgeon))) {
+                return;
+            }
+            //病情记录对比
+            if ((StringUtil.isNotBlank(chiefSurgeon) && allPathography.contains(chiefSurgeon)) ||
+                    (StringUtil.isNotBlank(firstAssistant) && allPathography.contains(firstAssistant))) {
+                return;
+            }
+            //查房标题对比
+            if (StringUtil.isNotBlank(chiefSurgeon) && !allTitle.contains(chiefSurgeon) &&
+                    StringUtil.isNotBlank(firstAssistant) && !allTitle.contains(firstAssistant)) {
+                status.set("-1");
+                return;
+            } else if (StringUtil.isBlank(chiefSurgeon) && StringUtil.isBlank(firstAssistant) && split.length > 1) {
+                for (int i = 0; i < split.length; i++) {
+                    if (allTitle.contains(split[i])) {
+                        return;
+                    }
+                }
+            }
+        }
+    }
+}

+ 68 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR02967.java

@@ -0,0 +1,68 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.threelevelward;
+
+import com.google.common.collect.Lists;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : THR02967
+ * @Description :  查房记录中查体与性别不匹配
+ * @Author : 胡敬
+ * @Date: 2020-06-13 16:13
+ */
+@Component
+public class THR02967 extends QCCatalogue {
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getBeHospitalizedDoc() == null || inputInfo.getThreeLevelWardDocs().size() == 0) {
+            return;
+        }
+        Map<String, String> beHospitalStructureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+        String gender = beHospitalStructureMap.get("性别");
+        if (StringUtil.isBlank(gender)) {
+            return;
+        }
+        List<String> noMatchWords = null;
+        if (gender.contains("男")) {
+            /* 男性不合理词 */
+            noMatchWords = Lists.newArrayList("阴道", "宫颈", "子宫", "宫底", "胎位", "胎数", "胎心",
+                    "宫缩", "宫口", "输卵管", "卵巢", "输卵管", "阴唇", "阴蒂", "阴道前庭", "前庭大腺", "处女膜");
+        } else if (gender.contains("女")) {
+            /* 女性不合理词 */
+            noMatchWords = Lists.newArrayList("睾丸", "阴茎", "精索", "包皮", "附睾", "输精管",
+                    "射精管", "尿道海绵体", "冠状沟", "精阜", "精囊腺");
+        }
+
+        if (noMatchWords == null || noMatchWords.size() == 0) {
+            return;
+        }
+        List<String> keys = Lists.newArrayList("病情记录");
+        for (ThreeLevelWardDoc threeLevelWardDoc : inputInfo.getThreeLevelWardDocs().get(0).getAllDoctorWradDocs()) {
+            Map<String, String> structureMap = threeLevelWardDoc.getStructureMap();
+            String text = CatalogueUtil.structureMapJoin(structureMap, keys);
+            for (String noMatchWord : noMatchWords) {
+                if (noMatchWord.contains("附睾") && text.contains("附睾")) {
+                    int index = text.indexOf("附睾");
+                    String substring = text.substring(Math.max(0, index - 5), Math.min(index + 7, text.length()));
+                    if (text.contains("附睾蛋白") || substring.contains("蛋白")) {
+                        continue;
+                    }
+                }
+                if (text.contains(noMatchWord)) {
+                    status.set("-1");
+                    info.set(noMatchWord);
+                    return;
+                }
+            }
+        }
+    }
+}

+ 518 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR02985.java

@@ -0,0 +1,518 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.threelevelward;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+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.LeaveHospitalDoc;
+import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
+import com.lantone.qc.pub.model.doc.consultation.ConsultationDoc;
+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.util.DateUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.time.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/**
+ * @ClassName : THR02985
+ * @Description : 医嘱有抗生素使用病程无记录
+ * 药品类型(0.普药 1.抗生素 2.激素)
+ * @Author : 胡敬
+ * @Date: 2020-06-23 10:04
+ */
+@Component
+public class THR02985 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();
+        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) {
+            return;
+        }
+
+        List<Map<String, String>> docAdvStruct = doctorAdviceDocs
+                .stream()
+                .filter(Objects::nonNull)
+                .map(DoctorAdviceDoc::getStructureMap)
+                .filter(x -> StringUtil.isNotBlank(x.get("药品类型")) && x.get("药品类型").contains("抗生素"))
+                .filter(x -> StringUtil.isNotBlank(x.get("医嘱状态判别")) && !x.get("医嘱状态判别").contains("作废"))
+                .collect(Collectors.toList());
+
+        docAdvStruct.removeIf(x -> StringUtil.isNotBlank(x.get("给药方式")) && !filterKey.contains(x.get("给药方式")));
+        //记录同一天内是否开过多次同一抗生素
+        Map<String, Map<Date, Integer>> antibioticDateTimes = Maps.newHashMap();
+        //记录同一抗生素同一天内是否开过多次,用于医嘱中需要处理的抗生素过滤(一天内同一抗生素开过多次的抗生素直接过滤)
+        getAntibioticTimes(docAdvStruct, antibioticDateTimes);
+        Map<Date, String> doctorAdviceDrugMap = Maps.newLinkedHashMap();
+        Date startDate = null;
+        for (Map<String, String> adviceDoc : docAdvStruct) {
+            String drugName = adviceDoc.get("医嘱项目名称");
+            String startDateStr = adviceDoc.get("医嘱开始时间");
+            if (StringUtil.isNotBlank(drugName)) {
+                startDate = DateUtil.dateZeroClear(StringUtil.parseDateTime(startDateStr));
+//                startDate = StringUtil.parseDateTime(startDateStr);
+                if (antibioticDateTimes.get(drugName).get(startDate) > 0) {
+                    continue;   //一天内同一抗生素开过多次的抗生素直接过滤
+                }
+                drugName = removeBracket(drugName).replaceAll("[^\u4e00-\u9fa5]", "");
+                String drugStandardWord = similarityUtil.getDrugStandardWord(drugName);
+                if (StringUtil.isNotBlank(drugStandardWord)) {
+                    drugName = drugStandardWord;
+                }
+                if (Arrays.asList(KSS).contains(drugName)) {
+                    doctorAdviceDrugMap.put(startDate, adviceDoc.get("医嘱项目名称"));
+                }
+            }
+        }
+
+        Map<String, Date> info = Maps.newLinkedHashMap();
+        Map<String, List<Drug>> infoModel = Maps.newLinkedHashMap();
+        String dateStr = null;
+        //入院记录中获取信息
+        /*if (beHospitalizedDoc != null) {
+            Map<String, String> structureMap = beHospitalizedDoc.getStructureMap();
+            getInfo(info, structureMap, "入院记录", "入院日期", "治疗计划");
+        }*/
+        //从首程治疗计划中获取信息
+        if (firstCourseRecordDoc != null) {
+            getInfo(info, firstCourseRecordDoc.getStructureMap(), "首次病程录", "病历日期", "诊疗计划");
+            if (firstCourseRecordDoc.getDrugLabel() != null) {
+                List<Drug> drugs = firstCourseRecordDoc.getDrugLabel().getDrugs();
+                dateStr = firstCourseRecordDoc.getStructureMap().get("病历日期");
+                if (StringUtil.isNotBlank(dateStr)) {
+                    getInfo(infoModel, dateStr, drugs);
+                }
+            }
+        }
+
+        //从查房记录中获取信息
+        if (threeLevelWardDocs.size() > 0) {
+            List<ThreeLevelWardDoc> allDoctorWradDocs = threeLevelWardDocs.get(0).getAllDoctorWradDocs();
+            List<ThreeLevelWardDoc> wardDocs = allDoctorWradDocs
+                    .stream()
+                    .filter(x -> StringUtil.isNotBlank(x.getStructureMap().get("查房日期")) && x.getThreeLevelWardLabel().size() > 0)
+                    .collect(Collectors.toList());
+            wardDocs.forEach(x -> getInfo(info, x.getStructureMap(), "查房记录", "查房日期", "病情记录", "治疗计划和措施"));
+            wardDocs.forEach(x -> getInfo(infoModel, x.getStructureMap().get("查房日期"), x.getThreeLevelWardLabel().get(x.getThreeLevelWardLabel().size() - 1).getDrugs()));
+        }
+        //从手术记录中获取信息
+        if (operationDocs.size() > 0) {
+            //手术记录
+            List<OperationRecordDoc> operationRecordDocs = operationDocs
+                    .stream()
+                    .map(OperationDoc::getOperationRecordDoc)
+                    .filter(Objects::nonNull)
+                    .filter(x -> x.getOperationRecordLabel() != null && StringUtil.isNotBlank(x.getStructureMap().get("病历日期")))
+                    .collect(Collectors.toList());
+            operationRecordDocs.forEach(x -> getInfo(info, x.getStructureMap(), "手术记录", "病历日期", "手术经过及处理"));
+            operationRecordDocs.forEach(x -> getInfo(infoModel, x.getStructureMap().get("病历日期"), x.getOperationRecordLabel().getDrugs()));
+            //术后首程
+            List<OperationDiscussionDoc> operationDiscussionDocs = operationDocs
+                    .stream()
+                    .map(OperationDoc::getOperationDiscussionDoc)
+                    .filter(Objects::nonNull)
+                    .filter(x -> x.getOperationDiscussionLabel() != null && StringUtil.isNotBlank(x.getStructureMap().get("病历日期")))
+                    .collect(Collectors.toList());
+            operationDiscussionDocs.forEach(x -> getInfo(info, x.getStructureMap(), "术后首程", "病历日期", "手术简要经过", "术后处理措施"));
+            operationDiscussionDocs.forEach(x -> getInfo(infoModel, x.getStructureMap().get("病历日期"), x.getOperationDiscussionLabel().getDrugs()));
+        }
+
+        //从会诊记录中获取信息
+        /*if (consultationDocs.size() > 0) {
+            List<ConsultationResultsDoc> consultationResultsDocs = consultationDocs
+                    .stream()
+                    .map(ConsultationDoc::getConsultationResultsDoc)
+                    .filter(Objects::nonNull)
+                    .filter(x -> x.getConsultationResultLabel() != null && StringUtil.isNotBlank(x.getStructureMap().get("会诊日期及时间")))
+                    .collect(Collectors.toList());
+            consultationResultsDocs.forEach(x -> getInfo(info, x.getStructureMap(), "会诊结果单", "会诊日期及时间", "会诊意见"));
+            consultationResultsDocs.forEach(x -> getInfo(infoModel, x.getStructureMap().get("会诊日期及时间"), x.getConsultationResultLabel().getDrugs()));
+        }*/
+
+        //从出院小结中获取信息
+        if (leaveHospitalDoc != null) {
+            if (inputInfo.getMedicalRecordInfoDoc() != null) {
+                Map<String, String> medicalRecordInfoStructureMap = inputInfo.getMedicalRecordInfoDoc().getStructureMap();
+                dateStr = medicalRecordInfoStructureMap.get("leaveHospitalDate");
+                //如果存在出院小结,出院日期为空,存储系统当前时间
+                if (StringUtil.isBlank(dateStr)) {
+                    dateStr = DateUtil.formatDateTime(new Date());
+                }
+            }
+            if (StringUtil.isNotBlank(dateStr)) {
+                if (leaveHospitalDoc.getLeaveHospitalLabel() != null) {
+                    List<Drug> drugs = leaveHospitalDoc.getLeaveHospitalLabel().getDrugs();
+                    getDischargeInfo(info, leaveHospitalDoc.getStructureMap(), "出院小结", dateStr, "诊治经过");
+                    getInfo(infoModel, dateStr, drugs);
+                }
+            }
+        }
+
+        StringBuffer sb = new StringBuffer();
+        Map<Object, Object> data = Maps.newHashMap();
+        Set<String> existDrug = Sets.newHashSet();
+        String infoStr = "";
+        for (Map.Entry<Date, String> doctorAdviceDrug : doctorAdviceDrugMap.entrySet()) {
+            Date doctorAdviceDate = doctorAdviceDrug.getKey();
+            String drugs = doctorAdviceDrug.getValue();
+            if (drugs.contains(" ")) {
+                drugs = drugs.split(" ")[0];
+            }
+//            drugs = removeBracket(drugs).replaceAll("[^\u4e00-\u9fa5]", "");
+            Set<String> splitDrugs = CatalogueUtil.getRegexWords(drugs, "[((\\[][^\\[\\]()()]+[\\]))]")
+                    .stream().filter(x -> !x.equals("合资") && !x.equals("进口") && !x.equals("国产")).collect(Collectors.toSet());
+            /**********************************************先文本匹配************************************************/
+            String missDrug = "";
+            for (Map.Entry<String, Date> map : info.entrySet()) {
+                missDrug = getMissDrug(map.getKey(), map.getValue(), doctorAdviceDate, splitDrugs, 2, missDrug, existDrug);
+                //当前抗生素药(drugs)在info中已找到,直接跳出当前循环
+                if (StringUtil.isBlank(missDrug)) {
+                    break;
+                }
+            }
+            if (StringUtil.isBlank(missDrug)) {
+                continue;
+            }
+            /**********************************************文本匹配没有找到药,再走模型************************************************/
+            boolean modelFind = false;
+            for (Map.Entry<String, List<Drug>> modelMap : infoModel.entrySet()) {
+                dateStr = modelMap.getKey();
+                List<Drug> diags = modelMap.getValue();
+                Date date = StringUtil.parseDateTime(dateStr);
+                //医嘱开始时间往后2天或往前一天找药
+                if ((doctorAdviceDate.before(date) && !CatalogueUtil.compareTime(doctorAdviceDate, date, 48 * 60L))
+                        || (date.before(doctorAdviceDate) && !CatalogueUtil.compareTime(date, doctorAdviceDate, 24 * 60L))) {
+                    for (String adDrug : splitDrugs) {
+                        for (Drug courseDrug : diags) {
+                            if (compareStandard(courseDrug.getName(), adDrug)) {
+                                modelFind = true;
+                                break;
+                            }
+                        }
+                    }
+                }
+                if (modelFind) {
+                    break;
+                }
+            }
+
+            if (StringUtil.isNotBlank(missDrug) && !modelFind && CatalogueUtil.compareTime(doctorAdviceDate, new Date(), 48 * 60L)) {
+                infoAppend(sb, drugs, DateUtil.formatDateTime(doctorAdviceDate));
+                data.put(doctorAdviceDate, splitDrugs.toString().replaceAll("[\\[\\]]", ""));
+            }
+        }
+        if (StringUtil.isNotBlank(sb.toString())) {
+            this.status.set("-1");
+            this.info.set("医嘱:" + sb.toString().substring(0, sb.toString().length() - 1));
+            extData.set(data);
+        }
+    }
+
+    /**
+     * 记录同一抗生素同一天内是否开过多次,用于医嘱中需要处理的抗生素过滤(一天内同一抗生素开过多次的抗生素直接过滤)
+     *
+     * @param docAdvStruct
+     * @param antibioticDateTimes
+     */
+    private void getAntibioticTimes(List<Map<String, String>> docAdvStruct, Map<String, Map<Date, Integer>> antibioticDateTimes) {
+        String drugName;
+        String startDateStr;
+        Date startDate;
+        Map<Date, Integer> antibioticDateTime;
+        for (Map<String, String> structMap : docAdvStruct) {
+            drugName = structMap.get("医嘱项目名称");
+            startDateStr = structMap.get("医嘱开始时间");
+            startDate = DateUtil.dateZeroClear(StringUtil.parseDateTime(startDateStr));
+//            startDate = StringUtil.parseDateTime(startDateStr);
+            if (antibioticDateTimes.containsKey(drugName)) {
+                Map<Date, Integer> map = antibioticDateTimes.get(drugName);
+                if (map.containsKey(startDate)) {
+                    map.put(startDate, map.get(startDate) + 1);
+                } else {
+                    map.put(startDate, 0);
+                }
+            } else {
+                antibioticDateTime = Maps.newHashMap();
+                antibioticDateTime.put(startDate, 0);
+                antibioticDateTimes.put(drugName, antibioticDateTime);
+            }
+        }
+    }
+
+    /**
+     * 获取各模块信息<入院记录、首次病程录、手术记录、术后首程、会诊结果单、查房记录>
+     *
+     * @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 structureMap
+     * @param info
+     */
+    private void getDischargeInfo(Map<String, Date> info, Map<String, String> structureMap, String modelType, String dateStr, String... contentKey) {
+        String content = CatalogueUtil.structureMapJoin(structureMap, Lists.newArrayList(contentKey));
+        if (StringUtil.isNotBlank(dateStr)) {
+            Date date = StringUtil.parseDateTime(dateStr);
+            if (StringUtil.isNotBlank(content) && date != null) {
+                info.put(modelType + "->" + content, date);
+            }
+        }
+    }
+
+    private void getInfo(Map<String, List<Drug>> info, String dateKey, List<Drug> drugs) {
+        List<Drug> tempDrugs = new ArrayList<>();
+        if (null != drugs && drugs.size() > 0) {
+            for (Drug drug : drugs) {
+                if (null != drug.getConsumption() && !drug.getConsumption().getName().contains("mg/Kg")) {
+                    tempDrugs.add(drug);
+                }
+            }
+        }
+        if (info.containsKey(dateKey)) {
+            info.get(dateKey).addAll(tempDrugs);
+        } else {
+            info.put(dateKey, tempDrugs);
+        }
+    }
+
+    /**
+     * 核心:从文本中找药
+     *
+     * @param content          文本
+     * @param wardDate
+     * @param doctorAdviceDate
+     * @param drugs
+     * @param days
+     * @return 如果文本中找到该药,则返回空字符串
+     */
+    private String getMissDrug(String content, Date wardDate, Date doctorAdviceDate, Set<String> drugs, int days, String missDrug, Set<String> existDrug) {
+        if ("时间不匹配".equals(missDrug)) {
+            missDrug = "";//初始化缺失药物
+        }
+        //开医嘱时间起,昨天今天明天记录内查找药
+        if ((doctorAdviceDate.before(wardDate) && !CatalogueUtil.compareTime(doctorAdviceDate, wardDate, days * 24 * 60L))
+                || (wardDate.before(doctorAdviceDate) && !CatalogueUtil.compareTime(wardDate, doctorAdviceDate, 24 * 60L)) ||
+                DateUtils.isSameDay(wardDate, doctorAdviceDate)) {
+            boolean findDrug = false;
+            String standardDrug = null;
+            for (String drug : drugs) {
+                if (StringUtil.isBlank(drug)) {
+                    continue;
+                }
+                drug = drug.replaceAll("[^\\u4e00-\\u9fa5]", "");
+                standardDrug = similarityUtil.getDrugStandardWord(drug);
+                if (content.contains(drug) || (StringUtil.isNotBlank(content) && StringUtil.isNotBlank(standardDrug) && content.contains(standardDrug))
+                        || (existDrug.contains(drug) && (regexFind(content, "继续", "治疗") || regexFind(content, "维持", "治疗")
+                        || regexFind(content, "继续", "抗感染") || regexFind(content, "治疗", "同前") || regexFind(content, "治疗同前")))) {
+                    findDrug = true;
+                    existDrug.add(drug);
+                    break;
+                } else {
+                    missDrug = concatInfo(missDrug, drug);
+                }
+            }
+            if (findDrug) {
+                missDrug = "";//如果找到一种抗生素药,就把报错信息置为空
+            }
+        } else {
+            if (StringUtil.isBlank(missDrug)) {
+                missDrug = "时间不匹配";
+            }
+        }
+        return missDrug;
+    }
+
+    private String concatInfo(String infoStr, String content) {
+        if (StringUtil.isBlank(infoStr)) {
+            infoStr += content;
+        } else {
+            if (!infoStr.contains(content)) {
+                infoStr += "或" + content;
+            }
+        }
+        return infoStr;
+    }
+
+    private boolean regexFind(String content, String... str) {
+        String s = "";
+        for (String word : str) {
+            s += word + ".*";
+        }
+        s = s.substring(0, s.lastIndexOf(".*"));
+        Pattern p = Pattern.compile(s);
+        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;
+    }
+
+    /**
+     * 拼接提示信息
+     *
+     * @param sb
+     * @param drugKey
+     * @param date
+     */
+    private void infoAppend(StringBuffer sb, String drugKey, String date) {
+        sb.append(drugKey).append("(").append(date).append(")").append("_");
+    }
+
+    private static final List<String> filterKey = Lists.newArrayList("ACF", "ID", "IG", "IM", "IP", "IV",
+            "关节腔注射", "宫颈注射", "皮下注射", "皮下注射(儿童)", "皮下注射(免费)", "皮下注射(成人)", "皮内", "皮内注射",
+            "结膜下注射", "肌注", "肌肉注射(儿童)", "肌肉注射(公卫专用)", "肌肉注射(成人)", "胸腔注射", "腹腔内注射", "腹腔注射",
+            "静滴(儿童)", "静滴(成人)", "静脉注射", "静脉注射(儿童)", "静脉注射(免费)", "静脉注射(成人)", "静脉注射(泵)",
+            "静脉滴注", "静脉滴注(泵)", "鞘内注射", "微泵");
+
+    private static final String[] KSS = {
+            "万古霉素",
+            "两性霉素B",
+            "亚胺培南西司他丁",
+            "伊曲康唑",
+            "伏立康唑",
+            "依替米星",
+            "克拉霉素",
+            "克林霉素",
+            "利奈唑胺",
+            "利奈唑胺葡萄糖",
+            "利福昔明",
+            "制霉菌素",
+            "卡泊芬净",
+            "厄他培南",
+            "吗啉硝唑",
+            "呋喃唑酮",
+            "哌拉西林他唑巴坦",
+            "磺胺甲恶唑",
+            "多粘菌素B",
+            "多西环素",
+            "夫西地酸",
+            "头孢丙烯",
+            "头孢他啶",
+            "头孢他啶阿维巴坦",
+            "头孢他美酯",
+            "头孢克洛",
+            "头孢克肟",
+            "头孢吡肟",
+            "头孢呋辛",
+            "头孢哌酮舒巴坦",
+            "头孢唑林",
+            "头孢噻肟",
+            "头孢地嗪",
+            "头孢地尼",
+            "头孢拉定",
+            "头孢曲松",
+            "头孢替安",
+            "头孢美唑",
+            "头孢西丁",
+            "奥硝唑",
+            "妥布霉素",
+            "妥布霉素地塞米松",
+            "左氧氟沙星",
+            "左氧氟沙星",
+            "庆大霉素",
+            "异帕米星",
+            "拉氧头孢",
+            "替加环素",
+            "替硝唑",
+            "替考拉宁",
+            "比阿培南",
+            "氟康唑",
+            "氟康唑",
+            "氟胞嘧啶",
+            "氨曲南",
+            "氨苄西林",
+            "泊沙康唑",
+            "特比萘芬",
+            "甲硝唑",
+            "甲硝唑",
+            "磷霉素",
+            "磷霉素氨丁三醇",
+            "米卡芬净",
+            "米诺环素",
+            "红霉素",
+            "美罗培南",
+            "苄星青霉素",
+            "莫西沙星",
+            "莫西沙星",
+            "达托霉素",
+            "阿奇霉素",
+            "阿奇霉素枸橼酸二氢钠",
+            "阿洛西林",
+            "阿米卡星",
+            "阿莫西林",
+            "阿莫西林克拉维酸",
+            "青霉素"
+    };
+}

+ 77 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR03015.java

@@ -0,0 +1,77 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.threelevelward;
+
+import com.lantone.qc.dbanaly.util.KernelConstants;
+import com.lantone.qc.dbanaly.util.SpecialStorageUtil;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
+import com.lantone.qc.pub.model.doc.ward.DirectorDoctorWardDoc;
+import com.lantone.qc.pub.util.SpringContextUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : THR03015
+ * @Description : 主任查房记录无审核  1/次(超过一周)
+ * @Author : 胡敬
+ * @Date: 2020-03-25 10:21
+ */
+@Component
+public class THR03015 extends QCCatalogue {
+
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getLeaveHospitalDoc() == null || inputInfo.getThreeLevelWardDocs().size() == 0) {
+            return;
+        }
+        Map<String, String> leaveHospitalStructureMap = inputInfo.getLeaveHospitalDoc().getStructureMap();
+        String lengthOfStay = leaveHospitalStructureMap.get("住院天数");
+        if (StringUtil.isNotBlank(lengthOfStay) && CatalogueUtil.numbersOnly(lengthOfStay)) {
+            //如果住院天数小于7天则不判断该条规则
+            if (Integer.parseInt(lengthOfStay) <= 7) {
+                return;
+            }
+        }
+
+        boolean findIndications = true;
+        ThreeLevelWardDoc threeLevelWardDoc = inputInfo.getThreeLevelWardDocs().get(0);
+        List<DirectorDoctorWardDoc> directorDoctorWardDocs = threeLevelWardDoc.getDirectorDoctorWardDocs();
+        String jlDateStr, shDateStr, professor;
+        for (DirectorDoctorWardDoc directorDoctorWardDoc : directorDoctorWardDocs) {
+            jlDateStr = directorDoctorWardDoc.getStructureMap().get("病历日期");
+            shDateStr = directorDoctorWardDoc.getStructureMap().get("审核日期");
+            professor = getProfessor(directorDoctorWardDoc.getStructureMap().get("审核人"));
+            if (StringUtil.isBlank(professor)
+                    || !professor.contains("主任")
+                    || CatalogueUtil.compareTime(StringUtil.parseDateTime(jlDateStr), StringUtil.parseDateTime(shDateStr), 7 * 24 * 60L)) {
+                findIndications = false;
+                break;
+            }
+        }
+        if (!findIndications) {
+            status.set("-1");
+        }
+    }
+
+    private String getProfessor(String doctorSign) {
+        String professor = "";
+        if (StringUtil.isBlank(doctorSign)) {
+            return professor;
+        }
+        SpecialStorageUtil specialStorageUtil = SpringContextUtil.getBean("specialStorageUtil");
+        Map<String, Map<String, String>> surgeon = specialStorageUtil.getJsonStringValue(KernelConstants.HOSPITAL_DOCTOR_MAP);
+        if (surgeon != null) {
+            Map<String, String> doctor = (Map) surgeon.get(doctorSign);
+            if (doctor != null) {
+                professor = doctor.get("professor");
+            }
+        }
+        return professor;
+    }
+
+}

+ 56 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR03017.java

@@ -0,0 +1,56 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.threelevelward;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
+import com.lantone.qc.pub.model.doc.ward.AttendingDoctorWardDoc;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : THR03017
+ * @Description : 主治查房记录无审核
+ * @Author : 胡敬
+ * @Date: 2020-03-25 10:21
+ */
+@Component
+public class THR03017 extends QCCatalogue {
+
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getLeaveHospitalDoc() == null || inputInfo.getThreeLevelWardDocs().size() == 0) {
+            return;
+        }
+        Map<String, String> leaveHospitalStructureMap = inputInfo.getLeaveHospitalDoc().getStructureMap();
+        String lengthOfStay = leaveHospitalStructureMap.get("住院天数");
+        if (StringUtil.isNotBlank(lengthOfStay) && CatalogueUtil.numbersOnly(lengthOfStay)) {
+            //如果住院天数小于2天则不判断该条规则
+            if (Integer.parseInt(lengthOfStay) <= 2) {
+                return;
+            }
+        }
+
+        boolean findIndications = true;
+        ThreeLevelWardDoc threeLevelWardDoc = inputInfo.getThreeLevelWardDocs().get(0);
+        List<AttendingDoctorWardDoc> attendingDoctorWardDocs = threeLevelWardDoc.getAttendingDoctorWardDocs();
+        String jlDateStr, shDateStr, professor;
+        for (AttendingDoctorWardDoc attendingDoctorWardDoc : attendingDoctorWardDocs) {
+            jlDateStr = attendingDoctorWardDoc.getStructureMap().get("病历日期");
+            shDateStr = attendingDoctorWardDoc.getStructureMap().get("审核日期");
+            if (!CatalogueUtil.isOccup(attendingDoctorWardDoc.getStructureMap().get("审核人"))
+                    || CatalogueUtil.compareTime(StringUtil.parseDateTime(jlDateStr), StringUtil.parseDateTime(shDateStr), 48 * 60L)) {
+                findIndications = false;
+                break;
+            }
+        }
+        if (!findIndications) {
+            status.set("-1");
+        }
+    }
+
+}

+ 342 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR03076.java

@@ -0,0 +1,342 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.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.FirstCourseRecordDoc;
+import com.lantone.qc.pub.model.doc.LeaveHospitalDoc;
+import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
+import com.lantone.qc.pub.model.doc.consultation.ConsultationDoc;
+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.DrugLabel;
+import com.lantone.qc.pub.model.label.LeaveHospitalLabel;
+import com.lantone.qc.pub.model.label.ThreeLevelWardLabel;
+import com.lantone.qc.pub.util.DateUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.time.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+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();
+        FirstCourseRecordDoc firstCourseRecordDoc = inputInfo.getFirstCourseRecordDoc();
+        List<ConsultationDoc> consultationDocs = inputInfo.getConsultationDocs();
+        List<OperationDoc> operationDocs = inputInfo.getOperationDocs();
+        LeaveHospitalDoc leaveHospitalDoc = inputInfo.getLeaveHospitalDoc();
+        if (doctorAdviceDocs.size() == 0) {
+            return;
+        }
+
+        Map<Date, String> extData = null;
+        if (outputInfo.getResult().get("THR02985") != null) {
+            extData = (Map<Date, String>) outputInfo.getResult().get("THR02985").get("extData");
+        }
+
+        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("医嘱单次剂量")))
+                .filter(x -> StringUtil.isNotBlank(x.get("医嘱状态判别")) && !x.get("医嘱状态判别").contains("作废"))
+                .collect(Collectors.toList());
+        docAdvStruct.removeIf(x -> StringUtil.isNotBlank(x.get("给药方式")) && !filterKey.contains(x.get("给药方式")));
+
+        //抗生素及开医嘱时间 <抗生素名,<抗生素用量,[抗生素使用时间...]>>
+        Map<String, Map<String, List<Double>>> antibioticInfo = Maps.newLinkedHashMap();
+        Map<String, Map<Date, Integer>> antibioticDateTimes = Maps.newHashMap();
+        //记录同一抗生素同一天内是否开过多次,用于医嘱中需要处理的抗生素过滤(一天内同一抗生素开过多次的抗生素直接过滤)
+        getAntibioticTimes(docAdvStruct, antibioticDateTimes);
+        String drugName = null, value = null, startDateStr = null;
+        Date startDate = null;
+        for (Map<String, String> structMap : docAdvStruct) {
+            drugName = structMap.get("医嘱项目名称");
+            value = structMap.get("医嘱单次剂量");
+            startDateStr = structMap.get("医嘱开始时间");
+            startDate = DateUtil.dateZeroClear(StringUtil.parseDateTime(startDateStr));
+//            startDate = StringUtil.parseDateTime(startDateStr);
+            if (extData != null && extData.containsKey(startDate) && extData.get(startDate).equals(drugName)) {
+                continue;   //THR02985  医嘱有抗生素使用病程无记录,规则中没报未记录的抗生素继续走这条规则,报未记录的抗生素过滤
+            }
+            if (antibioticDateTimes.get(drugName).get(startDate) > 0) {
+                continue;   //一天内同一抗生素开过多次的抗生素直接过滤
+            }
+            collectAntibioticInfo(antibioticInfo, drugName, value, startDateStr);
+        }
+
+        //抗生素及开医嘱时间 <抗生素名,<抗生素用量,[抗生素使用时间...]>>
+        Map<String, Map<String, List<Double>>> antibioticWardInfo = Maps.newLinkedHashMap();
+        String dateStr = null;
+        /*********************************************首程治疗计划********************************************************/
+        if (firstCourseRecordDoc != null) {
+            DrugLabel drugLabel = firstCourseRecordDoc.getDrugLabel();
+            dateStr = firstCourseRecordDoc.getStructureMap().get("病历日期");
+            if (drugLabel != null && StringUtil.isNotBlank(dateStr)) {
+                List<Drug> drugs = drugLabel.getDrugs();
+                getCourseDrugInfo(antibioticWardInfo, drugs, dateStr);
+            }
+        }
+        /*********************************************查房记录********************************************************/
+        if (threeLevelWardDocs.size() > 0) {
+            List<ThreeLevelWardDoc> allDoctorWradDocs = threeLevelWardDocs.get(0).getAllDoctorWradDocs();
+            for (ThreeLevelWardDoc doc : allDoctorWradDocs) {
+                if (doc.getThreeLevelWardLabel().size() == 0) {
+                    continue;
+                }
+                dateStr = doc.getStructureMap().get("查房日期");
+                ThreeLevelWardLabel label = doc.getThreeLevelWardLabel().get(0);
+                List<Drug> drugs = label.getDrugs();
+                getCourseDrugInfo(antibioticWardInfo, drugs, dateStr);
+            }
+        }
+        /**********************************************手术记录、术后首程************************************************/
+        if (operationDocs.size() > 0) {
+            //手术记录
+            List<OperationRecordDoc> operationRecordDocs = operationDocs
+                    .stream()
+                    .map(OperationDoc::getOperationRecordDoc)
+                    .filter(Objects::nonNull)
+                    .filter(x -> x.getOperationRecordLabel() != null && StringUtil.isNotBlank(x.getStructureMap().get("病历日期")))
+                    .collect(Collectors.toList());
+            operationRecordDocs.forEach(x -> getCourseDrugInfo(antibioticWardInfo, x.getOperationRecordLabel().getDrugs(), x.getStructureMap().get("病历日期")));
+            List<OperationDiscussionDoc> operationDiscussionDocs = operationDocs
+                    .stream()
+                    .map(OperationDoc::getOperationDiscussionDoc)
+                    .filter(Objects::nonNull)
+                    .filter(x -> x.getOperationDiscussionLabel() != null && StringUtil.isNotBlank(x.getStructureMap().get("病历日期")))
+                    .collect(Collectors.toList());
+            operationDiscussionDocs.forEach(x -> getCourseDrugInfo(antibioticWardInfo, x.getOperationDiscussionLabel().getDrugs(), x.getStructureMap().get("病历日期")));
+        }
+        /*********************************************会诊结果单********************************************************/
+        /*if (consultationDocs.size() > 0) {
+            List<ConsultationResultsDoc> consultationResultsDocs = consultationDocs
+                    .stream()
+                    .map(ConsultationDoc::getConsultationResultsDoc)
+                    .filter(Objects::nonNull)
+                    .filter(x -> x.getConsultationResultLabel() != null && StringUtil.isNotBlank(x.getStructureMap().get("会诊日期及时间")))
+                    .collect(Collectors.toList());
+            consultationResultsDocs.forEach(x -> getCourseDrugInfo(antibioticWardInfo, x.getConsultationResultLabel().getDrugs(), x.getStructureMap().get("会诊日期及时间")));
+        }*/
+        /*********************************************出院小结********************************************************/
+        if (leaveHospitalDoc != null) {
+            LeaveHospitalLabel leaveHospitalLabel = leaveHospitalDoc.getLeaveHospitalLabel();
+            if (inputInfo.getMedicalRecordInfoDoc() != null) {
+                Map<String, String> medicalRecordInfoStructureMap = inputInfo.getMedicalRecordInfoDoc().getStructureMap();
+                dateStr = medicalRecordInfoStructureMap.get("leaveHospitalDate");
+                //如果存在出院小结,出院日期为空,存储系统当前时间
+                if (StringUtil.isBlank(dateStr)) {
+                    dateStr = DateUtil.formatDateTime(new Date());
+                }
+            }
+            if (leaveHospitalLabel != null && StringUtil.isNotBlank(dateStr)) {
+                List<Drug> drugs = leaveHospitalLabel.getDrugs();
+                getCourseDrugInfo(antibioticWardInfo, drugs, dateStr);
+            }
+        }
+
+        /**
+         * 1.医嘱中开了抗生素,查房记录中没有该抗生素,则医嘱中该抗生素出现过的所有时间都会提示出来
+         * 2.医嘱中开了抗生素,查房记录中有该抗生素:
+         *      2.1 医嘱中该抗生素某使用量(如50),查房记录中没有该使用量(如只有100),则医嘱中该抗生素使用量出现过的所有时间都会提示出来
+         *      2.2 医嘱中该抗生素某使用量(如50),查房记录中也有该使用量,对比这两个时间,若医嘱时间两天内的查房记录没有该使用量,则该医嘱时间会提示出来
+         */
+        StringBuffer sb = new StringBuffer();
+        String drugKey = null;
+        for (Map.Entry<String, Map<String, List<Double>>> ai : antibioticInfo.entrySet()) {
+            drugKey = ai.getKey();
+            drugKey = removeBracket(drugKey).replaceAll("[^\u4e00-\u9fa5]", "");
+            String drugStandardWord = similarityUtil.getDrugStandardWord(drugKey);
+            if (StringUtil.isNotBlank(drugStandardWord)) {
+                drugKey = drugStandardWord;
+            }
+            if (antibioticWardInfo.containsKey(drugKey)) {
+                Map<String, List<Double>> adDateValue = ai.getValue();
+                Map<String, List<Double>> wardDateValue = antibioticWardInfo.get(drugKey);
+                for (Map.Entry<String, List<Double>> adMap : adDateValue.entrySet()) {
+                    String adDateStr = adMap.getKey();
+                    Date adDate = StringUtil.parseDateTime(adDateStr);
+                    List<Double> adUsage = adMap.getValue();
+                    for (Map.Entry<String, List<Double>> wdvMap : wardDateValue.entrySet()) {
+                        StringBuffer innersb = new StringBuffer();
+                        String wardDateStr = wdvMap.getKey();
+                        Date wardDate = StringUtil.parseDateTime(wardDateStr);
+                        List<Double> wardUsage = wdvMap.getValue();
+                        if ((adDate.before(wardDate) && !CatalogueUtil.compareTime(adDate, wardDate, 48 * 60L))
+                                || (wardDate.before(adDate) && !CatalogueUtil.compareTime(wardDate, adDate, 24 * 60L)) ||
+                                DateUtils.isSameDay(wardDate, adDate)) {
+                            wardUsage.removeAll(adUsage);//比如adUsage有1.0、2.0,wardUsage中有2.0、3.0,removeAll之后wardUsage只剩3.0
+                            adDateStr = DateUtil.formatDateTime(adDate);
+                            if (wardUsage.size() > 0 && !sb.toString().contains(ai.getKey() + "(" + adDateStr + ")")) {
+                                infoAppend(innersb, ai.getKey(), adDateStr);
+                            }
+                            if(wardUsage.size() == 0){
+                                innersb.delete(0,innersb.length());
+                                break;
+                            }
+                        }
+                        sb.append(innersb);
+                    }
+                }
+            }
+        }
+
+        if (sb.toString().length() > 0) {
+            status.set("-1");
+            info.set("医嘱:" + sb.toString().substring(0, sb.toString().length() - 1));
+        }
+    }
+
+    /**
+     * 记录同一抗生素同一天内是否开过多次,用于医嘱中需要处理的抗生素过滤(一天内同一抗生素开过多次的抗生素直接过滤)
+     *
+     * @param docAdvStruct
+     * @param antibioticDateTimes
+     */
+    private void getAntibioticTimes(List<Map<String, String>> docAdvStruct, Map<String, Map<Date, Integer>> antibioticDateTimes) {
+        String drugName;
+        String startDateStr;
+        Date startDate;
+        Map<Date, Integer> antibioticDateTime;
+        for (Map<String, String> structMap : docAdvStruct) {
+            drugName = structMap.get("医嘱项目名称");
+            startDateStr = structMap.get("医嘱开始时间");
+            startDate = DateUtil.dateZeroClear(StringUtil.parseDateTime(startDateStr));
+//            startDate = StringUtil.parseDateTime(startDateStr);
+            if (antibioticDateTimes.containsKey(drugName)) {
+                Map<Date, Integer> map = antibioticDateTimes.get(drugName);
+                if (map.containsKey(startDate)) {
+                    map.put(startDate, map.get(startDate) + 1);
+                } else {
+                    map.put(startDate, 0);
+                }
+            } else {
+                antibioticDateTime = Maps.newHashMap();
+                antibioticDateTime.put(startDate, 0);
+                antibioticDateTimes.put(drugName, antibioticDateTime);
+            }
+        }
+    }
+
+    private void getCourseDrugInfo(Map<String, Map<String, List<Double>>> antibioticWardInfo, List<Drug> drugs, String dateStr) {
+        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, dateStr);
+            }
+        }
+    }
+
+    /**
+     * 拼接提示信息
+     *
+     * @param sb
+     * @param drugKey
+     * @param date
+     */
+    private void infoAppend(StringBuffer sb, String drugKey, String date) {
+        sb.append(drugKey).append("(").append(date).append(")").append("_");
+    }
+
+    /**
+     * 收集抗生素各种信息
+     *
+     * @param antibioticInfo 抗生素使用量及所有时间
+     * @param drugName       抗生素名称
+     * @param value          抗生素用量
+     * @param startDateStr   抗生素使用时间(医嘱开始时间或查房时间)
+     */
+    private void collectAntibioticInfo(Map<String, Map<String, List<Double>>> antibioticInfo, String drugName, String value, String startDateStr) {
+        Map<String, List<Double>> 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 (v > 100) {
+            v = v / 1000;
+        }
+        if (!antibioticInfo.containsKey(drugName)) {
+            //存该抗生素使用第1个值
+            antibioticValueList = Maps.newLinkedHashMap();
+            antibioticValueList.put(startDateStr, Lists.newArrayList(v));
+            antibioticInfo.put(drugName, antibioticValueList);
+        } else {
+            antibioticValueList = antibioticInfo.get(drugName);
+            //存该抗生素使用时间时第n个量
+            if (antibioticValueList.containsKey(startDateStr)) {
+                antibioticValueList.get(startDateStr).add(v);
+            } else {
+                //存该抗生素使用时间时第1个量
+                antibioticValueList.put(startDateStr, Lists.newArrayList(v));
+            }
+        }
+    }
+
+    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;
+    }
+
+    private static final List<String> filterKey = Lists.newArrayList("ACF", "ID", "IG", "IM", "IP", "IV",
+            "关节腔注射", "宫颈注射", "皮下注射", "皮下注射(儿童)", "皮下注射(免费)", "皮下注射(成人)", "皮内", "皮内注射",
+            "结膜下注射", "肌注", "肌肉注射(儿童)", "肌肉注射(公卫专用)", "肌肉注射(成人)", "胸腔注射", "腹腔内注射", "腹腔注射",
+            "静滴(儿童)", "静滴(成人)", "静脉注射", "静脉注射(儿童)", "静脉注射(免费)", "静脉注射(成人)", "静脉注射(泵)",
+            "静脉滴注", "静脉滴注(泵)", "鞘内注射", "微泵");
+
+}

+ 603 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR03077.java

@@ -0,0 +1,603 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.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.FirstCourseRecordDoc;
+import com.lantone.qc.pub.model.doc.LeaveHospitalDoc;
+import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
+import com.lantone.qc.pub.model.doc.consultation.ConsultationDoc;
+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.DrugLabel;
+import com.lantone.qc.pub.model.label.ThreeLevelWardLabel;
+import com.lantone.qc.pub.util.DateUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.time.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Date;
+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-28 14:10
+ * @desc 病程中抗生素记录不规范
+ **/
+@Component
+public class THR03077 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();
+        FirstCourseRecordDoc firstCourseRecordDoc = inputInfo.getFirstCourseRecordDoc();
+        List<ConsultationDoc> consultationDocs = inputInfo.getConsultationDocs();
+        List<OperationDoc> operationDocs = inputInfo.getOperationDocs();
+        LeaveHospitalDoc leaveHospitalDoc = inputInfo.getLeaveHospitalDoc();
+        if (doctorAdviceDocs.size() == 0) {
+            return;
+        }
+        Map<Date, String> extData = null;
+        if (outputInfo.getResult().get("THR02985") != null) {
+            extData = (Map<Date, String>) outputInfo.getResult().get("THR02985").get("extData");
+        }
+
+        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("医嘱单次剂量")))
+                .filter(x -> StringUtil.isNotBlank(x.get("医嘱状态判别")) && !x.get("医嘱状态判别").contains("作废"))
+                .collect(Collectors.toList());
+        docAdvStruct.removeIf(x -> StringUtil.isNotBlank(x.get("给药方式")) && !filterKey.contains(x.get("给药方式")));
+
+        //抗生素及开医嘱时间(包括加用过抗生素的时间)     key:抗生素名    "2020-08-20,2020-08-21 ..."
+        Map<String, List<String>> antibioticDate = Maps.newHashMap();
+        //抗生素加用集合   key:抗生素名    value:  0:未加用,1及以上:加用次数
+        Map<String, Integer> antibioticStatus = Maps.newHashMap();
+        //抗生素及各初始剂量     key:抗生素名    value:抗生素第一次使用时剂量
+        Map<String, List<Double>> antibioticValue = Maps.newHashMap();
+        //记录同一天内是否开过多次同一抗生素
+        Map<String, Map<Date, Integer>> antibioticDateTimes = Maps.newHashMap();
+        String drugName = null, value = null, startDateStr = null;
+        Date startDate = null;
+        getAntibioticTimes(docAdvStruct, antibioticDateTimes);
+        for (Map<String, String> structMap : docAdvStruct) {
+            drugName = structMap.get("医嘱项目名称");
+            value = structMap.get("医嘱单次剂量");
+            startDateStr = structMap.get("医嘱开始时间");
+            startDate = DateUtil.dateZeroClear(StringUtil.parseDateTime(startDateStr));
+            if (StringUtil.isNotBlank(drugName)) {
+                if (antibioticDateTimes.get(drugName).get(startDate) > 0) {
+                    continue;   //一天内同一抗生素开过多次的抗生素直接过滤
+                }
+                drugName = removeBracket(drugName).replaceAll("[^\u4e00-\u9fa5]", "");
+                //相似度标准词抓取失败,增加暂时处理
+                if (drugName.equals("克林霉素磷酸酯注射液特丽仙")) {
+                    drugName = drugName.replace("特丽仙", "");
+                }
+                String drugStandardWord = similarityUtil.getDrugStandardWord(drugName);
+                if (StringUtil.isNotBlank(drugStandardWord)) {
+                    drugName = drugStandardWord;
+                }
+
+                if (extData != null && extData.containsKey(startDate) && extData.get(startDate).equals(drugName)) {
+                    continue;   //THR02985  医嘱有抗生素使用病程无记录,规则中没报未记录的抗生素继续走这条规则,报未记录的抗生素过滤
+                }
+
+                if (Arrays.asList(KSS).contains(drugName)) {
+                    collectAntibioticInfo(antibioticDate, antibioticStatus, antibioticValue, drugName, value, startDateStr);
+                }
+            }
+        }
+
+        //把抗生素使用剂量没变化过的抗生素删除
+//        antibioticStatus.forEach((x, y) -> {
+//            if (y == 0) {
+//                antibioticDate.remove(x);
+//                antibioticValue.remove(x);
+//            }
+//        });
+        //把同一天内同一个抗生素开过多次的抗生素删除
+//        antibioticDateTimes.forEach((x, y) -> {
+//            if (y > 0) {
+//                antibioticDate.remove(x);
+//                antibioticValue.remove(x);
+//            }
+//        });
+        //抗生素加用过的集合如果为空,则一个抗生素都没有加用过,直接返回0
+        if (antibioticDate.size() == 0) {
+            return;
+        }
+
+        //病程记录中没有用量的抗生素及查房时间       key:抗生素名    "2020-08-20,2020-08-21 ..."
+        Map<String, List<String>> antibioticDateCourse = Maps.newHashMap();
+        String dateStr = null;
+        /*********************************************首程治疗计划********************************************************/
+        if (firstCourseRecordDoc != null) {
+            DrugLabel drugLabel = firstCourseRecordDoc.getDrugLabel();
+            dateStr = firstCourseRecordDoc.getStructureMap().get("病历日期");
+            if (drugLabel != null && StringUtil.isNotBlank(dateStr)) {
+                List<Drug> drugs = drugLabel.getDrugs();
+                getCourseDrugInfo(antibioticDateCourse, dateStr, drugs,
+                        CatalogueUtil.structureMapJoin(firstCourseRecordDoc.getStructureMap(), Lists.newArrayList("诊疗计划")));
+            }
+        }
+        /*********************************************查房记录********************************************************/
+        if (threeLevelWardDocs.size() > 0) {
+            List<ThreeLevelWardDoc> allDoctorWradDocs = threeLevelWardDocs.get(0).getAllDoctorWradDocs();
+            for (ThreeLevelWardDoc doc : allDoctorWradDocs) {
+                if (doc.getThreeLevelWardLabel().size() == 0) {
+                    continue;
+                }
+                dateStr = doc.getStructureMap().get("查房日期");
+                ThreeLevelWardLabel label = doc.getThreeLevelWardLabel().get(0);
+                List<Drug> drugs = label.getDrugs();
+                getCourseDrugInfo(antibioticDateCourse, dateStr, drugs,
+                        CatalogueUtil.structureMapJoin(doc.getStructureMap(), Lists.newArrayList("病情记录", "治疗计划和措施")));
+            }
+        }
+        /*********************************************手术记录、术后首程************************************************/
+        if (operationDocs.size() > 0) {
+            //手术记录
+            List<OperationRecordDoc> operationRecordDocs = operationDocs
+                    .stream()
+                    .map(OperationDoc::getOperationRecordDoc)
+                    .filter(Objects::nonNull)
+                    .filter(x -> x.getOperationRecordLabel() != null && StringUtil.isNotBlank(x.getStructureMap().get("病历日期")))
+                    .collect(Collectors.toList());
+            operationRecordDocs.forEach(x -> getCourseDrugInfo(antibioticDateCourse, x.getStructureMap().get("病历日期"), x.getOperationRecordLabel().getDrugs()
+                    , CatalogueUtil.structureMapJoin(x.getStructureMap(), Lists.newArrayList("手术经过及处理"))));
+            //术后首程
+            List<OperationDiscussionDoc> operationDiscussionDocs = operationDocs
+                    .stream()
+                    .map(OperationDoc::getOperationDiscussionDoc)
+                    .filter(Objects::nonNull)
+                    .filter(x -> x.getOperationDiscussionLabel().getOperativeFindings() != null && StringUtil.isNotBlank(x.getStructureMap().get("病历日期")))
+                    .collect(Collectors.toList());
+            operationDiscussionDocs.forEach(x -> getCourseDrugInfo(antibioticDateCourse, x.getStructureMap().get("病历日期"), x.getOperationDiscussionLabel().getDrugs()
+                    , CatalogueUtil.structureMapJoin(x.getStructureMap(), Lists.newArrayList("手术简要经过", "术后处理措施"))));
+        }
+        /*********************************************会诊结果单********************************************************/
+        /*if (consultationDocs.size() > 0) {
+            List<ConsultationResultsDoc> consultationResultsDocs = consultationDocs
+                    .stream()
+                    .map(ConsultationDoc::getConsultationResultsDoc)
+                    .filter(Objects::nonNull)
+                    .filter(x -> x.getConsultationResultLabel() != null && StringUtil.isNotBlank(x.getStructureMap().get("会诊日期及时间")))
+                    .collect(Collectors.toList());
+            consultationResultsDocs.forEach(x -> getCourseDrugInfo(antibioticDateCourse, x.getStructureMap().get("会诊日期及时间"), x.getConsultationResultLabel().getDrugs()
+                    , CatalogueUtil.structureMapJoin(x.getStructureMap(), Lists.newArrayList("会诊意见"))));
+        }*/
+        /*********************************************出院小结********************************************************/
+//        if (leaveHospitalDoc != null) {
+//            LeaveHospitalLabel leaveHospitalLabel = leaveHospitalDoc.getLeaveHospitalLabel();
+//            if (inputInfo.getMedicalRecordInfoDoc() != null) {
+//                Map<String, String> medicalRecordInfoStructureMap = inputInfo.getMedicalRecordInfoDoc().getStructureMap();
+//                dateStr = medicalRecordInfoStructureMap.get("leaveHospitalDate");
+//                //如果存在出院小结,出院日期为空,存储系统当前时间
+//                if (StringUtil.isBlank(dateStr)) {
+//                    dateStr = DateUtil.formatDateTime(new Date());
+//                }
+//            }
+//            if (leaveHospitalLabel != null && StringUtil.isNotBlank(dateStr)) {
+//                List<Drug> drugs = leaveHospitalLabel.getDrugs();
+//                getCourseDrugInfo(antibioticDateCourse, dateStr, drugs
+//                        , CatalogueUtil.structureMapJoin(leaveHospitalDoc.getStructureMap(), Lists.newArrayList("诊治经过")));
+//            }
+//        }
+        //将病程日期排序
+        antibioticDateCourse.forEach((x, y) -> y.sort(Comparator.naturalOrder()));
+
+        /**
+         * 1.antibioticDate:从医嘱中取   key:抗生素名    value:医嘱中该抗生素所有剂量变化的时间(包括初始使用时间)
+         * 2.antibioticDateWard:从查房记录中取     key:抗生素名    value:病程记录中该抗生素所有没有用量时的查房时间(包括初始使用时间)
+         * 3.医嘱中该抗生素初始使用时间往后两天内,查房记录中出现该抗生素并且该抗生素没有用量,报出该抗生素
+         */
+        StringBuffer sb = new StringBuffer();
+        String drugKey = null, start = null, change = null, wardStartStr = null, wardChangeStr = null;
+        List<String> dateList = null;
+        for (Map.Entry<String, List<String>> ad : antibioticDate.entrySet()) {
+            drugKey = ad.getKey();
+            drugKey = removeBracket(drugKey).replaceAll("[^\u4e00-\u9fa5]", "");
+            String drugStandardWord = similarityUtil.getDrugStandardWord(drugKey);
+            if (StringUtil.isNotBlank(drugStandardWord)) {
+                drugKey = drugStandardWord;
+            }
+            if (antibioticDateCourse.containsKey(drugKey)) {
+                dateList = ad.getValue();
+                List<String> wardDateStr = antibioticDateCourse.get(drugKey);
+                for (int i = 0; i < dateList.size(); i++) {
+                    start = dateList.get(i);        //抗生素开医嘱时间
+                    Date adStart = DateUtil.dateZeroClear(StringUtil.parseDateTime(start));
+                    for (int j = 0; j < wardDateStr.size(); j++) {
+                        wardStartStr = wardDateStr.get(j);         //查房记录开抗生素时间
+                        wardStartStr = wardStartStr.split("=")[0];
+                        Date wardStart = StringUtil.parseDateTime(wardStartStr);
+                        if ((adStart.before(wardStart) && !CatalogueUtil.compareTime(adStart, wardStart, 48 * 60L))
+                                || (wardStart.before(adStart) && !CatalogueUtil.compareTime(wardStart, adStart, 24 * 60L)) ||
+                                DateUtils.isSameDay(wardStart, adStart)) {
+                            infoAppend(sb, ad.getKey(), start, wardDateStr.get(j).split("=")[1]);
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        if (sb.toString().length() > 0) {
+            status.set("-1");
+            info.set("医嘱:" + sb.toString().substring(0, sb.toString().length() - 1));
+        }
+    }
+
+    /**
+     * 记录同一抗生素同一天内是否开过多次,用于医嘱中需要处理的抗生素过滤(一天内同一抗生素开过多次的抗生素直接过滤)
+     *
+     * @param docAdvStruct
+     * @param antibioticDateTimes
+     */
+    private void getAntibioticTimes(List<Map<String, String>> docAdvStruct, Map<String, Map<Date, Integer>> antibioticDateTimes) {
+        String drugName;
+        String startDateStr;
+        Date startDate;
+        Map<Date, Integer> antibioticDateTime;
+        for (Map<String, String> structMap : docAdvStruct) {
+            drugName = structMap.get("医嘱项目名称");
+            startDateStr = structMap.get("医嘱开始时间");
+            startDate = DateUtil.dateZeroClear(StringUtil.parseDateTime(startDateStr));
+            if (antibioticDateTimes.containsKey(drugName)) {
+                Map<Date, Integer> map = antibioticDateTimes.get(drugName);
+                if (map.containsKey(startDate)) {
+                    map.put(startDate, map.get(startDate) + 1);
+                } else {
+                    map.put(startDate, 0);
+                }
+            } else {
+                antibioticDateTime = Maps.newHashMap();
+                antibioticDateTime.put(startDate, 0);
+                antibioticDateTimes.put(drugName, antibioticDateTime);
+            }
+        }
+    }
+
+    List<String> usageWords = Lists.newArrayList("WB", "wb", "泵", "静滴");
+
+    /**
+     * 收集各模块药品信息
+     *
+     * @param antibioticDateWard 病程中没有用量+用法+频率的抗生素使用所有时间
+     * @param dateStr            记录日期
+     * @param drugs              模型提取出的药品列表
+     */
+    private void getCourseDrugInfo(Map<String, List<String>> antibioticDateWard, String dateStr, List<Drug> drugs, String content) {
+        StringBuffer sb = null;
+        for (Drug drug : drugs) {
+            sb = new StringBuffer();
+            String behindWord = "";
+            String lastBehindWord = "";
+            String keyword = "";
+            String lastKeyword = "";
+            String wardDrug = drug.getName();
+            boolean front = false;
+            boolean latter = false;
+            int position = content.indexOf(wardDrug);
+            int lastPosition = content.lastIndexOf(wardDrug);
+            if (position != -1 && lastPosition != -1) {
+                keyword = content.substring(Math.max(0, position - 10), position);
+                lastKeyword = content.substring(Math.max(0, lastPosition - 10), lastPosition);
+                if (position != lastPosition) {
+                    if (lastKeyword.contains("继续") || lastKeyword.contains("停")) {
+                        continue;
+                    }
+                }
+                if (keyword.contains("继续") || keyword.contains("停")) {
+                    continue;
+                }
+                if (frequencyDispose(keyword) || frequencyDispose(lastKeyword)) {
+                    front = true;
+                }
+
+                behindWord = content.substring(position, Math.min(position + 20, content.toCharArray().length));
+                lastBehindWord = content.substring(lastPosition, Math.min(lastPosition + 20, content.toCharArray().length));
+                if (behindWord != lastBehindWord) {
+                    if (lastBehindWord.contains("阴性")) {
+                        continue;
+                    }
+                }
+                if (behindWord.contains("阴性")) {
+                    continue;
+                }
+                if (frequencyDispose(behindWord) || frequencyDispose(lastBehindWord)) {
+                    latter = true;
+                }
+            }
+            wardDrug = removeBracket(wardDrug);
+            String drugUsageWard = wardDrug;
+            String drugStandardWord = similarityUtil.getDrugStandardWord(wardDrug);
+            if (StringUtil.isNotBlank(drugStandardWord)) {
+                wardDrug = drugStandardWord;
+            }
+            if (drug.getConsumption() == null) {
+                if (StringUtil.isBlank(behindWord)) {
+                    concatInfo(dateStr, sb, "用量");
+                } else {
+                    if (!hasDigit(behindWord) && !hasDigit(lastBehindWord)) {
+                        concatInfo(dateStr, sb, "用量");
+                    }
+                }
+            }
+
+            int index = content.indexOf(drugUsageWard);
+            String drugContent = content.substring(Math.max(0, index));
+            boolean isUsage = true;
+            if (drug.getUsageWardRound() == null) {
+                for (String word : usageWords) {
+                    if (drugContent.contains(word)) {
+                        isUsage = false;
+                        break;
+                    }
+                }
+                if (isUsage) {
+                    concatInfo(dateStr, sb, "用法");
+                }
+            }
+            if (drug.getFrequency() == null) {
+                if (!front && !latter) {
+                    concatInfo(dateStr, sb, "频率");
+                }
+            }
+            if (sb.toString().length() > 0) {
+                if (antibioticDateWard.containsKey(wardDrug)) {
+                    antibioticDateWard.get(wardDrug).add(sb.toString());
+                } else {
+                    antibioticDateWard.put(wardDrug, Lists.newArrayList(sb.toString()));
+                }
+            } else {
+                if (antibioticDateWard.containsKey(wardDrug)) {
+                    for (String wardDate : antibioticDateWard.get(wardDrug)) {
+                        wardDate = wardDate.substring(0, wardDate.indexOf("="));
+                        if (wardDate.equals(dateStr)) {
+                            antibioticDateWard.remove(wardDrug);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 判断一个字符串是否含有数字
+     *
+     * @param content
+     */
+    public boolean hasDigit(String content) {
+        boolean flag = false;
+        Pattern p = Pattern.compile(".*\\d+.*");
+        Matcher m = p.matcher(content);
+        if (m.matches()) {
+            flag = true;
+        }
+        return flag;
+    }
+
+    /**
+     * 增加频率的处理
+     *
+     * @param content
+     */
+    public boolean frequencyDispose(String content) {
+        if (StringUtil.isNotBlank(content) &&
+                (content.contains("术前") || content.contains("术后") || content.contains("围手术期"))) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 拼接抗生素缺失信息
+     *
+     * @param dateStr
+     * @param sb
+     */
+    private void concatInfo(String dateStr, StringBuffer sb, String missType) {
+        if (sb.toString().contains("=")) {
+            sb.append(",").append(missType);
+        } else {
+            sb.append(dateStr).append("=").append(missType);
+        }
+    }
+
+    /**
+     * 收集抗生素各种信息
+     *
+     * @param antibioticDate   抗生素使用所有时间
+     * @param antibioticStatus 抗生素用量改变状态
+     * @param antibioticValue  抗生素及用量
+     * @param drugName         抗生素名称
+     * @param value            抗生素用量
+     * @param startDateStr     抗生素使用时间(医嘱开始时间或查房时间)
+     */
+    private void collectAntibioticInfo(Map<String, List<String>> antibioticDate, Map<String, Integer> antibioticStatus,
+                                       Map<String, List<Double>> antibioticValue, String drugName, String value, String startDateStr) {
+        double v = -1;
+        try {
+            v = Double.parseDouble(getNumber(value));
+        } catch (Exception e) {
+            System.out.println("THR03077:       " + drugName + ":" + value + "解析异常");
+        }
+        if (v < 0) {
+            return;
+        }
+        if (v > 100) {
+            v = v / 1000;
+        }
+        if (!antibioticValue.containsKey(drugName)) {
+            antibioticValue.put(drugName, Lists.newArrayList(v));
+            antibioticDate.put(drugName, Lists.newArrayList(startDateStr));
+            antibioticStatus.put(drugName, 0);
+        } else {
+            //1.如果抗生素剂量有变化,则记录该抗生素开始时间
+            List<Double> beforeValue = antibioticValue.get(drugName);
+            if (beforeValue.get(beforeValue.size() - 1) != v) {
+                beforeValue.add(v);
+                antibioticValue.put(drugName, beforeValue);//添加该抗生素更大的值
+                antibioticStatus.put(drugName, antibioticStatus.get(drugName) + 1);
+                antibioticDate.get(drugName).add(startDateStr);
+                return;
+            }
+            //2.如果抗生素剂量两次开启的时间间隔相差3天,也记录该抗生素开始时间
+            List<String> currentAntibioticDate = antibioticDate.get(drugName);
+            if (currentAntibioticDate.size() > 0) {
+                String lastDate = currentAntibioticDate.get(currentAntibioticDate.size() - 1);
+                if (CatalogueUtil.compareTime(StringUtil.parseDateTime(lastDate), StringUtil.parseDateTime(startDateStr), 72 * 60L)) {
+                    beforeValue.add(v);
+                    antibioticValue.put(drugName, beforeValue);//添加该抗生素值
+                    antibioticStatus.put(drugName, antibioticStatus.get(drugName) + 1);
+                    antibioticDate.get(drugName).add(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;
+    }
+
+    /**
+     * 拼接提示信息
+     *
+     * @param sb
+     * @param drugKey
+     * @param date
+     */
+    private void infoAppend(StringBuffer sb, String drugKey, String date, String missType) {
+        sb.append(drugKey).append("(").append(DateUtil.formatDate(StringUtil.parseDateTime(date)))
+                .append(",").append(missType).append(")").append("、");
+    }
+
+    private static final String[] KSS = {
+            "万古霉素",
+            "两性霉素B",
+            "亚胺培南西司他丁",
+            "伊曲康唑",
+            "伏立康唑",
+            "依替米星氯化钠",
+            "克拉霉素",
+            "克林霉素",
+            "利奈唑胺",
+            "利奈唑胺葡萄糖",
+            "利福昔明",
+            "制霉菌素",
+            "卡泊芬净",
+            "厄他培南",
+            "吗啉硝唑氯化钠",
+            "呋喃唑酮",
+            "哌拉西林他唑巴坦",
+            "复方磺胺甲噁唑",
+            "多粘菌素B",
+            "多西环素",
+            "夫西地酸",
+            "头孢丙烯",
+            "头孢他啶",
+            "头孢他啶阿维巴坦",
+            "头孢他美酯",
+            "头孢克洛",
+            "头孢克肟",
+            "头孢吡肟",
+            "头孢呋辛",
+            "头孢哌酮舒巴坦",
+            "头孢唑林",
+            "头孢噻肟",
+            "头孢地嗪",
+            "头孢地尼",
+            "头孢拉定",
+            "头孢曲松",
+            "头孢替安",
+            "头孢美唑",
+            "头孢西丁",
+            "奥硝唑",
+            "妥布霉素",
+            "妥布霉素地塞米松",
+            "左氧氟沙星",
+            "左氧氟沙星氯化钠",
+            "庆大霉素",
+            "异帕米星",
+            "拉氧头孢",
+            "替加环素",
+            "替硝唑",
+            "替考拉宁",
+            "比阿培南",
+            "氟康唑",
+            "氟康唑氯化钠",
+            "氟胞嘧啶",
+            "氨曲南",
+            "氨苄西林",
+            "泊沙康唑",
+            "特比萘芬",
+            "甲硝唑",
+            "甲硝唑氯化钠",
+            "磷霉素",
+            "磷霉素氨丁三醇",
+            "米卡芬净",
+            "米诺环素",
+            "红霉素",
+            "美罗培南",
+            "苄星青霉素",
+            "莫西沙星",
+            "莫西沙星氯化钠",
+            "达托霉素",
+            "阿奇霉素",
+            "阿奇霉素枸橼酸二氢钠",
+            "阿洛西林",
+            "阿米卡星",
+            "阿莫西林",
+            "阿莫西林克拉维酸",
+            "青霉素"
+    };
+
+    private static final List<String> filterKey = Lists.newArrayList("ACF", "ID", "IG", "IM", "IP", "IV",
+            "关节腔注射", "宫颈注射", "皮下注射", "皮下注射(儿童)", "皮下注射(免费)", "皮下注射(成人)", "皮内", "皮内注射",
+            "结膜下注射", "肌注", "肌肉注射(儿童)", "肌肉注射(公卫专用)", "肌肉注射(成人)", "胸腔注射", "腹腔内注射", "腹腔注射",
+            "静滴(儿童)", "静滴(成人)", "静脉注射", "静脉注射(儿童)", "静脉注射(免费)", "静脉注射(成人)", "静脉注射(泵)",
+            "静脉滴注", "静脉滴注(泵)", "鞘内注射", "微泵");
+
+}

+ 150 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0588.java

@@ -0,0 +1,150 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.threelevelward;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.StagesSummaryDoc;
+import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
+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.transferrecord.TransferIntoDoc;
+import com.lantone.qc.pub.model.doc.transferrecord.TransferOutDoc;
+import com.lantone.qc.pub.model.doc.transferrecord.TransferRecordDoc;
+import com.lantone.qc.pub.util.DateUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * @ClassName : THR0588
+ * @Description : 住院期间连续3天无病程记录
+ * @Author : 王世延
+ * @Date: 2020-09-8 14:22
+ */
+@Component
+public class THR0588 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        Date leaveDate = null;
+        if (inputInfo.getMedicalRecordInfoDoc() != null) {
+            Map<String, String> medicalRecordInfoStructureMap = inputInfo.getMedicalRecordInfoDoc().getStructureMap();
+            String leaveHospitalTime = medicalRecordInfoStructureMap.get("leaveHospitalDate");
+            leaveDate = StringUtil.parseDateTime(leaveHospitalTime);
+            if (leaveDate == null) {
+//                LeaveHospitalDoc leaveHospitalDoc = inputInfo.getLeaveHospitalDoc();
+//                if (leaveHospitalDoc != null) {
+//                    leaveDate = StringUtil.parseDateTime(leaveHospitalDoc.getStructureMap().get("出院日期"));
+//                }
+                leaveDate = new Date();
+            }
+        }
+        //查房记录
+        List<ThreeLevelWardDoc> threeLevelWardDocs = inputInfo.getThreeLevelWardDocs();
+        if (threeLevelWardDocs.size() == 0) {
+            return;
+        }
+        //所有查房记录的日期天
+        List<Date> dateThreeLevelDay = new ArrayList<>();
+        StringBuffer sb = new StringBuffer();
+        //所有的查房记录
+        List<ThreeLevelWardDoc> allDoctorWradDocs = threeLevelWardDocs.get(0).getAllDoctorWradDocs();
+        for (ThreeLevelWardDoc doc : allDoctorWradDocs) {
+            Date threeLevelDate = StringUtil.parseDateTime(doc.getStructureMap().get("查房日期"));
+            if (threeLevelDate == null) {
+                continue;
+            }
+            dateThreeLevelDay.add(threeLevelDate);
+        }
+        /******************************************首次病程********************************************************/
+        if (inputInfo.getFirstCourseRecordDoc() != null) {
+            Map<String, String> structureMap = inputInfo.getFirstCourseRecordDoc().getStructureMap();
+            if (StringUtil.isNotBlank(structureMap.get("病历日期"))) {
+                Date recordDate = StringUtil.parseDateTime(structureMap.get("病历日期"));
+                dateThreeLevelDay.add(recordDate);
+            }
+        }
+        /******************************************术后首程********************************************************/
+        if (inputInfo.getOperationDocs().size() > 0) {
+            List<String> recordDateList = inputInfo.getOperationDocs().stream().map(OperationDoc::getOperationDiscussionDoc).filter(Objects::nonNull)
+                    .map(OperationDiscussionDoc::getStructureMap).filter(i -> StringUtil.isNotBlank(i.get("病历日期")))
+                    .map(i -> i.get("病历日期")).collect(Collectors.toList());
+            for (String recordDateStr : recordDateList) {
+                Date recordDate = StringUtil.parseDateTime(recordDateStr);
+                if (recordDate == null) {
+                    continue;
+                }
+                dateThreeLevelDay.add(recordDate);
+            }
+        }
+        /******************************************转入转出********************************************************/
+        if (inputInfo.getTransferRecordDocs() != null) {
+            TransferRecordDoc transferRecordDocs = inputInfo.getTransferRecordDocs();
+            List<String> intoRecordDateList = transferRecordDocs.getTransferIntoDocs()
+                    .stream().map(TransferIntoDoc::getStructureMap).filter(i -> StringUtil.isNotBlank(i.get("病历日期")))
+                    .map(i -> i.get("病历日期")).collect(Collectors.toList());
+            for (String recordDateStr : intoRecordDateList) {
+                Date recordDate = StringUtil.parseDateTime(recordDateStr);
+                if (recordDate == null) {
+                    continue;
+                }
+                dateThreeLevelDay.add(recordDate);
+            }
+            intoRecordDateList = transferRecordDocs.getTransferOutDocs()
+                    .stream().map(TransferOutDoc::getStructureMap).filter(i -> StringUtil.isNotBlank(i.get("病历日期")))
+                    .map(i -> i.get("病历日期")).collect(Collectors.toList());
+            for (String recordDateStr : intoRecordDateList) {
+                Date recordDate = StringUtil.parseDateTime(recordDateStr);
+                if (recordDate == null) {
+                    continue;
+                }
+                dateThreeLevelDay.add(recordDate);
+            }
+        }
+        /******************************************阶段小结********************************************************/
+        if (inputInfo.getStagesSummaryDocs().size() > 0) {
+            List<String> intoRecordDateList = inputInfo.getStagesSummaryDocs().stream().map(StagesSummaryDoc::getStructureMap)
+                    .filter(i -> StringUtil.isNotBlank(i.get("病历日期")))
+                    .map(i -> i.get("病历日期")).collect(Collectors.toList());
+            for (String recordDateStr : intoRecordDateList) {
+                Date recordDate = StringUtil.parseDateTime(recordDateStr);
+                if (recordDate == null) {
+                    continue;
+                }
+                dateThreeLevelDay.add(recordDate);
+            }
+        }
+        dateThreeLevelDay = dateThreeLevelDay.stream().sorted().collect(Collectors.toList());
+        int timeCha = 259200000;
+        //获取连续3天无查房记录的时间
+        for (int i = 0; i < dateThreeLevelDay.size(); i++) {
+            if (i + 1 < dateThreeLevelDay.size()) {
+                if (DateUtil.dateZeroClear(dateThreeLevelDay.get(i + 1)).getTime() - DateUtil.dateZeroClear(dateThreeLevelDay.get(i)).getTime() > timeCha &&
+                        dateThreeLevelDay.get(i + 1).before(leaveDate)) {
+                    infoAppend(sb, dateThreeLevelDay.get(i), dateThreeLevelDay.get(i + 1));
+                }
+            }
+        }
+        if (sb.toString().length() > 0) {
+            status.set("-1");
+            info.set(sb.toString().substring(0, sb.toString().length() - 1));
+        }
+    }
+
+    /**
+     * 拼接提示信息
+     *
+     * @param sb
+     * @param bfDate
+     * @param afDate
+     */
+    private void infoAppend(StringBuffer sb, Date bfDate, Date afDate) {
+        sb.append("(").append(DateUtil.formatDate(bfDate))
+                .append("->").append(DateUtil.formatDate(afDate)).append(")").append("、");
+    }
+}

+ 133 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0601.java

@@ -0,0 +1,133 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.threelevelward;
+
+import com.lantone.qc.dbanaly.util.KernelConstants;
+import com.lantone.qc.dbanaly.util.SpecialStorageUtil;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.Content;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.MedicalRecordInfoDoc;
+import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
+import com.lantone.qc.pub.model.doc.operation.OperationDoc;
+import com.lantone.qc.pub.model.doc.ward.AttendingDoctorWardDoc;
+import com.lantone.qc.pub.util.DateUtil;
+import com.lantone.qc.pub.util.SpringContextUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : THR0601
+ * @Description : 整份病历无主治医师查房记录
+ * @Author : 胡敬
+ * @Date: 2020-03-25 10:21
+ */
+@Component
+public class THR0601 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        MedicalRecordInfoDoc medicalRecordInfoDoc = inputInfo.getMedicalRecordInfoDoc();
+        if (medicalRecordInfoDoc != null && medicalRecordInfoDoc.getStructureMap() != null) {
+            //入院日期
+            String admisTime = medicalRecordInfoDoc.getStructureMap().get("behospitalDate");
+            //出院日期
+            String dischargeTime = medicalRecordInfoDoc.getStructureMap().get("leaveHospitalDate");
+            if (CatalogueUtil.isEmpty(admisTime) || CatalogueUtil.isEmpty(dischargeTime)) {
+                return;
+            }
+            if (!CatalogueUtil.compareTime(
+                    StringUtil.parseDateTime(admisTime),
+                    StringUtil.parseDateTime(DateUtil.nowString()),
+                    Long.valueOf(48 * 60))) {//如果入院未超过48小时,规则不判断
+                return;
+            }
+            //如果住院天数小于2天则不判断该条规则
+            if (DateUtil.parseDate(dischargeTime) != null &&
+                    !CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(dischargeTime), (long) (48 * 60))) {
+                return;
+            } else {
+                if (inputInfo.getThreeLevelWardDocs().size() == 0) {
+                    status.set("-1");
+                    return;
+                }
+            }
+        }
+
+        if (inputInfo.getLeaveHospitalDoc() != null) {
+            Map<String, String> leaveHospitalStructureMap = inputInfo.getLeaveHospitalDoc().getStructureMap();
+            String lengthOfStay = leaveHospitalStructureMap.get("住院天数");
+            if (StringUtil.isNotBlank(lengthOfStay) && CatalogueUtil.numbersOnly(lengthOfStay)) {
+                //如果住院天数小于2天则不判断该条规则
+                if (Integer.parseInt(lengthOfStay) <= 2) {
+                    return;
+                }
+            }
+        }
+
+        /* 如果存在手术记录,判断主刀医生是否为主治医生 */
+        String operatorName = "";
+        List<OperationDoc> operationDocs = inputInfo.getOperationDocs();
+        if (operationDocs != null) {
+            for (OperationDoc operationDoc : operationDocs) {
+                if (operationDoc.getOperationRecordDoc() != null) {
+                    Map<String, String> operationDocStructureMap = operationDoc.getOperationRecordDoc().getStructureMap();
+                    if (StringUtil.isBlank(operatorName)) {
+                        operatorName = operationDocStructureMap.get("主刀医师");
+                    }
+                }
+            }
+        }
+
+        List<AttendingDoctorWardDoc> attendingDoctorWardDocs = inputInfo.getThreeLevelWardDocs().get(0).getAttendingDoctorWardDocs();//主治查房记录
+        if (attendingDoctorWardDocs != null && attendingDoctorWardDocs.size() > 0) {
+            return;
+        }
+
+        List<ThreeLevelWardDoc> allDoctorWradDocs = inputInfo.getThreeLevelWardDocs().get(0).getAllDoctorWradDocs();//查房记录
+        String title, record;
+        boolean findIndications = false;
+        for (ThreeLevelWardDoc threeLevelWardDoc : allDoctorWradDocs) {
+            Map<String, String> rescueStructureMap = threeLevelWardDoc.getStructureMap();
+            title = CatalogueUtil.subTitle(rescueStructureMap.get("查房标题"));
+            record = CatalogueUtil.subTitle(rescueStructureMap.get("病情记录"));
+            if (StringUtil.isNotBlank(title) && title.contains(Content.attend)) {
+                findIndications = true;
+                break;
+            }
+            if (StringUtil.isNotBlank(record) && record.contains(Content.attend)) {
+                findIndications = true;
+                break;
+            }
+            if (StringUtil.isNotBlank(operatorName) && (title.contains("主刀") || record.contains("主刀"))) {
+                String operationProfessor = getCourseProfessor(operatorName);
+                if (operationProfessor.contains("主治")) {
+                    findIndications = true;
+                    break;
+                }
+            }
+        }
+        if (!findIndications) {
+            status.set("-1");
+        }
+    }
+
+    private String getCourseProfessor(String operatorName) {
+        String professor = "";
+        if (StringUtil.isBlank(operatorName)) {
+            return professor;
+        }
+        SpecialStorageUtil specialStorageUtil = SpringContextUtil.getBean("specialStorageUtil");
+        Map<String, Object> surgeon = specialStorageUtil.getJsonStringValue(KernelConstants.HOSPITAL_DOCTOR_MAP);
+        if (surgeon != null) {
+            Map<String, String> doctor = (Map) surgeon.get(operatorName);
+            if (doctor != null) {
+                professor = doctor.get("professor");
+            }
+
+        }
+        return professor;
+    }
+}

+ 41 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xiamen/threelevelward/THR0698.java

@@ -0,0 +1,41 @@
+package com.lantone.qc.kernel.catalogue.hospital.xiamen.threelevelward;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @ClassName : THR0698
+ * @Description : 查房记录无记录时间
+ * @Author : 胡敬
+ * @Date: 2020-04-20 15:23
+ */
+@Component
+public class THR0698 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        List<ThreeLevelWardDoc> threeLevelWardDocs = inputInfo.getThreeLevelWardDocs();
+        if (threeLevelWardDocs.size() == 0) {
+            status.set("0");
+            return;
+        }
+        List<ThreeLevelWardDoc> allDoctorWradDocs = threeLevelWardDocs.get(0).getAllDoctorWradDocs();
+        if (allDoctorWradDocs.size() == 0) {
+            status.set("0");
+            return;
+        }
+        List<ThreeLevelWardDoc> recordDoctorList = allDoctorWradDocs
+                .stream()
+                .filter(doc -> StringUtil.isBlank(doc.getStructureMap().get("病历日期")))
+                .collect(Collectors.toList());
+        if (recordDoctorList.size() == 0) {
+            status.set("0");
+        }
+
+    }
+}

+ 87 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0001.java

@@ -0,0 +1,87 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.PD;
+import com.lantone.qc.pub.model.label.ChiefLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+
+/**
+ * @ClassName : BEH0001
+ * @Description : 症状缺少时间描述
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class BEH0001 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        ChiefLabel chiefLabel = inputInfo.getBeHospitalizedDoc().getChiefLabel();
+        if (chiefLabel == null) {
+            status.set("0");
+            return;
+        }
+        String chiefText = chiefLabel.getText();
+        if (StringUtil.isBlank(chiefText)) {
+            status.set("0");
+            return;
+        }
+        if (StringUtil.isNotBlank(chiefText) && (chiefText.contains("检查")
+                || chiefText.contains("术后") || chiefText.contains("药物")
+                || chiefText.contains("天")|| chiefText.contains("周")
+                || chiefText.contains("月")|| chiefText.contains("时")
+                || chiefText.contains("秒")|| chiefText.contains("半年")
+                || chiefText.contains("日")|| chiefText.contains("今")
+                || chiefText.contains("余年")|| chiefText.contains("年")
+                || chiefText.contains("分"))) {
+            status.set("0");
+            return;
+        } else {
+            List<PD> pds = chiefLabel.getPds();
+            if (pds != null && pds.size() > 0) {
+                for (PD pd : pds) {
+                    String pdName = pd.getName();
+                    if (StringUtil.isNotBlank(pdName)) {
+                        if (pdName.contains("天") || pdName.contains("周") || pdName.contains("月")
+                                || pdName.contains("时") || pdName.contains("秒") || pdName.contains("半年")
+                                || pdName.contains("日") || pdName.contains("今") || pdName.contains("余年")
+                                || pdName.contains("年") || pdName.contains("分") || isDate(pdName)) {
+                            status.set("0");
+                            break;
+                        }
+                    }
+                }
+            }
+       /*     List<Clinical> clinicals = inputInfo.getBeHospitalizedDoc().getChiefLabel().getClinicals();
+            if (clinicals.size() > 0) {
+                for (Clinical clinical : clinicals) {
+                    String clinicalName = clinical.getName();
+                    List<PD> timestamp = clinical.getTimestamp();
+                    if (ListUtil.isEmpty(timestamp)) {
+                        if (StringUtils.isEmpty(info.get())) {
+                            info.set(clinicalName);
+                        } else {
+                            info.set(info.get() + "," + clinicalName);
+                        }
+                    }
+                }
+            }*/
+        }
+     /*   if (StringUtils.isNotEmpty(info.get())) {
+            status.set("-1");
+        }*/
+    }
+
+    private boolean isDate(String pdName) {
+        String regex = "[0-9]{4}.?[0-9]{2}.?[0-9]{2}";
+        return pdName.matches(regex);
+    }
+}

+ 114 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0006.java

@@ -0,0 +1,114 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.PD;
+import com.lantone.qc.pub.model.label.ChiefLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.List;
+
+
+/**
+ * @ClassName : BEH0006
+ * @Description :主诉症状缺少近期时间描述
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class BEH0006 extends QCCatalogue {
+    private List<String> containList = Arrays.asList("半年", "术后");
+
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        ChiefLabel chiefLabel = inputInfo.getBeHospitalizedDoc().getChiefLabel();
+        if (chiefLabel == null || StringUtil.isBlank(chiefLabel.getText())) {
+            status.set("0");
+            return;
+        }
+//        List<Clinical> clinicalList = chiefLabel.getClinicals();
+//        boolean flag = true;
+//        // 主诉症状不超过1年就不报错,单位不包含“年”
+//        if (ListUtil.isNotEmpty(clinicalList)) {
+//            for (Clinical c : clinicalList) {
+//                List<PD> pds = c.getTimestamp();
+//                if (ListUtil.isNotEmpty(pds)) {
+//                    for (PD pd : pds) {
+//                        if (StringUtil.isNotBlank(pd.getName()) &&
+//                                pd.getName().contains("年") && !"半年".equals(pd.getName())) {
+//                            flag = false;
+//                            break;
+//                        }
+//                    }
+//                }
+//            }
+//            if (flag) {
+//                status.set("0");
+//                return;
+//            }
+//        }
+        String chiefText = chiefLabel.getText();
+        if (StringUtil.isNotBlank(chiefText)) {
+            for (String fild : containList) {
+                if (chiefText.contains(fild)) {
+                    status.set("0");
+                    return;
+                }
+            }
+            List<PD> pds = chiefLabel.getPds();
+            if (pds != null && pds.size() > 0) {
+                if (pds.size() == 2) {
+                    status.set("0");
+                    return;
+                }
+                for (PD pd : pds) {
+                    String pdName = pd.getName();
+                    if (!CatalogueUtil.isEmpty(pdName)) {
+                        if (pdName.contains("天") || pdName.contains("周") || pdName.contains("月")
+                                || pdName.contains("时") || pdName.contains("半年") || pdName.contains("秒")
+                                || pdName.contains("分") || pdName.contains("日") || pdName.contains("今")
+                                || pdName.contains("1年") || pdName.contains("一年")) {
+                            status.set("0");
+                            break;
+                        }
+                    }
+                }
+            } else {
+                if (StringUtil.isNotBlank(chiefLabel.getText())) {
+                    status.set("0");
+                    return;
+                }
+            }
+        }
+            /*List<Clinical> clinicals = chiefLabel.getClinicals();
+            if(clinicals.size()>0){
+                for (Clinical clinical:clinicals) {
+                    List<PD> timestamp = clinical.getTimestamp();
+                    if(timestamp != null){
+                        for (PD pd:timestamp) {
+                            if(!CatalogueUtil.isEmpty(pd.getName())){
+                                if(pd.getName().contains("天") || pd.getName().contains("周")|| pd.getName().contains("月")
+                                        || pd.getName().contains("时") || pd.getName().contains("半年") || pd.getName().contains("秒")
+                                        || pd.getName().contains("日")|| pd.getName().contains("今")){
+                                    status.set("0");
+                                    break;
+                                }
+                            }
+                        }
+                        if(status.get().equals("0")){
+                            break;
+                        }
+                    }
+                }
+            }else {
+                status.set("0");
+            }*/
+    }
+}

+ 67 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0009.java

@@ -0,0 +1,67 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Clinical;
+import com.lantone.qc.pub.model.entity.Diag;
+import com.lantone.qc.pub.model.label.ChiefLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.List;
+
+
+/**
+ * @ClassName : BEH0009
+ * @Description :主诉缺少主症状
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class BEH0009 extends QCCatalogue {
+    private List<String> containList = Arrays.asList("检查", "术后", "药物", "发现", "误服", "确诊", "经", "异常", "诊断"
+            , "示", "超", "伤", "术", "复查", "体检", "血透", "血液透析","孕","生后");
+
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        ChiefLabel chiefLabel = inputInfo.getBeHospitalizedDoc().getChiefLabel();
+        if (chiefLabel == null) {
+            status.set("0");
+            return;
+        }
+        String chiefText = chiefLabel.getText();
+        if (StringUtil.isBlank(chiefText)) {
+            status.set("0");
+            return;
+        }
+        if (StringUtil.isNotBlank(chiefText)) {
+            for (String word : containList) {
+                if (chiefText.contains(word)) {
+                    status.set("0");
+                    return;
+                }
+            }
+            List<Clinical> clinicals = chiefLabel.getClinicals();
+            if (clinicals != null && clinicals.size() > 0) {
+                status.set("0");
+                return;
+            }
+            List<Diag> diags = chiefLabel.getDiags();
+            if (diags != null && diags.size() > 0) {
+                for (Diag diag : diags) {
+                    String hospitalDiagName = diag.getHospitalDiagName();
+                    if (hospitalDiagName.contains("术后") || hospitalDiagName.contains("癌") ||
+                            hospitalDiagName.contains("瘤") || hospitalDiagName.contains("复诊")) {
+                        status.set("0");
+                        break;
+                    }
+                }
+            }
+        }
+    }
+}

+ 225 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0011.java

@@ -0,0 +1,225 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.alibaba.fastjson.JSONArray;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.client.ChiefPresentSimilarityServiceClient;
+import com.lantone.qc.kernel.structure.ai.ModelAI;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Diag;
+import com.lantone.qc.pub.model.entity.GeneralDesc;
+import com.lantone.qc.pub.model.label.DiagLabel;
+import com.lantone.qc.pub.model.label.PastLabel;
+import com.lantone.qc.pub.model.label.PresentLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * @ClassName : BEH0011
+ * @Description : 初步诊断不完整
+ * 原逻辑 --初步诊断没有既往史里的慢性疾病
+ * 现逻辑 --检查现病史中一般情况之后的疾病名称,既往史中的疾病名称是否都在初步诊断里
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class BEH0011 extends QCCatalogue {
+    //    @Autowired
+    //    private SpecialStorageUtil specialStorageUtil;
+    @Autowired
+    ChiefPresentSimilarityServiceClient chiefPresentSimilarityServiceClient;
+
+    private List<String> containList = Arrays.asList("脑萎缩", "慢性", "纤颤", "高血压", "糖尿", "冠状", "冠心病", "支架", "起搏器", "房颤", "风湿");
+    private List<String> filterList = Arrays.asList("心脏病", "低血糖", "急性", ";");
+
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        PresentLabel presentLabel = inputInfo.getBeHospitalizedDoc().getPresentLabel();
+        DiagLabel initialDiagLabel = inputInfo.getBeHospitalizedDoc().getInitialDiagLabel();
+        /*补充诊断*/
+        DiagLabel suppleDiagLabel = inputInfo.getBeHospitalizedDoc().getSuppleDiagLabel();
+        PastLabel pastLabel = inputInfo.getBeHospitalizedDoc().getPastLabel();
+        if (initialDiagLabel == null) {
+            status.set("0");
+            return;
+        }
+        Set<String> presentPastDiags = new HashSet<>();
+        if (presentLabel != null) {
+            List<GeneralDesc> generals = presentLabel.getGenerals();
+            if (generals.size() > 0) {
+                String presentText = presentLabel.getText();
+                List<Diag> presentDiags = presentLabel.getDiags();
+                /* 取现病史中一般情况之后的疾病名称 */
+                if (StringUtil.isNotBlank(presentText) && presentDiags.size() > 0) {
+                    String lastGeneral = generals.get(generals.size() - 1).getName();
+                    int lastGeneralIndex = presentText.indexOf(lastGeneral);
+                    for (Diag presentDiag : presentDiags) {
+                        if (presentDiag.getNegative() != null || presentDiag.getHospitalDiagName().contains("否认")) {
+                            continue;
+                        }
+                        /* 现病史中一般情况之后的疾病名称 */
+                        if (presentText.indexOf(presentDiag.getHospitalDiagName()) > lastGeneralIndex) {
+                            if (isContains(presentDiag.getHospitalDiagName()) && !isFilter(presentDiag.getHospitalDiagName())) {
+                                presentPastDiags.add(presentDiag.getHospitalDiagName());
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        /* 取既往史中疾病名称 */
+        if (pastLabel != null && StringUtils.isNotEmpty(pastLabel.getText())) {
+            List<Diag> pastDiags = pastLabel.getDiags();
+            addDiagHospitalName(presentPastDiags, pastDiags);
+        } else {            //结构化数据
+            List<Diag> pastDiags = new ArrayList<>();
+
+            Map<String, String> structureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+            String a1 = structureMap.get("高血压");
+            if (StringUtils.isNotEmpty(a1) && !"否认".equals(a1)) {
+                Diag diag = new Diag();
+                diag.setName("高血压");
+                diag.setHospitalDiagName("高血压");
+                if (!isHave(presentPastDiags, "高血压")) {
+                    pastDiags.add(diag);
+                }
+            }
+            a1 = structureMap.get("糖尿病");
+            if (StringUtils.isNotEmpty(a1) && !"否认".equals(a1)) {
+                Diag diag = new Diag();
+                diag.setName("糖尿病");
+                diag.setHospitalDiagName("糖尿病");
+                if (!isHave(presentPastDiags, "糖尿病")) {
+                    pastDiags.add(diag);
+                }
+            }
+            addDiagHospitalName(presentPastDiags, pastDiags);
+        }
+        /* 取初步诊断中疾病名称 */
+        List<String> initDiags = new ArrayList<>();
+        List<Diag> initialDiagDiags = initialDiagLabel.getDiags();
+        addInitDiagHospitalName(initDiags, initialDiagDiags);
+        if (suppleDiagLabel != null) {
+            List<Diag> suppleDiagDiags = suppleDiagLabel.getDiags();
+            addInitDiagHospitalName(initDiags, suppleDiagDiags);
+        }
+        initDiags = initDiags.stream().distinct().collect(Collectors.toList());
+
+        String infoStr = "";
+        int matchSum = 0;
+        ModelAI modelAI = new ModelAI();
+        for (String presentPastDiag : presentPastDiags) {
+            JSONArray jsonArray = modelAI.loadChiefPresentSimilarAI(presentPastDiag, initDiags, false
+                    , "diagnose", chiefPresentSimilarityServiceClient);
+            if (jsonArray.size() == 2) {
+                /* 相似度最高症状 */
+                String symptom = jsonArray.getString(0);
+                /* 相似度分数 */
+                double likeRate = jsonArray.getDoubleValue(1);
+                if (likeRate > 0.85) {
+                    matchSum++;
+                } else {
+                    infoStr = CatalogueUtil.concatInfo(infoStr, presentPastDiag);
+                }
+            } else {
+                infoStr = CatalogueUtil.concatInfo(infoStr, presentPastDiag);
+            }
+        }
+        info.set(infoStr);
+        if (matchSum == presentPastDiags.size()) {
+            status.set("0");
+        }
+        /*
+        if (initDiags.containsAll(presentPastDiags)) {
+            status.set("0");
+        }
+         */
+    }
+
+    private void addDiagHospitalName(Set<String> presentPastDiag, List<Diag> pastDiags) {
+        for (Diag pastDiag : pastDiags) {
+            if (pastDiag.getNegative() != null) {
+                continue;
+            }
+            if (isContains(pastDiag.getHospitalDiagName()) && !isFilter(pastDiag.getHospitalDiagName())) {
+                presentPastDiag.add(pastDiag.getHospitalDiagName());
+            }
+        }
+    }
+
+    private void addInitDiagHospitalName(List<String> presentPastDiag, List<Diag> pastDiags) {
+        for (Diag pastDiag : pastDiags) {
+            if (pastDiag.getNegative() != null) {
+                continue;
+            }
+            presentPastDiag.add(pastDiag.getHospitalDiagName());
+        }
+    }
+
+    private boolean isHave(Set<String> presentDiag, String diagName) {
+        for (String haveDiag : presentDiag) {
+            if (haveDiag.contains(diagName) || diagName.contains(haveDiag)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isContains(String diagName) {
+        for (String c : containList) {
+            if (diagName.contains(c)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isFilter(String diagName) {
+        for (String c : filterList) {
+            if (diagName.contains(c)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    /* 原逻辑
+    Map<String, Map<String, Object>> diagMap = specialStorageUtil.getJsonStringValue(KernelConstants.CONCEPT_DIAG_PROPERTY_MAP);
+    String initDiagText = CatalogueUtil.removeSpecialChar(initialDiagLabel.getText());
+        if (pastLabel.getDiags() != null) {
+            List<Diag> diags = pastLabel.getDiags().stream().filter(diag -> diag.getNegative() == null).collect(Collectors.toList());
+            List<String> initDiags = Arrays.asList(initDiagText.split(","));
+            if (diags.size() > 0) {
+                for (Diag diag : diags) {
+                    Map<String, Object> map = (Map<String, Object>) diagMap.get(diag.getName());
+                    if (map != null && map.size() > 0) {
+                        String chronic = (String) map.get("chronic");//1是慢病
+                        if ("1".equals(chronic) && !initDiags.contains(diag.getName())) {
+                            if (StringUtils.isEmpty(info.get())) {
+                                info.set(diag.getName());
+                            } else {
+                                info.set(info.get() + "," + diag.getName());
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if (StringUtils.isEmpty(info.get())) {
+            status.set("0");
+        }
+     */
+}

+ 73 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0013.java

@@ -0,0 +1,73 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.google.common.collect.Lists;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+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.entity.Clinical;
+import com.lantone.qc.pub.model.label.PastLabel;
+import com.lantone.qc.pub.model.label.PresentLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * @ClassName : BEH0013
+ * @Description :  现病史缺少有鉴别意义的阴性症状
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class BEH0013 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        List<String> words = Lists.newArrayList("无", "否认", "内固定", "诱因");
+        BeHospitalizedDoc beHospitalizedDoc = inputInfo.getBeHospitalizedDoc();
+        if (beHospitalizedDoc == null) {
+            return;
+        }
+        //现病史
+        PresentLabel presentLabel = beHospitalizedDoc.getPresentLabel();
+        //既往史
+        PastLabel pastLabel = beHospitalizedDoc.getPastLabel();
+        //入院记录存在一般情况
+        Map<String, String> structureMap_bh = beHospitalizedDoc.getStructureMap();
+        String generalCondition = structureMap_bh.get("一般情况");
+        if (StringUtil.isNotBlank(generalCondition) && presentLabel == null) {
+            for (String word : words) {
+                if (generalCondition.contains(word)) {
+                    return;
+                }
+            }
+        }
+        if ((presentLabel == null || StringUtil.isBlank(presentLabel.getText()) || "。".equals(presentLabel.getText()))
+                && (pastLabel == null || StringUtil.isBlank(pastLabel.getText()) || "。".equals(pastLabel.getText()))) {
+            return;
+        }
+        String text = presentLabel.getText();
+        if (StringUtil.isNotBlank(text)) {
+            for (String word : words) {
+                if (text.contains(word)) {
+                    return;
+                }
+            }
+        }
+        List<Clinical> clinicalNegative = new ArrayList<>();
+        List<Clinical> clinicals = presentLabel.getClinicals();
+        if (clinicals.size() > 0) {
+            for (Clinical clinical : clinicals) {
+                if (clinical.getNegative() != null) {
+                    clinicalNegative.add(clinical);
+                }
+            }
+        }
+        if (clinicalNegative.size() == 0) {
+            status.set("-1");
+        }
+    }
+}

+ 118 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0014.java

@@ -0,0 +1,118 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+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.entity.Cause;
+import com.lantone.qc.pub.model.entity.Clinical;
+import com.lantone.qc.pub.model.entity.Diag;
+import com.lantone.qc.pub.model.label.PastLabel;
+import com.lantone.qc.pub.model.label.PresentLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * @ClassName : BEH0014
+ * @Description :  现病史症状缺少诱因
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class BEH0014 extends QCCatalogue {
+    private List<String> containList = Arrays.asList("体检", "发现", "检查", "因", "确诊", "诊断", "复查", "术后"
+            , "药物", "误服", "查", "撞", "伤", "月经", "暴力", "超", "术");
+
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        BeHospitalizedDoc beHospitalizedDoc = inputInfo.getBeHospitalizedDoc();
+        if (beHospitalizedDoc == null) {
+            status.set("0");
+            return;
+        }
+        /*List<Clinical> clinicals = inputInfo.getBeHospitalizedDoc().getPresentLabel().getClinicals();
+        if(clinicals.size()>0){
+            Clinical clinical = clinicals.get(0);
+            String clinicalName = clinical.getName();
+            Cause cause = clinical.getCause();
+            if(cause == null){
+                info.set(clinicalName);
+            }else {
+                status.set("0");
+            }
+        }*/
+        PresentLabel presentLabel = inputInfo.getBeHospitalizedDoc().getPresentLabel();
+        Map<String, String> structureMap_bh = beHospitalizedDoc.getStructureMap();
+        String generalCondition = structureMap_bh.get("一般情况");
+        if (StringUtil.isNotBlank(generalCondition) && presentLabel == null) {
+            //能取到一般情况,前30个字有"体检"或"发现"或"检查"(containList)字样
+            if (isInducement(generalCondition)) {
+                status.set("0");
+                return;
+            }
+        }
+        //既往史
+        PastLabel pastLabel = inputInfo.getBeHospitalizedDoc().getPastLabel();
+        if ((presentLabel == null || StringUtil.isBlank(presentLabel.getText()) || "。".equals(presentLabel.getText()))
+                && (pastLabel == null || StringUtil.isBlank(pastLabel.getText()) || "。".equals(pastLabel.getText()))) {
+            status.set("0");
+            return;
+        }
+        List<Clinical> clinicals = presentLabel.getClinicals();
+        if (ListUtil.isNotEmpty(clinicals)) {
+            for (Clinical clinical : clinicals) {
+                if (clinical.getCause() != null) {
+                    status.set("0");
+                    return;
+                }
+            }
+        }
+        //硬规则匹配 前30个字有"体检"或"发现"或"检查"(containList)字样
+        String present = presentLabel.getText();
+        if (StringUtils.isNotEmpty(present)) {
+            if (isInducement(present)) {
+                status.set("0");
+                return;
+            }
+            //模型在现病史前30个字里能提出来疾病,那也可以算有诱因
+            List<Diag> presentDiags = presentLabel.getDiags();
+            if (presentDiags.size() > 0) {
+                for (Diag diag : presentDiags) {
+                    String hospitalDiagName = diag.getHospitalDiagName();
+                    if (StringUtil.isBlank(hospitalDiagName)) {
+                        continue;
+                    }
+                    if (present.contains(hospitalDiagName)) {
+                        status.set("0");
+                        return;
+                    }
+                }
+            }
+        }
+
+        List<Cause> causes = presentLabel.getCauses();
+        if (causes != null && causes.size() > 0) {
+            status.set("0");
+        }
+    }
+
+    //判断一般情况和现病史中是否含有containList字样
+    private boolean isInducement(String text) {
+        if (text.length() > 50) {
+            text = text.substring(0, 50);
+        }
+        text = text.replaceAll("[\"“”]", "");
+        for (String word : containList) {
+            if (text.contains(word)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}

+ 59 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0022.java

@@ -0,0 +1,59 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+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.entity.General;
+import com.lantone.qc.pub.model.entity.GeneralDesc;
+import com.lantone.qc.pub.model.label.PresentLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * @ClassName : BEH0022
+ * @Description :  现病史缺少发病以来一般情况描述
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class BEH0022 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        PresentLabel presentLabel = inputInfo.getBeHospitalizedDoc().getPresentLabel();
+        if (presentLabel == null || StringUtil.isBlank(presentLabel.getText())) {
+            status.set("0");
+            return;
+        }
+        String presentText = presentLabel.getText();
+        if (presentText.contains("发病以来")) {
+            status.set("0");
+            return;
+        }
+        List<GeneralDesc> generals = presentLabel.getGenerals();
+        if (generals != null && generals.size() > 0) {
+            status.set("0");
+            return;
+        }
+        List<General> gens = inputInfo.getBeHospitalizedDoc().getPresentLabel().getGens();
+        if (gens != null && gens.size() > 0) {
+            status.set("0");
+            return;
+        }
+        //增加强判断,现病史有无"病来..."
+        BeHospitalizedDoc beHospitalizedDoc = inputInfo.getBeHospitalizedDoc();
+        Map<String, String> beHospitalizedDocStructureMap = beHospitalizedDoc.getStructureMap();
+        if (beHospitalizedDocStructureMap.get("现病史") != null && (beHospitalizedDocStructureMap.get("现病史").contains("病来")
+                || beHospitalizedDocStructureMap.get("现病史").contains("孕来"))) {
+            status.set("0");
+            return;
+        }
+    }
+}

+ 60 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0024.java

@@ -0,0 +1,60 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Wound;
+import com.lantone.qc.pub.model.label.PastLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Description: 外伤史未填写
+ * @author: rengb
+ * @time: 2020/3/10 13:53
+ */
+@Component
+public class BEH0024 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        //台州结构化
+        Map<String, String> behStructureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+        if (StringUtils.isNotEmpty(behStructureMap.get("手术外伤史"))) {
+            status.set("0");
+            return;
+        }
+        String past = behStructureMap.get("既往史");
+        if (StringUtil.isNotBlank(past) && past.contains("外伤史")) {
+            status.set("0");
+            return;
+        }
+        PastLabel pastLabel = inputInfo.getBeHospitalizedDoc().getPastLabel();
+        /* 如果既往史为空或者既往史文本为空,则不报错 */
+        if (pastLabel == null || StringUtil.isBlank(pastLabel.getText())) {
+            status.set("0");
+            return;
+        }
+        List<Wound> wounds = pastLabel.getWounds();
+        if (ListUtil.isNotEmpty(wounds)) {
+            if (wounds.stream().map(i -> i.getName()).filter(i -> StringUtil.isNotBlank(i)).count() > 0) {
+                status.set("0");
+                return;
+            }
+        }
+        //硬规则匹配
+        String pastLabelText = pastLabel.getText();
+        if (pastLabelText.contains("外伤") || pastLabelText.contains("详见原病历") || pastLabelText.contains("骨折")) {
+            status.set("0");
+        }
+    }
+}

+ 80 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0025.java

@@ -0,0 +1,80 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Diag;
+import com.lantone.qc.pub.model.entity.Operation;
+import com.lantone.qc.pub.model.label.PastLabel;
+import com.lantone.qc.pub.model.label.PresentLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Description: 手术史未填写
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0025 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        //台州结构化
+        Map<String, String> behStructureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+        if (StringUtils.isNotEmpty(behStructureMap.get("手术外伤史"))) {
+            status.set("0");
+            return;
+        }
+        PastLabel pastLabel = inputInfo.getBeHospitalizedDoc().getPastLabel();
+        /* 如果既往史为空或者既往史文本为空,则不报错 */
+        if (pastLabel == null || StringUtil.isBlank(pastLabel.getText())) {
+            status.set("0");
+            return;
+        }
+        List<Operation> operations = pastLabel.getOperations();
+        if (ListUtil.isNotEmpty(operations)) {
+            if (operations.stream().map(i -> i.getName()).filter(i -> StringUtil.isNotBlank(i)).count() > 0) {
+                status.set("0");
+                return;
+            }
+        }
+        /* 疾病名称:**术后**,算是有手术史 */
+        List<Diag> diags = pastLabel.getDiags();
+        for (Diag diag : diags) {
+            String hospitalDiagName = diag.getHospitalDiagName();
+            if (StringUtil.isBlank(hospitalDiagName)) {
+                continue;
+            }
+            if (hospitalDiagName.contains("术后")) {
+                status.set("0");
+                return;
+            }
+        }
+        //规则硬匹配
+        String pastLabelText = pastLabel.getText();
+        if (pastLabelText.contains("手术") || pastLabelText.contains("详见原病历")
+                || pastLabelText.contains("体外碎石") || pastLabelText.contains("术后")
+                || pastLabelText.matches(".*行.*术.*")) {
+            status.set("0");
+        }
+        //现病史里出现手术记录也不报
+        PresentLabel presentLabel=inputInfo.getBeHospitalizedDoc().getPresentLabel();
+        String presentText=presentLabel.getText();
+        if(presentText.contains("手术") || presentText.contains("详见原病历")
+                || presentText.contains("体外碎石") || presentText.contains("术后")
+                || presentText.matches(".*行.*术.*")){
+            status.set("0");
+        }
+    }
+
+}

+ 65 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0026.java

@@ -0,0 +1,65 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Allergy;
+import com.lantone.qc.pub.model.label.PastLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Description: 食物过敏史未填写
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0026 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        Map<String, String> structureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+        String past = structureMap.get("既往史");
+        if (StringUtil.isNotBlank(past) && past.contains("食物过敏史")) {
+            status.set("0");
+            return;
+        }
+        if (StringUtils.isNotEmpty(structureMap.get("过敏史"))) {
+            status.set("0");
+            return;
+        }
+        PastLabel pastLabel = inputInfo.getBeHospitalizedDoc().getPastLabel();
+        /* 如果既往史为空或者既往史文本为空,则不报错 */
+        if (pastLabel == null || StringUtil.isBlank(pastLabel.getText())) {
+            status.set("0");
+            return;
+        }
+        String pastText = pastLabel.getText();
+        if (pastText.contains("过敏史") || pastText.contains("详见原病历")) {
+            status.set("0");
+            return;
+        }
+        List<Allergy> allergies = pastLabel.getAllergies();
+        if (ListUtil.isNotEmpty(allergies)) {
+            long count = allergies.stream().filter(
+                    i -> i != null
+                            && StringUtil.isNotBlank(i.getName())
+                    //                            && i.getAllergyFood() != null
+                    //                            && StringUtil.isNotBlank(i.getAllergyFood().getName())
+            ).count();
+            if (count > 0) {
+                status.set("0");
+            }
+        }
+    }
+
+}

+ 59 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0028.java

@@ -0,0 +1,59 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.BloodTransfusion;
+import com.lantone.qc.pub.model.label.PastLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Description: 输血史未填写
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0028 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        Map<String, String> behStructure = inputInfo.getBeHospitalizedDoc().getStructureMap();
+        if (StringUtils.isNotEmpty(behStructure.get("输血史"))) {
+            status.set("0");
+            return;
+        }
+        String past = behStructure.get("既往史");
+        if (StringUtil.isNotBlank(past) && past.contains("输血史")) {
+            status.set("0");
+            return;
+        }
+        PastLabel pastLabel = inputInfo.getBeHospitalizedDoc().getPastLabel();
+        /* 如果既往史为空或者既往史文本为空,则不报错 */
+        if (pastLabel == null || StringUtil.isBlank(pastLabel.getText())) {
+            status.set("0");
+            return;
+        }
+        String pastText = pastLabel.getText();
+        if (pastText.contains("输血") || pastText.contains("详见原病历")) {
+            status.set("0");
+            return;
+        }
+        List<BloodTransfusion> bloodTransfusions = pastLabel.getBloodTransfusions();
+        if (ListUtil.isNotEmpty(bloodTransfusions)) {
+            if (bloodTransfusions.stream().map(i -> i.getName()).filter(i -> StringUtil.isNotBlank(i)).count() > 0) {
+                status.set("0");
+            }
+        }
+    }
+
+}

+ 90 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0029.java

@@ -0,0 +1,90 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+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.entity.Vaccinate;
+import com.lantone.qc.pub.model.label.PastLabel;
+import com.lantone.qc.pub.model.label.PersonalLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Description: 预防接种史未填写
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0029 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        BeHospitalizedDoc beHospitalizedDoc = inputInfo.getBeHospitalizedDoc();
+        //台州结构化
+        Map<String, String> structureMap = beHospitalizedDoc.getStructureMap();
+        if (StringUtils.isNotEmpty(structureMap.get("预防接种史"))) {
+            status.set("0");
+            return;
+        }
+        String past = structureMap.get("既往史");
+        if (StringUtil.isNotBlank(past) && past.contains("预防接种")) {
+            status.set("0");
+            return;
+        }
+        PastLabel pastLabel = beHospitalizedDoc.getPastLabel();
+        //个人史
+        PersonalLabel personalLabel = beHospitalizedDoc.getPersonalLabel();
+        /* 如果既往史为空或者既往史文本为空,则不报错 */
+        if ((pastLabel == null || StringUtil.isBlank(pastLabel.getText())) &&
+                (personalLabel == null || StringUtil.isBlank(personalLabel.getText()))) {
+            status.set("0");
+            return;
+        }
+        if (pastLabel != null && pastLabel.getText() != null) {
+            String pastText = pastLabel.getText();
+            if (pastText.contains("详见原病历") || pastText.contains("预防接种")) {
+                status.set("0");
+                return;
+            }
+            List<Vaccinate> vaccinates = pastLabel.getVaccinates();
+            if (ListUtil.isNotEmpty(vaccinates)) {
+                if (vaccinates.stream().map(i -> i.getName()).filter(i -> StringUtil.isNotBlank(i)).count() > 0) {
+                    status.set("0");
+                }
+            }
+        }
+        if (personalLabel != null && personalLabel.getText() != null) {
+            String personText = personalLabel.getText();
+            if (StringUtil.isNotBlank(personText) && (personText.contains("详见原病历") || personText.contains("预防接种"))) {
+                status.set("0");
+                return;
+            }
+        }
+        //直接map拿既往史、个人史
+        if (structureMap.get("既往史") != null) {
+            String pastText = structureMap.get("既往史");
+            if (pastText.contains("详见原病历") || pastText.contains("预防接种")) {
+                status.set("0");
+                return;
+            }
+        }
+        if (structureMap.get("个人史") != null) {
+            String personText = structureMap.get("个人史");
+            if (personText.contains("详见原病历") || personText.contains("预防接种")) {
+                status.set("0");
+                return;
+            }
+        }
+    }
+
+}

+ 71 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0030.java

@@ -0,0 +1,71 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.label.FamilyLabel;
+import com.lantone.qc.pub.model.label.PastLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @Description: 传染病史未填写
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0030 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        Map<String, String> structureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+        if (StringUtils.isNotEmpty(structureMap.get("结核病")) || StringUtils.isNotEmpty(structureMap.get("病毒性肝炎"))) {
+            status.set("0");
+            return;
+        }
+        PastLabel pastLabel = inputInfo.getBeHospitalizedDoc().getPastLabel();
+        FamilyLabel familyLabel = inputInfo.getBeHospitalizedDoc().getFamilyLabel();
+        /* 如果既往史为空或者既往史文本为空,则不报错 */
+        if ((pastLabel == null || StringUtil.isBlank(pastLabel.getText())) && (familyLabel == null || StringUtil.isBlank(familyLabel.getText()))) {
+            status.set("0");
+            return;
+        }
+        if (ListUtil.isNotEmpty(
+                CatalogueUtil.filterDiagsByNature(
+                        pastLabel.getDiags(),
+                        "infectious",
+                        "1"
+                )
+        )) {
+            status.set("0");
+        }
+        String familyText = null;
+        String pastText = pastLabel.getText();
+        if (familyLabel != null) {
+            familyText = familyLabel.getText();
+        }
+        String pastText1 = structureMap.get("既往史");
+        if (pastText != null && (pastText.contains("肝炎") || pastText.contains("结核") || pastText.contains("详见原病历")
+                || pastText.contains("乙肝") || pastText.contains("传染病史"))) {
+            status.set("0");
+        }
+        if (familyText != null && (familyText.contains("肝炎") || familyText.contains("结核") || familyText.contains("详见原病历")
+                || familyText.contains("乙肝"))) {
+            status.set("0");
+        }
+        if (pastText1 != null && (pastText1.contains("肝炎") || pastText1.contains("结核") || pastText1.contains("详见原病历")
+                || pastText1.contains("乙肝") || pastText1.contains("传染病史"))) {
+            status.set("0");
+        }
+    }
+
+}

+ 78 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0031.java

@@ -0,0 +1,78 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.google.common.collect.Lists;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.util.ListUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Description: 慢病史未填写
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0031 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        Map<String, String> structureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+        if (StringUtils.isNotEmpty(structureMap.get("高血压"))) {
+            status.set("0");
+            return;
+        }
+
+        if (ListUtil.isNotEmpty(
+                CatalogueUtil.filterDiagsByNature(
+                        inputInfo.getBeHospitalizedDoc().getPastLabel().getDiags(),
+                        "chronic",
+                        "1"
+                )
+        )) {
+            status.set("0");
+        }
+        //硬规则匹配
+        String text = inputInfo.getBeHospitalizedDoc().getPastLabel().getText();
+        if (StringUtils.isNotEmpty(text)) {
+            List<String> words = Lists.newArrayList("高血压", "糖尿病", "阿尔茨海默病", "帕金森", "冠心病心律失常型"
+                    , "冠状动脉性心脏病", "冠状动脉粥样硬化性心脏病", "慢性肾炎综合征", "肾病", "慢性肾衰竭", "肾功能异常", "哮喘"
+                    , "肺结核", "腹膜透析", "慢性阻塞性肺病", "精神分裂症", "分裂情感性精神病", "双相情感障碍,目前为缓解状态", "前列腺增生"
+                    , "高脂血症", "高低密度脂蛋白胆固醇血症", "高胆固醇血症", "高甘油三酯血症", "骨质疏松", "慢性乙型病毒性肝炎"
+                    , "慢性庚型肝炎", "慢性肝炎", "慢性丁型肝炎", "慢性病毒性肝炎", "慢性丙型病毒性肝炎", "酒精性肝病", "脂肪肝"
+                    , "肝硬化", "肝恶性肿瘤", "肝恶性细胞瘤", "肝病", "类风湿性关节炎", "心脑血管", "内分泌","肝炎","结核");
+            for (String word : words) {
+                if (text.contains(word)) {
+                    status.set("0");
+                    return;
+                }
+            }
+        }
+        //直接匹配map中既往史
+        String text1 = structureMap.get("既往史");
+        if (StringUtils.isNotEmpty(text1)) {
+            List<String> words = Lists.newArrayList("高血压", "糖尿病", "阿尔茨海默病", "帕金森", "冠心病心律失常型"
+                    , "冠状动脉性心脏病", "冠状动脉粥样硬化性心脏病", "慢性肾炎综合征", "肾病", "慢性肾衰竭", "肾功能异常", "哮喘"
+                    , "肺结核", "腹膜透析", "慢性阻塞性肺病", "精神分裂症", "分裂情感性精神病", "双相情感障碍,目前为缓解状态", "前列腺增生"
+                    , "高脂血症", "高低密度脂蛋白胆固醇血症", "高胆固醇血症", "高甘油三酯血症", "骨质疏松", "慢性乙型病毒性肝炎"
+                    , "慢性庚型肝炎", "慢性肝炎", "慢性丁型肝炎", "慢性病毒性肝炎", "慢性丙型病毒性肝炎", "酒精性肝病", "脂肪肝"
+                    , "肝硬化", "肝恶性肿瘤", "肝恶性细胞瘤", "肝病", "类风湿性关节炎", "心脑血管", "内分泌","肝炎","结核");
+            for (String word : words) {
+                if (text1.contains(word)) {
+                    status.set("0");
+                    return;
+                }
+            }
+        }
+    }
+
+}

+ 47 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0032.java

@@ -0,0 +1,47 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Diag;
+import com.lantone.qc.pub.model.label.PastLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @Description: 疾病名未标引号
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0032 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if(inputInfo.getBeHospitalizedDoc() == null){
+            return;
+        }
+        PastLabel pastLabel = inputInfo.getBeHospitalizedDoc().getPastLabel();
+        List<Diag> diags = pastLabel.getDiags();
+        if (ListUtil.isEmpty(diags)) {
+            return;
+        }
+        List<String> wtDiagNames = CatalogueUtil.noInQuotes(
+                diags.stream().filter(diag -> diag.getNegative() == null).map(i -> i.getHospitalDiagName()).filter(i -> StringUtil.isNotEmpty(i)).distinct().collect(Collectors.toList()),
+                pastLabel.getText().replace("“","\"").replace("”","\"")
+        );
+        if (ListUtil.isNotEmpty(wtDiagNames)) {
+            status.set("-1");
+            for (String wtDiagName : wtDiagNames) {
+                info.set(info.get() + wtDiagName + " ");
+            }
+        }
+    }
+
+}

+ 54 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0034.java

@@ -0,0 +1,54 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Operation;
+import com.lantone.qc.pub.model.label.PastLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @Description: 手术名称未标引号
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0034 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if(inputInfo.getBeHospitalizedDoc() == null){
+            return;
+        }
+        PastLabel pastLabel = inputInfo.getBeHospitalizedDoc().getPastLabel();
+        List<Operation> operations = pastLabel.getOperations();
+        if (ListUtil.isEmpty(operations)) {
+            return;
+        }
+        List<String> wtOperationNames = CatalogueUtil.noInQuotes(
+                operations.stream()
+                        .filter(i ->
+                                i != null && StringUtil.isNotBlank(i.getName()) && i.getNegative() == null
+                                        && !"手术史".equals(i.getName())  && !"手术".equals(i.getName()) && !"手术治疗".equals(i.getName())
+                        )
+                        .map(i -> i.getName())
+                        .distinct()
+                        .collect(Collectors.toList()),
+                pastLabel.getText().replace("“","\"").replace("”","\"")
+        );
+        if (ListUtil.isNotEmpty(wtOperationNames)) {
+            status.set("-1");
+            for (String wtOperationName : wtOperationNames) {
+                info.set(info.get() + wtOperationName + " ");
+            }
+        }
+    }
+
+}

+ 54 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0035.java

@@ -0,0 +1,54 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Allergy;
+import com.lantone.qc.pub.model.label.PastLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @Description: 过敏药物未标引号
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0035 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if(inputInfo.getBeHospitalizedDoc() == null){
+            return;
+        }
+        PastLabel pastLabel = inputInfo.getBeHospitalizedDoc().getPastLabel();
+        List<Allergy> allergies = pastLabel.getAllergies();
+        if (ListUtil.isEmpty(allergies)) {
+            return;
+        }
+
+        List<String> wtAmNames = CatalogueUtil.noInQuotes(
+                allergies.stream().filter(
+                        i -> i != null && StringUtil.isNotBlank(i.getName()) && i.getNegative() == null
+                                && i.getAllergyMedicine() != null && StringUtil.isNotBlank(i.getAllergyMedicine().getName()))
+                        .map(i -> i.getAllergyMedicine().getName()).distinct().collect(Collectors.toList()),
+                pastLabel.getText()
+        );
+        if(wtAmNames.contains("止痛片")){
+            return;
+        }
+        if (ListUtil.isNotEmpty(wtAmNames)) {
+            status.set("-1");
+            for (String wtAmName : wtAmNames) {
+                info.set(info.get() + wtAmName + " ");
+            }
+        }
+    }
+
+}

+ 59 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0039.java

@@ -0,0 +1,59 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Allergy;
+import com.lantone.qc.pub.model.label.PastLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * @Description: 食物过敏史描述不完整
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0039 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            return;
+        }
+        PastLabel pastLabel = inputInfo.getBeHospitalizedDoc().getPastLabel();
+        if (pastLabel == null) {
+            return;
+        }
+        String pastText = pastLabel.getText();
+        if (StringUtil.isNotBlank(pastText) && pastText.contains("食物过敏史")) {
+            return;
+        }
+        List<Allergy> allergies = pastLabel.getAllergies();
+        if (ListUtil.isEmpty(allergies)) {
+            return;
+        }
+        for (Allergy allergy : allergies) {
+            if (allergy == null
+                    || StringUtil.isBlank(allergy.getName())
+                    || allergy.getAllergyFood() == null
+                    || StringUtil.isBlank(allergy.getAllergyFood().getName())) {
+                continue;
+            }
+            if ((allergy.getNegative() == null || StringUtil.isBlank(allergy.getNegative().getName()))
+                    && (allergy.getAllergyFood().getPd() == null || StringUtil.isBlank(allergy.getAllergyFood().getPd().getName()))
+                    && (allergy.getAllergyFood().getDegree() == null || StringUtil.isBlank(allergy.getAllergyFood().getDegree().getName()))
+                    && (allergy.getAllergyFood().getAllergyDesc() == null || StringUtil.isBlank(allergy.getAllergyFood().getAllergyDesc().getName()))) {
+                info.set(info.get() + allergy.getAllergyFood().getName() + " ");
+            }
+        }
+        if (StringUtil.isNotBlank(info.get())) {
+            status.set("-1");
+        }
+    }
+
+}

+ 42 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0041.java

@@ -0,0 +1,42 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @Description: 个人史未填写
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0041 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if(inputInfo.getBeHospitalizedDoc() == null){
+            status.set("0");
+            return;
+        }
+        Map<String, String> structureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+        //以台州为例,个人史细分很多结构化信息,取其一
+        if (StringUtils.isNotEmpty(structureMap.get("出生、生长史"))
+                || StringUtils.isNotEmpty(structureMap.get("疫区居留史"))
+                || StringUtils.isNotEmpty(structureMap.get("冶游史"))
+                || StringUtils.isNotEmpty(structureMap.get("工作性质"))
+                || StringUtils.isNotEmpty(structureMap.get("化学及放射性毒物接触史"))) {
+            status.set("0");
+            return;
+        }
+
+        if (inputInfo.getBeHospitalizedDoc().getPersonalLabel() != null && StringUtil.isNotBlank(inputInfo.getBeHospitalizedDoc().getPersonalLabel().getText())) {
+            status.set("0");
+        }
+    }
+
+}

+ 70 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0043.java

@@ -0,0 +1,70 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Address;
+import com.lantone.qc.pub.model.label.PersonalLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * @Description: 居住地未描述
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0043 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        //台州结构化
+        Map<String, String> structureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+        if (StringUtils.isNotEmpty(structureMap.get("户口地址")) || StringUtils.isNotEmpty(structureMap.get("出生地"))
+        ) {
+            status.set("0");
+            return;
+        }
+
+        PersonalLabel personalLabel = inputInfo.getBeHospitalizedDoc().getPersonalLabel();
+        if (personalLabel == null) {
+            status.set("0");
+            return;
+        }
+        String text = personalLabel.getText();
+        if (StringUtil.isBlank(text) || text.contains("居住") || text.contains("生长") || text.contains("生活")
+                || text.contains("详见原病历")) {
+            status.set("0");
+            return;
+        }
+        List<Address> addresses = personalLabel.getAddresses();
+        if (ListUtil.isNotEmpty(addresses)) {
+            long count = addresses.stream().filter(i -> {
+                boolean flag = false;
+                if (i != null && StringUtil.isNotBlank(i.getName())) {
+                    if (i.getName().indexOf("居住") > -1) {
+                        flag = true;
+                    } else {
+                        Pattern pattern = Pattern.compile("[\\s\\S]*(居住|生长)[\\s\\S]{0,5}" + i.getName() + "[\\s\\S]*");
+                        flag = pattern.matcher(text).matches();
+                    }
+                }
+                return flag;
+            }).count();
+            if (count > 0) {
+                status.set("0");
+            }
+        }
+    }
+
+}

+ 57 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0044.java

@@ -0,0 +1,57 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.EpidemicArea;
+import com.lantone.qc.pub.model.label.PersonalLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @Description: 疫区接触史未描述
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0044 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        //台州结构化
+        Map<String, String> structureMap_beh = inputInfo.getBeHospitalizedDoc().getStructureMap();
+        if (StringUtils.isNotEmpty(structureMap_beh.get("疫区居留史"))) {
+            status.set("0");
+            return;
+        }
+        PersonalLabel personalLabel = inputInfo.getBeHospitalizedDoc().getPersonalLabel();
+        if (personalLabel == null || StringUtil.isBlank(personalLabel.getText())) {
+            status.set("0");
+            return;
+        }
+        String personalText = personalLabel.getText();
+        if (personalText.contains("详见病历") || personalText.contains("疫区") || personalText.contains("高危地区")
+                || personalText.contains("疫水") || personalText.contains("疫源") ){
+            status.set("0");
+            return;
+        }
+        //北仑硬匹配
+        if (personalText.contains("否认疫水疫源接触史") || personalText.contains("否认疫区、疫情、疫水接触史")
+                || personalText.contains("否认其他疫区、疫情、疫水接触史") || personalText.contains("否认发病前14天内曾接触过来自武汉市及周边地区")) {
+            status.set("0");
+            return;
+        }
+        EpidemicArea epidemicArea = personalLabel.getEpidemicArea();
+        if (epidemicArea != null && StringUtil.isNotBlank(epidemicArea.getName())) {
+            status.set("0");
+        }
+    }
+
+}

+ 54 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0045.java

@@ -0,0 +1,54 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.MaritalHistory;
+import com.lantone.qc.pub.model.label.PersonalLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @Description: 冶游史未描述
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0045 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        //台州结构化
+        Map<String, String> structureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+        if (StringUtils.isNotEmpty(structureMap.get("冶游史"))) {
+            status.set("0");
+            return;
+        }
+        PersonalLabel personalLabel = inputInfo.getBeHospitalizedDoc().getPersonalLabel();
+        if (personalLabel == null || StringUtil.isBlank(personalLabel.getText())) {
+            status.set("0");
+            return;
+        }
+        String personalText = personalLabel.getText();
+        if (personalText.contains("冶游史") || personalText.contains("详见原病历")) {
+            status.set("0");
+            return;
+        }
+        MaritalHistory maritalHistory = personalLabel.getMaritalHistory();
+        if (maritalHistory != null && StringUtil.isNotBlank(maritalHistory.getName())) {
+            status.set("0");
+        }
+        //针对切词获得的个人史
+        if(structureMap.get("个人史").contains("不洁性交史")){
+            status.set("0");
+        }
+    }
+
+}

+ 60 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0048.java

@@ -0,0 +1,60 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Contact;
+import com.lantone.qc.pub.model.label.PastLabel;
+import com.lantone.qc.pub.model.label.PersonalLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @Description: 放射物、毒物、粉尘接触史未描述
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0048 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        Map<String, String> structureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+        if (StringUtils.isNotEmpty(structureMap.get("化学及放射性毒物接触史"))) {
+            status.set("0");
+            return;
+        }
+
+        PersonalLabel personalLabel = inputInfo.getBeHospitalizedDoc().getPersonalLabel();
+        if (personalLabel == null || StringUtil.isBlank(personalLabel.getText())) {
+            status.set("0");
+            return;
+        }
+        String personalText = personalLabel.getText();
+        if (personalText.contains("详见原病历") || personalText.contains("放射") || personalText.contains("粉尘") || personalText.contains("毒物")) {
+            status.set("0");
+            return;
+        }
+        Contact contact = personalLabel.getContact();
+        if (contact != null && StringUtil.isNotBlank(contact.getName())) {
+            status.set("0");
+        }
+
+        PastLabel pastLabel = inputInfo.getBeHospitalizedDoc().getPastLabel();
+        if(pastLabel != null && StringUtil.isNotBlank(pastLabel.getText())){
+            String pastLabelText = pastLabel.getText();
+            if(pastLabelText.contains("放射") || pastLabelText.contains("粉尘") || pastLabelText.contains("毒物")){
+                status.set("0");
+                return;
+            }
+        }
+    }
+
+}

+ 56 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0050.java

@@ -0,0 +1,56 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Smoking;
+import com.lantone.qc.pub.model.entity.Usage;
+import com.lantone.qc.pub.model.label.PersonalLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+/**
+ * @Description: 吸烟史患者描述不规范
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0050 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        PersonalLabel personalLabel = inputInfo.getBeHospitalizedDoc().getPersonalLabel();
+        if (personalLabel == null) {
+            status.set("0");
+            return;
+        }
+        String personalText = personalLabel.getText();
+        if (StringUtil.isNotBlank(personalText) && personalText.contains("偶有")) {
+            status.set("0");
+            return;
+        }
+        if (StringUtil.isNotBlank(personalText) && (personalText.contains("无吸烟史") || personalText.contains("否认吸烟史"))
+                || personalText.contains("不吸烟")) {
+            status.set("0");
+            return;
+        }
+        Smoking smoking = personalLabel.getSmoking();
+        if (smoking == null
+                || StringUtil.isBlank(smoking.getName())
+                || (smoking.getNegative() != null && StringUtil.isNotBlank(smoking.getNegative().getName()))
+                || (smoking.getPd() != null && StringUtil.isNotBlank(smoking.getPd().getName()))
+                || (smoking.getUsage() != null && StringUtil.isNotBlank(smoking.getUsage().getName()))) {
+            status.set("0");
+        }
+        //出现用量实体,即认为规范
+        Usage usage = inputInfo.getBeHospitalizedDoc().getPersonalLabel().getUsage();
+        if (usage != null && StringUtil.isNotEmpty(usage.getName())) {
+            status.set("0");
+        }
+    }
+
+}

+ 75 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0053.java

@@ -0,0 +1,75 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.Content;
+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.entity.Marryiage;
+import com.lantone.qc.pub.model.label.MaritalLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @Description: 结婚年龄未描述
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0053 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        BeHospitalizedDoc beHospitalizedDoc = inputInfo.getBeHospitalizedDoc();
+        if (beHospitalizedDoc == null) {
+            status.set("0");
+            return;
+        }
+        //先取一次结构化数据
+        Map<String, String> beHospitalizedStructureMap = beHospitalizedDoc.getStructureMap();
+        String marryiAgeStr = beHospitalizedStructureMap.get("结婚年龄");
+        if (StringUtil.isNotBlank(marryiAgeStr)) {
+            status.set("0");
+            return;
+        }
+        //硬规则 匹配未婚
+        String marry = beHospitalizedDoc.getStructureMap().get(Content.marry);
+        if (StringUtil.isBlank(marry)) {
+            marry = beHospitalizedDoc.getStructureMap().get("婚姻状况");
+        }
+        MaritalLabel maritalLabel = beHospitalizedDoc.getMaritalLabel();
+        if (maritalLabel == null || StringUtil.isBlank(maritalLabel.getText())) {
+            status.set("0");
+            return;
+        }
+        String maritalText = maritalLabel.getText();
+        if ("未婚".equals(marry) || maritalText.contains("未婚") || maritalText.contains("详见原病历")
+                || maritalText.contains("离婚") || maritalText.contains("离异") || maritalText.contains("适龄结婚")) {
+            status.set("0");
+            return;
+        }
+        if (beHospitalizedDoc.getMaritalLabel() == null
+                || StringUtil.isBlank(beHospitalizedDoc.getMaritalLabel().getText())) {
+            status.set("0");
+        }
+
+        Marryiage marryiage = beHospitalizedDoc.getMaritalLabel().getMarryiage();
+        if (marryiage != null && StringUtil.isNotBlank(marryiage.getName())) {
+            status.set("0");
+        }
+        //硬规则 匹配婚育史text信息
+
+        String maritalText1=inputInfo.getBeHospitalizedDoc().getStructureMap().get("婚育史");
+        if (maritalText1.contains("未婚") || maritalText1.contains("详见原病历")
+                || maritalText1.contains("离婚") || maritalText1.contains("离异") || maritalText1.contains("适龄结婚")) {
+            status.set("0");
+            return;
+        }
+        if(maritalText1!=null && maritalText1.matches(".*[0-9]{2}岁.*")){
+            status.set("0");
+        }
+    }
+
+}

+ 64 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0054.java

@@ -0,0 +1,64 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.Content;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Consanguineous;
+import com.lantone.qc.pub.model.label.FamilyLabel;
+import com.lantone.qc.pub.model.label.MaritalLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+/**
+ * @Description: 是否近亲结婚未描述
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0054 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        //硬规则 未婚
+        String marry = inputInfo.getBeHospitalizedDoc().getStructureMap().get(Content.marry);
+        if (StringUtil.isBlank(marry)) {
+            marry = inputInfo.getBeHospitalizedDoc().getStructureMap().get("婚姻状况");
+        }
+        MaritalLabel maritalLabel = inputInfo.getBeHospitalizedDoc().getMaritalLabel();
+        FamilyLabel familyLabel = inputInfo.getBeHospitalizedDoc().getFamilyLabel();
+        if (maritalLabel == null) {
+            status.set("0");
+            return;
+        }
+        if ("未婚".equals(marry) || "离婚".equals(marry) || StringUtil.isBlank(maritalLabel.getText()) || maritalLabel.getText().contains("未婚")
+                || maritalLabel.getText().contains("详见原病历")) {
+            status.set("0");
+            return;
+        }
+        /* 有少数病历的近亲结婚时会写在家族史中(普通病历会写在婚育史里) */
+        if (familyLabel != null) {
+            String familyText = familyLabel.getText();
+            if (StringUtil.isNotBlank(familyText) && familyText.contains("近亲结婚")) {
+                status.set("0");
+                return;
+            }
+        }
+        Consanguineous consanguineous = inputInfo.getBeHospitalizedDoc().getMaritalLabel().getConsanguineous();
+        if (consanguineous != null && StringUtil.isNotBlank(consanguineous.getName())) {
+            status.set("0");
+        }
+
+        //硬规则 匹配婚育史text信息
+
+        String maritalText1 = inputInfo.getBeHospitalizedDoc().getStructureMap().get("婚育史");
+        if (StringUtil.isBlank(maritalText1) || maritalText1.contains("未婚") || maritalText1.contains("详见原病历") || maritalText1.contains("近亲")) {
+            status.set("0");
+        }
+    }
+
+}

+ 82 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0056.java

@@ -0,0 +1,82 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.Content;
+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.entity.ConjugalRelation;
+import com.lantone.qc.pub.model.label.MaritalLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @Description: 夫妻关系未描述
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0056 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        BeHospitalizedDoc beHospitalizedDoc = inputInfo.getBeHospitalizedDoc();
+        Map<String, String> structureMap = beHospitalizedDoc.getStructureMap();
+        if (StringUtils.isNotEmpty(structureMap.get("夫妻关系"))) {
+            status.set("0");
+            return;
+        }
+        //婚育史未填写,直接返回;
+        MaritalLabel maritalLabel = beHospitalizedDoc.getMaritalLabel();
+        if (maritalLabel == null || StringUtils.isEmpty(maritalLabel.getText())) {
+            status.set("0");
+            return;
+        }
+        //硬规则 匹配未婚
+        String marry = structureMap.get(Content.marry);
+        String text = maritalLabel.getText();
+
+        if (StringUtil.isNotBlank(text)) {
+            if (text.contains("未婚") || text.contains("离异") || text.contains("离婚") || text.contains("丧偶")
+                    || "未婚".equals(marry) || text.contains("详见原病历")) {
+                status.set("0");
+                return;
+            }
+        }
+        ConjugalRelation conjugalRelation = inputInfo.getBeHospitalizedDoc().getMaritalLabel().getConjugalRelation();
+        if (conjugalRelation != null) {
+            if (StringUtil.isNotBlank(conjugalRelation.getName())) {
+                status.set("0");
+                return;
+            }
+        }
+        if (inputInfo.getBeHospitalizedDoc().getMaritalLabel().getFamily() != null) {
+            long cont = inputInfo.getBeHospitalizedDoc().getMaritalLabel()
+                    .getFamily().stream()
+                    .filter(family -> family.getName().contains("配偶") && family.getDead() != null).count();
+            if (cont > 0) {
+                status.set("0");
+                return;
+            }
+        }
+        //硬规则 匹配婚育史text信息
+        String maritalText1=inputInfo.getBeHospitalizedDoc().getStructureMap().get("婚育史");
+        if (maritalText1.contains("未婚") || maritalText1.contains("详见原病历")
+                || maritalText1.contains("离婚") || maritalText1.contains("离异") || maritalText1.contains("适龄结婚")) {
+            status.set("0");
+            return;
+        }
+        if(maritalText1!=null && maritalText1.contains("夫妻关系")){
+            status.set("0");
+        }
+
+    }
+
+}

+ 108 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0058.java

@@ -0,0 +1,108 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.google.common.collect.Lists;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.Content;
+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.entity.Family;
+import com.lantone.qc.pub.model.entity.Fertility;
+import com.lantone.qc.pub.model.label.MaritalLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * @Description: 子女数量情况未描述
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0058 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        BeHospitalizedDoc beHospitalizedDoc = inputInfo.getBeHospitalizedDoc();
+        //硬规则 匹配未育
+        String marry = beHospitalizedDoc.getStructureMap().get(Content.marry);
+        MaritalLabel maritalLabel = beHospitalizedDoc.getMaritalLabel();
+        if (maritalLabel == null) {
+            status.set("0");
+            return;
+        }
+        Fertility fertility = maritalLabel.getFertility();
+        if (fertility != null) {
+            status.set("0");
+            return;
+        }
+        String maritalText = maritalLabel.getText();
+        if (StringUtil.isBlank(maritalText)) {
+            status.set("0");
+            return;
+        } else {
+            String regex = ".*\\d?子\\d?女.*";
+            boolean flag = maritalText.matches(regex);
+            regex = ".*\\d+-\\d+-\\d+-[1-9].*";
+            boolean matches = maritalText.matches(regex);
+            if (flag || matches) {
+                status.set("0");
+                return;
+            }
+        }
+        //硬规则 匹配未育
+        if ("未婚".equals(marry)) {
+            status.set("0");
+            return;
+        }
+        if (StringUtil.isNotBlank(maritalText)) {
+            List<String> words = Lists.newArrayList("未婚", "未育", "未婚育", "未生育", "未生", "0子0女"
+                    , "0-0-0-0", "详见原病历", "0-0-0-0");
+            for (String word : words) {
+                if (maritalText.contains(word)) {
+                    status.set("0");
+                    return;
+                }
+            }
+        }
+        Map<String, String> structureMap = beHospitalizedDoc.getStructureMap();
+        String familyMembersHealth = structureMap.get("家庭成员健康情况");
+        List<Family> familyList = Lists.newArrayList();
+        List<Family> familiesFl = inputInfo.getBeHospitalizedDoc().getFamilyLabel().getFamilies();
+        List<Family> familiesMl = inputInfo.getBeHospitalizedDoc().getMaritalLabel().getFamily();
+        if (ListUtil.isNotEmpty(familiesFl)) {
+            familyList.addAll(familiesFl);
+        }
+        if (ListUtil.isNotEmpty(familiesMl)) {
+            familyList.addAll(familiesMl);
+        }
+        Pattern p = Pattern.compile("[儿子女]");
+        if (StringUtil.isNotBlank(familyMembersHealth)) {
+            if (p.matcher(familyMembersHealth).find()) {
+                status.set("0");
+                return;
+            }
+        }
+        long count = familyList
+                .stream()
+                .filter(
+                        i -> i != null
+                                && StringUtil.isNotBlank(i.getName())
+                                && StringUtil.isContainNumber(i.getName())
+                                && p.matcher(i.getName()).find()
+                )
+                .count();
+        if (count > 0) {
+            status.set("0");
+        }
+    }
+
+}

+ 54 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0068.java

@@ -0,0 +1,54 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.label.MenstrualLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @ClassName : BEH0068
+ * @Description : 月经史未描述白带情况
+ * @Author : 胡敬
+ * @Date: 2020-03-11 14:49
+ */
+@Component
+public class BEH0068 extends QCCatalogue {
+    @Override
+    protected void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        if (inputInfo.getBeHospitalizedDoc().getStructureMap().get("性别") == null
+                || inputInfo.getBeHospitalizedDoc().getStructureMap().get("性别").contains("男")) {
+            status.set("0"); //如果性别是男,就不报错
+        } else if (inputInfo.getBeHospitalizedDoc().getMenstrualLabel() == null
+                || inputInfo.getBeHospitalizedDoc().getMenstrualLabel().getText().contains("null")) {
+            status.set("0");
+        } else {
+            Map<String, String> structureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+            if (StringUtil.isNotBlank(structureMap.get("白带"))) {
+                status.set("0");
+                return;
+            }
+            if (inputInfo.getBeHospitalizedDoc().getMenstrualLabel() != null) {
+                MenstrualLabel menstrualLabel = inputInfo.getBeHospitalizedDoc().getMenstrualLabel();
+                String text = menstrualLabel.getText();
+                if (StringUtil.isNotBlank(text) && (text.contains("未行经") || text.contains("未来潮") || text.contains("绝经") || text.contains("白带"))) {
+                    status.set("0");
+                    return;
+                }
+                if (menstrualLabel.getLeukorrheas() == null) {
+                    return;
+                }
+                if (menstrualLabel.getLeukorrheas().size() > 0) {
+                    status.set("0");
+                }
+            }
+        }
+    }
+}

+ 71 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0070.java

@@ -0,0 +1,71 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Diag;
+import com.lantone.qc.pub.model.entity.Family;
+import com.lantone.qc.pub.model.label.FamilyLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @ClassName : BEH0070
+ * @Description : 家族史未描述是否有家族性遗传病史及传染病史
+ * @Author : 胡敬
+ * @Date: 2020-03-11 15:09
+ */
+@Component
+public class BEH0070 extends QCCatalogue {
+    @Override
+    protected void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        Map<String, String> structureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+        String familyText = structureMap.get("家族史");
+        if (StringUtil.isNotBlank(familyText)) {
+            familyText = StringUtil.removeBlank(familyText);
+            if (familyText.contains("家族遗传病") || familyText.contains("结核") || familyText.contains("遗传")
+                    || familyText.contains("传染病")) {
+                status.set("0");
+                return;
+            }
+        }
+        if (inputInfo.getBeHospitalizedDoc().getFamilyLabel() != null) {
+            FamilyLabel familyLabel = inputInfo.getBeHospitalizedDoc().getFamilyLabel();
+            List<Family> families = familyLabel.getFamilies();
+            if (ListUtil.isEmpty(families)) {
+                status.set("0");
+                return;
+            }
+            boolean isFindGeneticDiseaseKeyword = false, isFindDiagInfectious = false;
+            for (Family family : families) {
+                if (family.getGeneticDiseaseKeyword() != null && StringUtil.isNotBlank(family.getGeneticDiseaseKeyword().getName())) {
+                    isFindGeneticDiseaseKeyword = true;
+                }
+                if (family.getDiagInfectious() != null && StringUtil.isNotBlank(family.getDiagInfectious().getName())) {
+                    isFindDiagInfectious = true;
+                }
+                if (family.getDiags() != null) {
+                    List<Diag> diags = family.getDiags().stream().filter(diag ->
+                            (diag.getHospitalDiagName() != null && diag.getHospitalDiagName().contains("炎"))
+                                    || (diag.getHospitalDiagName() != null && diag.getHospitalDiagName().contains("核"))).collect(Collectors.toList());
+                    if (diags.size() > 0) {
+                        isFindDiagInfectious = true;
+                    }
+                }
+                if (isFindGeneticDiseaseKeyword || isFindDiagInfectious) {
+                    status.set("0");
+                    return;
+                }
+            }
+        }
+    }
+}

+ 68 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0072.java

@@ -0,0 +1,68 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Dead;
+import com.lantone.qc.pub.model.entity.Family;
+import com.lantone.qc.pub.model.label.FamilyLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * @ClassName : BEH0072
+ * @Description : 家属有死亡者,未记录死亡原因
+ * @Author : 胡敬
+ * @Date: 2020-03-11 16:44
+ */
+@Component
+public class BEH0072 extends QCCatalogue {
+    @Override
+    protected void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getBeHospitalizedDoc() != null && inputInfo.getBeHospitalizedDoc().getFamilyLabel() != null) {
+            FamilyLabel familyLabel = inputInfo.getBeHospitalizedDoc().getFamilyLabel();
+            if (familyLabel == null) {
+                return;
+            }
+            String familyText = familyLabel.getText();
+            String familyText1= inputInfo.getBeHospitalizedDoc().getStructureMap().get("家族史");
+            if (StringUtil.isNotBlank(familyText)) {
+                familyText = familyText.substring(0, Math.min(15, familyText.length()));
+                if (familyText.contains("死因") || familyText.contains("原因") || familyText.contains("详")
+                || familyText.contains("因") || familyText.contains("死于")) {
+                    return;
+                }
+            }
+            //硬规则
+            if (StringUtil.isNotBlank(familyText1)) {
+                familyText1 = familyText1.substring(0, Math.min(15, familyText1.length()));
+                if (familyText1.contains("死因") || familyText1.contains("原因") || familyText1.contains("详")
+                        || familyText1.contains("因") || familyText1.contains("死于")) {
+                    return;
+                }
+            }
+            List<Family> families = familyLabel.getFamilies();
+            if (ListUtil.isEmpty(families)) {
+                return;
+            }
+            for (Family family : families) {
+                if (family.getDead() != null) {
+                    Dead dead = family.getDead();
+                    if (family.getName().contains("年迈") || dead.getNegative() != null) {
+                        continue;
+                    }
+                    if (dead.getDeadReason() != null || dead.getUnknow() != null) {
+                        return;
+                    } else {
+                        status.set("-1");
+                        return;
+                    }
+                }
+            }
+        }
+    }
+}

+ 75 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0073.java

@@ -0,0 +1,75 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Diag;
+import com.lantone.qc.pub.model.entity.Family;
+import com.lantone.qc.pub.model.label.FamilyLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : BEH0073
+ * @Description : 家族中是否有肝炎、结核等病史未描述
+ * @Author : 胡敬
+ * @Date: 2020-03-11 17:05
+ */
+@Component
+public class BEH0073 extends QCCatalogue {
+    @Override
+    protected void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        Map<String, String> structureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+        if (StringUtils.isNotEmpty(structureMap.get("病毒性肝炎")) || StringUtils.isNotEmpty(structureMap.get("结核病"))) {
+            status.set("0");
+            return;
+        }
+        String past = structureMap.get("既往史");
+        if (StringUtil.isNotBlank(past) && (past.contains("肝炎") || past.contains("结核"))) {
+            status.set("0");
+            return;
+        }
+        FamilyLabel familyLabel = inputInfo.getBeHospitalizedDoc().getFamilyLabel();
+        if (familyLabel == null || StringUtil.isBlank(familyLabel.getText())) {
+            status.set("0");
+            return;
+        }
+        String familyText = familyLabel.getText();
+        if (familyText.contains("肝炎") || familyText.contains("结核") || familyText.contains("详见原病历")) {
+            status.set("0");
+            return;
+        }
+        List<Family> families = familyLabel.getFamilies();
+        if (ListUtil.isNotEmpty(families)) {
+            for (Family family : families) {
+                if (family.getDiags() == null || family.getDiags().size() == 0) {
+                    continue;
+                }
+                for (Diag diag : family.getDiags()) {
+                    String hospitalDiagName = diag.getHospitalDiagName();
+                    String name = diag.getName();
+                    if (findDiag(hospitalDiagName) || findDiag(name)) {
+                        status.set("0");
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+    private boolean findDiag(String diagName) {
+        if (StringUtil.isBlank(diagName)) {
+            return false;
+        }
+        return diagName.contains("肝炎") || diagName.contains("结核");
+    }
+}

+ 47 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0075.java

@@ -0,0 +1,47 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Family;
+import com.lantone.qc.pub.model.label.FamilyLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * @ClassName : BEH0075
+ * @Description : 类似疾病史未描述
+ * @Author : 胡敬
+ * @Date: 2020-03-11 17:37
+ */
+@Component
+public class BEH0075 extends QCCatalogue {
+    @Override
+    protected void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getBeHospitalizedDoc() != null && inputInfo.getBeHospitalizedDoc().getFamilyLabel() != null) {
+            FamilyLabel familyLabel = inputInfo.getBeHospitalizedDoc().getFamilyLabel();
+            List<Family> families = familyLabel.getFamilies();
+            if (ListUtil.isEmpty(families)) {
+                return;
+            }
+            String familyText = familyLabel.getText();
+            if (StringUtil.isNotBlank(familyText) && familyText.contains("类似疾病")) {
+                return;
+            }
+            boolean findSimilarDiag = false;
+            for (Family family : families) {
+                if (family.getSimilarDiag() != null && StringUtil.isNotBlank(family.getSimilarDiag().getName())) {
+                    findSimilarDiag = true;
+                    break;
+                }
+            }
+            if (!findSimilarDiag) {
+                status.set("-1");
+            }
+        }
+    }
+}

+ 96 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH02902.java

@@ -0,0 +1,96 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.PD;
+import com.lantone.qc.pub.model.entity.Pacs;
+import com.lantone.qc.pub.model.label.PacsLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * @ClassName : BEH02902
+ * @Description : 辅助检查未注明地点
+ * @Author : 胡敬
+ * @Date: 2020-05-28 09:56
+ */
+@Component
+public class BEH02902 extends QCCatalogue {
+    @Override
+    protected void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+
+        String pacsText = inputInfo.getBeHospitalizedDoc().getStructureMap().get("辅助检查");
+        String pacsText1 = inputInfo.getBeHospitalizedDoc().getStructureMap().get("特殊检查");
+        String treat = inputInfo.getBeHospitalizedDoc().getStructureMap().get("诊疗情况");
+        if (StringUtil.isBlank(pacsText)) {
+            status.set("0");
+            return;
+        }
+
+        if (StringUtil.isNotBlank(pacsText) && (pacsText.contains("暂缺")
+                || pacsText.contains("暂无")|| pacsText.contains("院")
+                || pacsText.contains("病理")
+                || pacsText.contains("科") || pacsText.contains("公司")
+                || pacsText.contains("社区卫生服务中心"))) {
+            status.set("0");
+            return;
+        }
+        if (StringUtil.isNotBlank(pacsText1) && (pacsText1.contains("暂缺")
+                || pacsText1.contains("暂无") || pacsText1.contains("院")
+                || pacsText1.contains("科")|| pacsText1.contains("公司")
+                || pacsText.contains("社区卫生服务中心"))) {
+            status.set("0");
+            return;
+        }
+
+        if (StringUtil.isNotBlank(treat) && treat.contains("完善相关辅助检查")){
+            status.set("0");
+            return;
+        }
+
+        PacsLabel pacsLabel = inputInfo.getBeHospitalizedDoc().getPacsLabel();
+        if (pacsLabel == null || StringUtil.isBlank(pacsLabel.getText())) {
+            status.set("0");
+            return;
+        }
+        boolean findPlace = false;
+        pacsText = pacsLabel.getText();
+        List<Pacs> pacses = pacsLabel.getPacses();
+        if (pacses != null) {
+            for (Pacs pacs : pacses) {
+                /* 时间为入院检查的时间,模型输出处理后结构为 name为空,pd不为空 */
+                if (pacs.getName() == null && pacs.getPd() != null) {
+                    /* 模型先找到时间实体,找到后再从这个时间实体开始,往前往后找 */
+                    PD pd = pacs.getPd();
+                    String name = pd.getName();
+                    int timeIndex = pacsText.indexOf(name);
+                    String beforeTimeText = pacsText.substring(Math.max(timeIndex - 5, 0), timeIndex);
+                    String afterTimeText = pacsText.substring(timeIndex + name.length(), Math.min(timeIndex + name.length() + 10, pacsText.length()));
+                    if (beforeTimeText.contains("院") || afterTimeText.contains("院")) {
+                        findPlace = true;
+                        break;
+                    }
+                }
+            }
+        }
+
+        /* 如果模型没找到时间实体,则直接取辅助检查前20个字,判断有没有院字 */
+        if (!findPlace) {
+            String prefixText = pacsText.substring(0, Math.min(20, pacsText.length()));
+            if (prefixText.contains("院")) {
+                findPlace = true;
+            }
+        }
+
+        if (findPlace) {
+            status.set("0");
+        }
+    }
+}

+ 65 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH02903.java

@@ -0,0 +1,65 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Pacs;
+import com.lantone.qc.pub.model.label.PacsLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * @ClassName : BEH02903
+ * @Description : 辅助检查未注明时间
+ * @Author : 胡敬
+ * @Date: 2020-05-28 09:56
+ */
+@Component
+public class BEH02903 extends QCCatalogue {
+    @Override
+    protected void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+
+        String pacsText = inputInfo.getBeHospitalizedDoc().getStructureMap().get("辅助检查");
+        String pacsText1 = inputInfo.getBeHospitalizedDoc().getStructureMap().get("特殊检查");
+        String treat = inputInfo.getBeHospitalizedDoc().getStructureMap().get("诊疗情况");
+        if (StringUtil.isBlank(pacsText)) {
+            status.set("0");
+            return;
+        }
+
+        if (StringUtil.isNotBlank(pacsText) && (pacsText.contains("暂缺") || pacsText.contains("病理") || pacsText.contains("暂无"))) {
+            status.set("0");
+            return;
+        }
+        if (StringUtil.isNotBlank(pacsText1) && (pacsText1.contains("20"))) {
+            status.set("0");
+            return;
+        }
+        if (StringUtil.isNotBlank(treat) && treat.contains("完善相关辅助检查")){
+            status.set("0");
+            return;
+        }
+
+        PacsLabel pacsLabel = inputInfo.getBeHospitalizedDoc().getPacsLabel();
+        if (pacsLabel == null) {
+            status.set("0");
+            return;
+        }
+
+        List<Pacs> pacses = pacsLabel.getPacses();
+        if (pacses != null && pacses.size() > 0) {
+            for (Pacs pacs : pacses) {
+                if (pacs.getPd() != null && pacs.getPd().getName() != null) {
+                    status.set("0");
+                    return;
+                }
+            }
+        }
+    }
+}

+ 70 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH02966.java

@@ -0,0 +1,70 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.google.common.collect.Lists;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.util.CatalogueUtil;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.MedicalRecordInfoDoc;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : BEH02966
+ * @Description :  患者病历书写与性别不符(入院记录)
+ * @Author : 胡敬
+ * @Date: 2020-06-13 15:51
+ */
+@Component
+public class BEH02966 extends QCCatalogue {
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            return;
+        }
+
+        MedicalRecordInfoDoc medicalRecordInfoDoc = inputInfo.getMedicalRecordInfoDoc();
+        if (medicalRecordInfoDoc != null && medicalRecordInfoDoc.getStructureMap() != null) {
+            //科室
+            String behDeptName = medicalRecordInfoDoc.getStructureMap().get("behDeptName");
+            if (StringUtil.isNotBlank(behDeptName) && (behDeptName.contains("新生儿科") || behDeptName.contains("产科"))) {
+                return;
+            }
+        }
+
+        Map<String, String> beHospitalStructureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+        String gender = beHospitalStructureMap.get("性别");
+        if (StringUtil.isBlank(gender)) {
+            return;
+        }
+        List<String> noMatchWords = null;
+        if (gender.contains("男")) {
+            /* 男性不合理词 */
+            noMatchWords = Lists.newArrayList("阴道", "宫颈", "宫底", "胎位", "胎数", "胎心",
+                    "宫缩", "宫口", "输卵管", "卵巢", "输卵管", "阴唇", "阴蒂", "阴道前庭", "前庭大腺", "处女膜", "月经");
+        } else if (gender.contains("女")) {
+            /* 女性不合理词 */
+            noMatchWords = Lists.newArrayList("睾丸", "阴茎", "精索", "包皮", "附睾", "输精管",
+                    "射精管", "尿道海绵体", "冠状沟", "精阜", "精囊腺");
+        }
+        if (noMatchWords == null || noMatchWords.size() == 0) {
+            return;
+        }
+
+        List<String> keys = Lists.newArrayList("主诉", "现病史", "既往史", "个人史", "月经史", "体格检查", "一般情况"
+                , "初步诊断", "专科体格检查", "神经系统检查", "实验室检查", "影像学检查");
+        String text = CatalogueUtil.structureMapJoin(beHospitalStructureMap, keys);
+
+        for (String noMatchWord : noMatchWords) {
+            if (text.contains(noMatchWord)) {
+                status.set("-1");
+                info.set(noMatchWord);
+                return;
+            }
+        }
+    }
+}

+ 192 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH02980.java

@@ -0,0 +1,192 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.alibaba.fastjson.JSONArray;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.client.ChiefPresentSimilarityServiceClient;
+import com.lantone.qc.kernel.structure.ai.ModelAI;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Diag;
+import com.lantone.qc.pub.model.entity.GeneralDesc;
+import com.lantone.qc.pub.model.entity.Negative;
+import com.lantone.qc.pub.model.label.DiagLabel;
+import com.lantone.qc.pub.model.label.PastLabel;
+import com.lantone.qc.pub.model.label.PresentLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * @ClassName : BEH02980
+ * @Description : 病历前后描述不一致
+ * @Author : Mark
+ * @Date: 2020-06-23 11:02
+ */
+@Component
+public class BEH02980 extends QCCatalogue {
+    @Autowired
+    ChiefPresentSimilarityServiceClient chiefPresentSimilarityServiceClient;
+
+    private List<String> containList = Arrays.asList("脑萎缩", "慢性", "纤颤", "高血压", "糖尿", "冠状", "冠心病", "支架", "起搏器", "房颤", "风湿");
+    private List<String> filterList = Arrays.asList("心脏病", "低血糖", "急性", ";");
+
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getBeHospitalizedDoc() == null){
+            return;
+        }
+        PresentLabel presentLabel = inputInfo.getBeHospitalizedDoc().getPresentLabel();
+        DiagLabel initialDiagLabel = inputInfo.getBeHospitalizedDoc().getInitialDiagLabel();
+        PastLabel pastLabel = inputInfo.getBeHospitalizedDoc().getPastLabel();
+
+        List<String> pos_diags = new ArrayList<>();
+        List<String> neg_diags = new ArrayList<>();
+        //现病史需要取一般情况之后疾病
+        if (presentLabel != null) {
+            List<GeneralDesc> generals = presentLabel.getGenerals();
+            if (generals.size() > 0) {
+                String presentText = presentLabel.getText();
+                List<Diag> presentDiags = presentLabel.getDiags();
+                /* 取现病史中一般情况之后的疾病名称 */
+                if (StringUtil.isNotBlank(presentText) && presentDiags.size() > 0) {
+                    String lastGeneral = generals.get(generals.size() - 1).getName();
+                    int lastGeneralIndex = presentText.indexOf(lastGeneral);
+                    for (Diag presentDiag : presentDiags) {
+                        if (presentDiag.getNegative() != null || presentDiag.getHospitalDiagName().contains("否认")) {
+                            continue;
+                        }
+                        /* 现病史中一般情况之后的疾病名称 */
+                        if (presentText.indexOf(presentDiag.getHospitalDiagName()) > lastGeneralIndex) {
+                            if (isContains(presentDiag.getHospitalDiagName()) && !isFilter(presentDiag.getHospitalDiagName())) {
+                                String dgname = presentDiag.getHospitalDiagName();
+                                if (presentDiag.getNegative()==null) {
+                                    if (!pos_diags.contains(dgname)) {
+                                        pos_diags.add(dgname);
+                                    }
+                                }
+                                else {
+                                    if (!neg_diags.contains(dgname)) {
+                                        neg_diags.add(dgname);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+
+        if (pastLabel != null && StringUtils.isNotEmpty(pastLabel.getText())) {
+            extract_diags(pastLabel.getDiags(), pos_diags, neg_diags);
+        } else {
+            //例如邵逸夫 台州这种结构化数据,判断高血压 和 糖尿病是否有冲突
+            List<Diag> pastDiags = new ArrayList<>();
+            Map<String, String> structureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+            String a1 = structureMap.get("高血压");
+            Diag diag = new Diag();
+            diag.setName("高血压");
+            diag.setHospitalDiagName("高血压");
+            if (StringUtils.isNotEmpty(a1) && "否认".equals(a1)) {
+                Negative negative = new Negative();
+                negative.setName("否认");
+                pastDiags.add(diag);
+            } else if (StringUtils.isNotEmpty(a1) && !"否认".equals(a1)) {
+                pastDiags.add(diag);
+            }
+
+            a1 = structureMap.get("糖尿病");
+            diag = new Diag();
+            diag.setName("糖尿病");
+            diag.setHospitalDiagName("糖尿病");
+            if  (StringUtils.isNotEmpty(a1) && "否认".equals(a1)) {
+                Negative negative = new Negative();
+                negative.setName("否认");
+                pastDiags.add(diag);
+            } else if (StringUtils.isNotEmpty(a1) && !"否认".equals(a1)) {
+                pastDiags.add(diag);
+            }
+
+            extract_diags(pastDiags, pos_diags, neg_diags);
+        }
+        if (initialDiagLabel != null) {
+            extract_diags(initialDiagLabel.getDiags(), pos_diags, neg_diags);
+        }
+
+        String infoStr = "";
+        int matchSum = 0;
+        ModelAI modelAI = new ModelAI();
+
+        for (String negdiag : neg_diags) {
+            JSONArray jsonArray = modelAI.loadChiefPresentSimilarAI(negdiag, pos_diags, false
+                    , "diagnose", chiefPresentSimilarityServiceClient);
+            if (jsonArray.size() == 2) {
+                /* 相似度最高症状 */
+                String dgname = jsonArray.getString(0);
+                /* 相似度分数 */
+                double likeRate = jsonArray.getDoubleValue(1);
+                if (likeRate > 0.99) {
+                    matchSum++;
+                    if (StringUtils.isEmpty(infoStr)) {
+                        infoStr = negdiag;
+                    } else {
+                        infoStr = infoStr + "," + negdiag;
+                    }
+                    break;
+                }
+            }
+        }
+        if (matchSum > 0) {
+            status.set("-1");
+            info.set(infoStr);
+        }
+
+    }
+
+
+    private List<String> extract_diags(List<Diag> diags, List<String> pos_diags, List<String> neg_diags ) {
+        List<String> dgs = new ArrayList<>();
+        for (Diag dg:diags) {
+            String dgname = dg.getHospitalDiagName();
+            if (dg.getNegative()==null) {
+                if (!pos_diags.contains(dgname)) {
+                    pos_diags.add(dgname);
+                }
+            }
+            else {
+                if (!neg_diags.contains(dgname)) {
+                    neg_diags.add(dgname);
+                    dgs.add(dgname);
+                }
+            }
+        }
+
+        return dgs;
+    }
+
+    private boolean isContains(String diagName) {
+        for (String c : containList) {
+            if (diagName.contains(c)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isFilter(String diagName) {
+        for (String c : filterList) {
+            if (diagName.contains(c)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}

+ 83 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0372.java

@@ -0,0 +1,83 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.MaritalStatus;
+import com.lantone.qc.pub.model.label.MaritalLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+/**
+ * @Description: 婚姻状况前后不一致
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0372 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+
+        String basicInfoStatus = inputInfo.getBeHospitalizedDoc().getStructureMap().get("婚育史");
+        String bhbasicInfoStatus = inputInfo.getBeHospitalizedDoc().getStructureMap().get("婚姻状况");
+        if (StringUtil.isBlank(bhbasicInfoStatus)) {
+            bhbasicInfoStatus = inputInfo.getBeHospitalizedDoc().getStructureMap().get("婚姻");
+        }
+        if (StringUtil.isBlank(basicInfoStatus) || StringUtil.isBlank(bhbasicInfoStatus)) {
+            status.set("0");
+            return;
+        }
+
+        if (basicInfoStatus.contains(bhbasicInfoStatus)) {
+            status.set("0");
+            return;
+        }
+
+        if (bhbasicInfoStatus.equals("未婚") && basicInfoStatus.contains("未婚")) {
+            status.set("0");
+            return;
+        }
+
+        if (StringUtil.isNotBlank(bhbasicInfoStatus) && basicInfoStatus.equals("其他")) {
+            status.set("0");
+            return;
+        }
+
+        if (bhbasicInfoStatus.equals("丧偶") || basicInfoStatus.contains("已故")) {
+            status.set("0");
+            return;
+        }
+
+        if ((bhbasicInfoStatus.equals("离婚") || bhbasicInfoStatus.equals("离异")) &&
+                (basicInfoStatus.contains("离异") || bhbasicInfoStatus.equals("离婚"))) {
+            status.set("0");
+            return;
+        }
+
+        if (bhbasicInfoStatus.equals("已婚") && basicInfoStatus.contains("结婚")) {
+            status.set("0");
+            return;
+        }
+
+        MaritalStatus mts = inputInfo.getBeHospitalizedDoc().getMaritalLabel().getMaritalStatus();
+        if (mts != null && StringUtil.isNotBlank(mts.getName())) {
+            String maritalStatus = mts.getName();
+            if (basicInfoStatus.equals(maritalStatus)) {
+                status.set("0");
+                return;
+            }
+        }
+
+        //无婚育史
+        MaritalLabel maritalLabel = inputInfo.getBeHospitalizedDoc().getMaritalLabel();
+        if (maritalLabel == null || maritalLabel.getText() == null) {
+            status.set("0");
+        }
+    }
+
+}

+ 117 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0375.java

@@ -0,0 +1,117 @@
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.behospitalized;
+
+import com.google.common.collect.Lists;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.Content;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.entity.Family;
+import com.lantone.qc.pub.model.label.MaritalLabel;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/**
+ * @Description: 配偶健康状况未描述
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0375 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        //硬规则 匹配未婚
+        String marry = inputInfo.getBeHospitalizedDoc().getStructureMap().get(Content.marry);
+        if(StringUtil.isBlank(marry)){
+            marry = inputInfo.getBeHospitalizedDoc().getStructureMap().get("婚姻状况");
+        }
+        MaritalLabel maritalLabel = inputInfo.getBeHospitalizedDoc().getMaritalLabel();
+        if ("未婚".equals(marry) ||
+                (maritalLabel != null &&
+                (StringUtil.isBlank(maritalLabel.getText())
+                        || maritalLabel.getText().contains("未婚")
+                        || maritalLabel.getText().contains("离婚")
+                        || maritalLabel.getText().contains("离异")
+                        || maritalLabel.getText().contains("已故")
+                        || maritalLabel.getText().contains("已逝")
+                        || maritalLabel.getText().contains("丧偶")
+                        || maritalLabel.getText().contains("详见原病历")
+                )
+                )
+        ) {
+            status.set("0");
+            return;
+        }
+        //台州市结构化的
+        Map<String, String> structureMap_beh = inputInfo.getBeHospitalizedDoc().getStructureMap();
+        if (StringUtils.isNotEmpty(structureMap_beh.get("配偶健康状况"))) {
+            status.set("0");
+            return;
+        }
+        List<Family> familyList = Lists.newArrayList();
+        if (inputInfo.getBeHospitalizedDoc().getFamilyLabel() != null){
+            List<Family> familiesFl = inputInfo.getBeHospitalizedDoc().getFamilyLabel().getFamilies();
+            if (ListUtil.isNotEmpty(familiesFl)) {
+                familyList.addAll(familiesFl);
+            }
+        }
+
+        if (inputInfo.getBeHospitalizedDoc().getMaritalLabel() != null){
+            List<Family> familiesMl = inputInfo.getBeHospitalizedDoc().getMaritalLabel().getFamily();
+            if (ListUtil.isNotEmpty(familiesMl)) {
+                familyList.addAll(familiesMl);
+            }
+        }
+
+
+        Pattern p = Pattern.compile("[配偶]");
+        List<Family> filterFamilies = familyList
+                .stream()
+                .filter(
+                        i -> i != null
+                                && StringUtil.isNotBlank(i.getName())
+                                && p.matcher(i.getName()).find()).collect(Collectors.toList());
+
+        for (Family family : filterFamilies) {
+            if (family.getDead() != null) {
+                status.set("0");
+                return;
+            } else if (family.getHealthCondition() != null && StringUtil.isNotBlank(family.getHealthCondition().getName())) {
+                status.set("0");
+                return;
+            } else if (family.getDiags() != null && family.getDiags().size() > 0) {
+                status.set("0");
+                return;
+            }
+        }
+        //硬规则 匹配婚育史text信息
+        String maritalText1=inputInfo.getBeHospitalizedDoc().getStructureMap().get("婚育史");
+        if (maritalText1.contains("未婚")
+                || maritalText1.contains("详见原病历")
+                || maritalText1.contains("离婚")
+                || maritalText1.contains("离异")
+                || maritalText1.contains("适龄结婚")
+                || maritalLabel.getText().contains("已故")
+                || maritalLabel.getText().contains("已逝")
+                || maritalLabel.getText().contains("丧偶")) {
+            status.set("0");
+            return;
+        }
+        if(maritalText1!=null && maritalText1.contains("配偶健康状况")){
+            status.set("0");
+        }
+
+    }
+
+}

+ 0 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/yiwu/behospitalized/BEH0376.java


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است