Przeglądaj źródła

Merge branch 'hb/beilun' into his/xszyy

# Conflicts:
#	dbanaly/src/main/resources/application-local.yml
#	kernel/src/main/resources/bootstrap.yml
liuqq 3 lat temu
rodzic
commit
757a31a206
100 zmienionych plików z 5846 dodań i 108 usunięć
  1. 152 0
      dbanaly/src/main/java/com/lantone/qc/dbanaly/facade/qdnzyy/QdnzyyXmlUtil.java
  2. 4 5
      dbanaly/src/main/resources/application-dev.yml
  3. 16 0
      dbanaly/src/main/resources/rebel.xml
  4. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/behospitalized/BEH0009.java
  5. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/behospitalized/BEH0010.java
  6. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/behospitalized/BEH0014.java
  7. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/behospitalized/BEH0030.java
  8. 5 5
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/behospitalized/BEH02966.java
  9. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/behospitalized/BEH03176.java
  10. 2 2
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/behospitalized/BEH0372.java
  11. 6 1
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/behospitalized/BEH0378.java
  12. 1 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/behospitalized/BEH0411.java
  13. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/clinicalblood/CLI0301.java
  14. 3 2
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/deathrecord/DEAR0342.java
  15. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/deathrecord/DEAR0344.java
  16. 6 6
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/difficultcasediscuss/DIF0118.java
  17. 3 2
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/difficultcasediscuss/DIF0119.java
  18. 2 2
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP0162.java
  19. 7 1
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP0163.java
  20. 3 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP0166.java
  21. 31 7
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP0184.java
  22. 11 12
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP0193.java
  23. 1 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP0196.java
  24. 6 2
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP0255.java
  25. 10 9
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03038.java
  26. 33 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03200.java
  27. 40 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03201.java
  28. 33 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03202.java
  29. 37 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03203.java
  30. 33 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03204.java
  31. 34 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03205.java
  32. 39 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03206.java
  33. 39 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03207.java
  34. 40 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03208.java
  35. 40 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03209.java
  36. 39 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03210.java
  37. 51 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03211.java
  38. 40 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03212.java
  39. 80 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03213.java
  40. 41 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03214.java
  41. 40 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03215.java
  42. 43 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03216.java
  43. 32 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03217.java
  44. 35 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03218.java
  45. 29 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03219.java
  46. 47 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03220.java
  47. 29 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03221.java
  48. 34 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03222.java
  49. 29 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03223.java
  50. 47 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03224.java
  51. 29 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03225.java
  52. 34 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03226.java
  53. 50 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03229.java
  54. 2 2
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/changshaxy/behospitalized/BEH02966.java
  55. 2 2
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/changshaxy/clinicalblood/CLI0301.java
  56. 21 5
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/changshaxy/firstcourserecord/FIRC0093.java
  57. 61 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/changshaxy/firstcourserecord/FIRC03086.java
  58. 36 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/changshaxy/firstpagerecord/FIRP0170.java
  59. 0 1
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/changshaxy/firstpagerecord/FIRP03242.java
  60. 0 2
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/changshaxy/firstpagerecord/FIRP03282.java
  61. 171 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/changshaxy/threelevelward/THR0125.java
  62. 36 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/changshaxy/threelevelward/THR03199.java
  63. 173 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ningbozhenhai/firstpagerecord/FIRP0178.java
  64. 45 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ningbozhongyi/clinicalblood/CLI0571.java
  65. 2 5
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ningbozhongyi/firstpagerecord/FIRP0178.java
  66. 149 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ningbozhongyi/preoperativediscussion/PRE0328.java
  67. 110 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ningbozhongyi/threelevelward/THR0144.java
  68. 16 7
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ningbozhongyi/threelevelward/THR02900.java
  69. 4 4
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/behospitalized/BEH02966.java
  70. 43 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/behospitalized/BEH0400.java
  71. 5 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/firstpagerecord/FIRP0163.java
  72. 66 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/operationdiscussion/OPE0326.java
  73. 47 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/threelevelward/THR0123.java
  74. 203 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/threelevelward/THR0127.java
  75. 229 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/threelevelward/THR0128.java
  76. 91 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/threelevelward/THR0140.java
  77. 508 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/threelevelward/THR02985.java
  78. 157 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/threelevelward/THR03014.java
  79. 157 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/threelevelward/THR03016.java
  80. 57 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/threelevelward/THR03020.java
  81. 67 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/threelevelward/THR03021.java
  82. 342 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/threelevelward/THR03076.java
  83. 598 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/threelevelward/THR03077.java
  84. 8 1
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/threelevelward/THR03090.java
  85. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaiyiyi/behospitalized/BEH0439.java
  86. 81 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaiyiyi/firstpagerecord/FIRP0250.java
  87. 3 5
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaiyiyi/threelevelward/THR0125.java
  88. 4 6
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaiyiyi/threelevelward/THR0126.java
  89. 508 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaiyiyi/threelevelward/THR02985.java
  90. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaiyiyi/threelevelward/THR03090.java
  91. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/shengzhouyy/behospitalized/BEH02902.java
  92. 125 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/shengzhouyy/clinicalblood/CLI0301.java
  93. 54 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/shengzhouyy/operationdiscussion/OPE0322.java
  94. 68 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xszyy/firstpagerecord/FIRP0190.java
  95. 45 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xszyy/firstpagerecord/FIRP0220.java
  96. 74 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xszyy/operationdiscussion/OPE03142.java
  97. 64 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xszyy/operationdiscussion/OPE03143.java
  98. 36 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xszyy/threelevelward/THR0685.java
  99. 2 2
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/leavehospital/LEA02968.java
  100. 0 0
      kernel/src/main/java/com/lantone/qc/kernel/catalogue/operationdiscussion/OPE03143.java

+ 152 - 0
dbanaly/src/main/java/com/lantone/qc/dbanaly/facade/qdnzyy/QdnzyyXmlUtil.java

@@ -0,0 +1,152 @@
+package com.lantone.qc.dbanaly.facade.qdnzyy;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.lantone.qc.pub.util.FileUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.dom4j.Document;
+import org.dom4j.DocumentHelper;
+import org.dom4j.Element;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Description: xml解析工具
+ * @author: rengb
+ * @time: 2020/3/28 14:23
+ */
+@Slf4j
+public class QdnzyyXmlUtil {
+
+    public static Map<String, String> xmlToMap(String xml) {
+        Map<String, String> map = Maps.newHashMap();
+        try {
+            Document doc = DocumentHelper.parseText(xml);
+            Element root = (Element) doc.selectSingleNode("//XTextDocument/XElements/Element[@xsi:type='XTextBody']/XElements");
+            findElement(root, "XInputField").forEach(i -> {
+                xInputField(map, i, null);
+            });
+            findElement(root, "XTextTable").forEach(tableElement -> {
+                String tablePreTxt = getElementPreVal(tableElement);
+                findElement(tableElement.element("XElements"), "XTextTableRow").forEach(rowElement -> {
+                    findElement(rowElement.element("XElements"), "XTextTableCell").forEach(cellElement -> {
+                        findElement(cellElement.element("XElements"), "XInputField").forEach(xInputFieldElement -> {
+                            xInputField(map, xInputFieldElement, tablePreTxt);
+                        });
+                    });
+                });
+            });
+            Element bodyTextElement = (Element) doc.selectSingleNode("//XTextDocument/BodyText");
+            String bodyText = bodyTextElement.getText();
+            map.put("原始文本", bodyText);
+        } catch (Exception e) {
+            e.printStackTrace();
+            map.clear();
+        }
+//        map.keySet().forEach(key -> {
+//            System.out.println(key + "----" + map.get(key));
+//        });
+        return map;
+    }
+
+    public static List<Element> findElement(Element element, String attual) {
+        List<Element> ret = Lists.newArrayList();
+        ((List<Element>) (element.elements())).forEach(i -> {
+            if (StringUtil.isNotBlank(i.attributeValue("type")) && i.attributeValue("type").equals(attual)) {
+                ret.add(i);
+            }
+        });
+        return ret;
+    }
+
+    public static void xInputField(Map<String, String> map, Element xInputFieldElement, String tablePreTxt) {
+        String value = getXInputFieldValue(xInputFieldElement);
+        if (value == null) {
+            return;
+        }
+        String key = getXInputFieldKey(xInputFieldElement, tablePreTxt);
+        if (StringUtil.isNotBlank(key)) {
+            if (map.containsKey(key)) {
+                value = map.get(key) + " " + value;
+            }
+            map.put(key, value);
+        }
+    }
+
+    //获取 XInputField 的键
+    private static String getXInputFieldKey(Element xInputFieldElement, String tablePreTxt) {
+        String key = null;
+        String[] elementNames = {"Name","BackgroundText", "ToolTip" };
+        for (String elementName : elementNames) {
+            key = xInputFieldElement.elementTextTrim(elementName);
+            if (StringUtil.isNotBlank(key)) {
+                break;
+            }
+        }
+        if (StringUtil.isBlank(key)) {
+            key = getElementPreVal(xInputFieldElement);
+        }
+        if (StringUtil.isBlank(key)) {
+            key = tablePreTxt;
+        }
+        if (StringUtil.isBlank(key)) {
+            key = "病历内容";
+        }
+        return keyHandle(key);
+    }
+
+    //获取 XInputField 的值
+    private static String getXInputFieldValue(Element xInputFieldElement) {
+        String value = null;
+        Element innerValueElement = xInputFieldElement.element("InnerValue");
+        if (innerValueElement != null) {
+            value = innerValueElement.getTextTrim();
+        }
+        if (StringUtil.isBlank(value)) {
+            Element xElementsElement = xInputFieldElement.element("XElements");
+            if (xElementsElement != null) {
+                List<Element> elements = findElement(xElementsElement, "XString");
+                if (elements.size() > 0) {
+                    value = "";
+                    for (Element element : elements) {
+                        Element text = element.element("Text");
+                        if (text != null) {
+                            value += text.getTextTrim();
+                        }
+                    }
+                }
+            }
+        }
+        return value;
+    }
+
+    //获取前面文本信息作为key
+    private static String getElementPreVal(Element xInputFieldElement) {
+        String ret = "";
+        List<Element> sonElements = xInputFieldElement.getParent().elements();
+        int index = sonElements.indexOf(xInputFieldElement);
+        for (int i = index - 1; i >= 0; i--) {
+            Element sonElement = sonElements.get(i);
+            if (sonElement.attributeValue("type").equals("XTextTable") || sonElement.attributeValue("type").equals("XInputField")) {
+                break;
+            }
+            if (sonElement.attributeValue("type").equals("XString")) {
+                ret = sonElement.elementTextTrim("Text") + ret;
+            }
+        }
+        return ret;
+    }
+
+    //针对key的一些特殊处理
+    private static String keyHandle(String key) {
+        key = StringUtil.removeBlank(key).replaceAll("[::]", "");
+        return key;
+    }
+
+    public static void main(String[] args) {
+        xmlToMap(FileUtil.fileRead("C:\\Users\\Administrator\\Desktop\\义务\\jiexi\\n5.xml"));
+    }
+
+}

+ 4 - 5
dbanaly/src/main/resources/application-dev.yml

@@ -5,9 +5,9 @@ spring:
     druid:
       lantone:
         driver-class-name: com.mysql.jdbc.Driver
-        url: jdbc:mysql://192.168.2.125:3307/qc?useUnicode=true&characterEncoding=utf8&useSSL=false
+        url: jdbc:mysql://192.168.2.237:3307/qc_xszyy?useUnicode=true&characterEncoding=utf8&useSSL=false
         username: root
-        password: LangT0ng@lt
+        password: lantone
         initial-size: 8
         min-idle: 1
         max-active: 20
@@ -24,14 +24,13 @@ spring:
         filters: stat
         connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
         use-global-data-source-stat: true
-  #redis
   redis:
     database:
       cache: 10 # cache索引
       token: 10 # Token索引
-    host: 192.168.2.125  #Redis服务器地址
+    host: 127.0.0.1  #Redis服务器地址
     port: 6379 # Redis服务器连接端口(本地环境端口6378,其他环境端口是6379)
-    password: lantone # Redis服务器连接密码(默认为空)
+    password:  # Redis服务器连接密码(默认为空)
     lettuce:
       pool:
         max-active: 8 # 连接池最大连接数(使用负值表示没有限制)

+ 16 - 0
dbanaly/src/main/resources/rebel.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  This is the JRebel configuration file. It maps the running application to your IDE workspace, enabling JRebel reloading for this project.
+  Refer to https://manuals.jrebel.com/jrebel/standalone/config.html for more information.
+-->
+<application generated-by="intellij" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.zeroturnaround.com" xsi:schemaLocation="http://www.zeroturnaround.com http://update.zeroturnaround.com/jrebel/rebel-2_3.xsd">
+
+	<id>dbanaly</id>
+
+	<classpath>
+		<dir name="C:/Users/10185/Desktop/work/后端/aiPlat/qc/dbanaly/target/classes">
+		</dir>
+	</classpath>
+
+</application>

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/catalogue/behospitalized/BEH0009.java

@@ -22,7 +22,7 @@ import java.util.List;
 @Component
 public class BEH0009 extends QCCatalogue {
     private List<String> containList = Arrays.asList("检查", "术后", "药物", "发现", "误服", "确诊", "经", "异常", "诊断"
-            , "示", "超", "伤", "术", "复查", "体检", "血透", "血液透析","孕","农药");
+            , "示", "超", "伤", "术", "复查", "体检", "血透", "血液透析", "孕", "农药", "呻吟", "颈椎");
 
     public void start(InputInfo inputInfo, OutputInfo outputInfo) {
         if (inputInfo.getBeHospitalizedDoc() == null) {

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/catalogue/behospitalized/BEH0010.java

@@ -21,7 +21,7 @@ import java.util.List;
 @Component
 public class BEH0010 extends QCCatalogue {
     private List<String> containList = Arrays.asList("癌", "瘤", "复诊", "术后", "化疗后", "发现", "体检", "检查", "确诊"
-            , "诊断", "复查", "复发", "示", "超", "CT", "血透", "血液透析", "治疗后");
+            , "诊断", "复查", "复发", "示", "超", "CT", "血透", "血液透析", "治疗后", "痛");
 
     public void start(InputInfo inputInfo, OutputInfo outputInfo) {
         status.set("0");

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/catalogue/behospitalized/BEH0014.java

@@ -28,7 +28,7 @@ import java.util.List;
 @Component
 public class BEH0014 extends QCCatalogue {
     private List<String> containList = Arrays.asList("体检", "发现", "检查", "因", "确诊", "诊断", "复查", "术后"
-            , "药物", "误服", "查", "撞", "伤", "月经", "暴力", "超", "术");
+            , "药物", "误服", "查", "撞", "伤", "跌", "月经", "暴力", "超", "术");
 
     public void start(InputInfo inputInfo, OutputInfo outputInfo) {
         if (inputInfo.getBeHospitalizedDoc() == null) {

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/catalogue/behospitalized/BEH0030.java

@@ -47,7 +47,7 @@ public class BEH0030 extends QCCatalogue {
             status.set("0");
         }
         String pastText = pastLabel.getText();
-        if (pastText.contains("肝炎") || pastText.contains("结核") || pastText.contains("详见原病历")
+        if (pastText.contains("肝炎") || pastText.contains("传染病") || pastText.contains("结核") || pastText.contains("详见原病历")
                 || pastText.contains("见旧病历") || pastText.contains("见既往病历") || pastText.contains("乙肝")) {
             status.set("0");
         }

+ 5 - 5
kernel/src/main/java/com/lantone/qc/kernel/catalogue/behospitalized/BEH02966.java

@@ -35,11 +35,11 @@ public class BEH02966 extends QCCatalogue {
         if (gender.contains("男")) {
             /* 男性不合理词 */
             noMatchWords = Lists.newArrayList("阴道", "宫颈", "子宫", "宫底", "胎位", "胎数", "胎心",
-                    "宫缩", "宫口", "输卵管", "卵巢", "输卵管", "阴唇", "阴蒂", "阴道前庭", "前庭大腺", "处女膜");
+                    "宫缩", "宫口", "输卵管", "卵巢", "输卵管", "阴唇", "阴蒂", "阴道前庭", "前庭大腺", "处女膜", "女");
         } else if (gender.contains("女")) {
             /* 女性不合理词 */
             noMatchWords = Lists.newArrayList("睾丸", "阴茎", "精索", "包皮", "输精管",
-                    "射精管", "尿道海绵体", "冠状沟", "精阜", "精囊腺", "阴囊");
+                    "射精管", "尿道海绵体", "冠状沟", "精阜", "精囊腺", "阴囊", "男");
         }
         if (noMatchWords == null || noMatchWords.size() == 0) {
             return;
@@ -48,11 +48,11 @@ public class BEH02966 extends QCCatalogue {
         List<String> keys = Lists.newArrayList("主诉", "现病史", "既往史", "体格检查", "一般情况"
                 , "初步诊断", "专科体格检查", "神经系统检查", "实验室检查", "影像学检查");
         String text = CatalogueUtil.structureMapJoin(beHospitalStructureMap, keys);
-        String rex="(?<!((母孕期|母亲|妈妈|分娩期|分娩|出生时|母亲怀孕|怀孕时|孕期)[^。,;。、,;]{0,15}))(阴道|宫颈|子宫|宫底|胎位|胎数|胎心|宫缩|宫口|卵巢|输卵管|阴唇|阴蒂|阴道前庭|前庭大腺|处女膜)";
+        String rex = "(?<!((母孕期|母亲|妈妈|分娩期|分娩|出生时|母亲怀孕|怀孕时|孕期)[^。,;。、,;]{0,15}))(阴道|宫颈|子宫|宫底|胎位|胎数|胎心|宫缩|宫口|卵巢|输卵管|阴唇|阴蒂|阴道前庭|前庭大腺|处女膜)";
         for (String noMatchWord : noMatchWords) {
             if (text.contains(noMatchWord)) {
-                if(gender.contains("男")){
-                    if(!text.matches(rex)){
+                if (gender.contains("男")) {
+                    if (!text.matches(rex)) {
                         status.set("0");
                         return;
                     }

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/catalogue/behospitalized/BEH03176.java

@@ -23,7 +23,7 @@ import java.util.List;
 @Component
 public class BEH03176 extends QCCatalogue {
 
-    private List<String> containList = Arrays.asList("心血管");
+    private List<String> containList = Arrays.asList("心血管", "心力衰竭", "心衰", "心律失常", "冠心病", "心绞痛", "心肌梗死", "高血压", "心肌病", "心肌炎", "心脏病", "高血脂", "高血糖", "糖尿病", "遗传");
 
     public void start(InputInfo inputInfo, OutputInfo outputInfo) {
 

+ 2 - 2
kernel/src/main/java/com/lantone/qc/kernel/catalogue/behospitalized/BEH0372.java

@@ -29,7 +29,7 @@ public class BEH0372 extends QCCatalogue {
             bhbasicInfoStatus = inputInfo.getBeHospitalizedDoc().getStructureMap().get("婚姻");
         }
         if (StringUtil.isBlank(basicInfoStatus) || basicInfoStatus.contains("详见")
-                || basicInfoStatus.contains("见旧病历")|| basicInfoStatus.contains("见既往病历")|| StringUtil.isBlank(bhbasicInfoStatus)) {
+                || basicInfoStatus.contains("见旧病历") || basicInfoStatus.contains("见既往病历") || StringUtil.isBlank(bhbasicInfoStatus)) {
             status.set("0");
             return;
         }
@@ -58,7 +58,7 @@ public class BEH0372 extends QCCatalogue {
         }
 
         if (bhbasicInfoStatus.equals("已婚") && (basicInfoStatus.contains("结婚") || basicInfoStatus.contains("再婚")
-                || basicInfoStatus.contains("育有") || basicInfoStatus.contains("已婚"))) {
+                || basicInfoStatus.contains("育有") || basicInfoStatus.contains("已婚") || basicInfoStatus.contains("婚育"))) {
             status.set("0");
             return;
         }

+ 6 - 1
kernel/src/main/java/com/lantone/qc/kernel/catalogue/behospitalized/BEH0378.java

@@ -41,7 +41,7 @@ public class BEH0378 extends QCCatalogue {
             familiesFl = familyLabel.getFamilies();
             //规则匹配
             String familyText = familyLabel.getText();
-            if (StringUtil.isNotBlank(familyText) && familyText.contains("自然死亡")) {
+            if (StringUtil.isNotBlank(familyText) && (familyText.contains("自然死亡")|| familyText.matches("[\\s\\S]*(?=配偶因)[^,;,;。]{0,15}(?=已故)[\\s\\S]*"))) {
                 status.set("0");
                 return;
             }
@@ -95,5 +95,10 @@ public class BEH0378 extends QCCatalogue {
                 status.set("0");
             }
         }
+        String maritalText = maritalLabel.getText();
+        if (StringUtil.isNotBlank(maritalText) && maritalText.matches("[\\s\\S]*(?=配偶因)[^,;,;。]{0,15}(?=已故)[\\s\\S]*")) {
+            status.set("0");
+            return;
+        }
     }
 }

+ 1 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/behospitalized/BEH0411.java

@@ -39,6 +39,7 @@ public class BEH0411 extends QCCatalogue {
         {
             case "1":                            //长兴
             case "2":
+            case "11":
                 return "记录日期";
             case "7":                            //厦门
                 return "记录日期";

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/catalogue/clinicalblood/CLI0301.java

@@ -79,7 +79,7 @@ public class CLI0301 extends QCCatalogue {
                         continue;
                     }
                     String rex="[\\s\\S]*(?=输血)[^,;,;。]{0,10}(?=知情同意书)[\\s\\S]*";
-                    if(Content.BLOODRECORDLIST.contains(str)||str.matches(rex)){
+                    if(Content.BLOODRECORDLIST.stream().anyMatch(obj -> str.contains(obj))||str.matches(rex)){
                         status.set("0");
                         return;
                     }

+ 3 - 2
kernel/src/main/java/com/lantone/qc/kernel/catalogue/deathrecord/DEAR0342.java

@@ -27,13 +27,14 @@ public class DEAR0342 extends QCCatalogue {
             }
         }
     }
+
     private String getKeyByHospitalId() {
-        switch (Content.hospital_Id)
-        {
+        switch (Content.hospital_Id) {
             case "1":               //长兴
             case "2":
             case "5":
             case "35":
+            case "11":
                 return "诊疗经过";
             default:
                 return "诊疗经过(重点记录病情演变、抢救经过)";

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/catalogue/deathrecord/DEAR0344.java

@@ -24,7 +24,7 @@ public class DEAR0344 extends QCCatalogue {
             if (CatalogueUtil.isEmpty(diagnosisTreatmentProcess)) {
                 return;
             }
-            if (!diagnosisTreatmentProcess.contains("抢救")) {
+            if (!diagnosisTreatmentProcess.contains("抢救") && !diagnosisTreatmentProcess.contains("胸外按压") && !diagnosisTreatmentProcess.contains("心肺复苏")) {
                 status.set("-1");
             }
         }

+ 6 - 6
kernel/src/main/java/com/lantone/qc/kernel/catalogue/difficultcasediscuss/DIF0118.java

@@ -23,15 +23,15 @@ public class DIF0118 extends QCCatalogue {
     public void start(InputInfo inputInfo, OutputInfo outputInfo) {
         status.set("0");
         List<DifficultCaseDiscussDoc> difficultCaseDiscussDocs = inputInfo.getDifficultCaseDiscussDocs();
-        if(ListUtil.isEmpty(difficultCaseDiscussDocs)){
+        if (ListUtil.isEmpty(difficultCaseDiscussDocs)) {
             return;
         }
-        if(difficultCaseDiscussDocs != null && difficultCaseDiscussDocs.size()>0){
-            for (DifficultCaseDiscussDoc dcdd:difficultCaseDiscussDocs) {
+        if (difficultCaseDiscussDocs != null && difficultCaseDiscussDocs.size() > 0) {
+            for (DifficultCaseDiscussDoc dcdd : difficultCaseDiscussDocs) {
                 Map<String, String> dcddStructureMap = dcdd.getStructureMap();
                 String key = getKeyByHospitalId();
                 String diisDate = dcddStructureMap.get(key);
-                if(CatalogueUtil.isEmpty(diisDate)){
+                if (CatalogueUtil.isEmpty(diisDate)) {
                     status.set("-1");
                     break;
                 }
@@ -40,10 +40,10 @@ public class DIF0118 extends QCCatalogue {
     }
 
     private String getKeyByHospitalId() {
-        switch (Content.hospital_Id)
-        {
+        switch (Content.hospital_Id) {
             case "1":               //长兴
             case "2":
+            case "11":
                 return "主持人";
             default:
                 return "主持人姓名及专业技术职务";

+ 3 - 2
kernel/src/main/java/com/lantone/qc/kernel/catalogue/difficultcasediscuss/DIF0119.java

@@ -38,10 +38,11 @@ public class DIF0119 extends QCCatalogue {
             }
         }
     }
+
     private String getKeyByHospitalId() {
-        switch (Content.hospital_Id)
-        {
+        switch (Content.hospital_Id) {
             case "5":
+            case "11":
                 return "参加人员的姓名及专业技术职务";
             case "20":
                 return "参加人员的姓名及专业技术职务";

+ 2 - 2
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP0162.java

@@ -19,14 +19,14 @@ import java.util.Map;
  */
 @Component
 public class FIRP0162 extends QCCatalogue {
-    private List<String> containList = Arrays.asList("-", "—", "拒", "无", "不详", "未上户口","提供");
+    private List<String> containList = Arrays.asList("-", "—", "拒", "无", "不详", "未上户口", "提供");
 
     public void start(InputInfo inputInfo, OutputInfo outputInfo) {
         status.set("0");
         if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
             Map<String, String> firstpageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
             String nationality = firstpageStructureMap.get(Content.nationality);
-            if(StringUtil.isNotBlank(nationality) && !"中国".equals(nationality)){
+            if (StringUtil.isNotBlank(nationality) && !"中国".equals(nationality)) {
                 return;
             }
             String idNumber = firstpageStructureMap.get(Content.idNumber);

+ 7 - 1
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP0163.java

@@ -5,6 +5,7 @@ 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;
@@ -18,12 +19,17 @@ import java.util.Map;
 @Component
 public class FIRP0163 extends QCCatalogue {
     public void start(InputInfo inputInfo, OutputInfo outputInfo) {
-        if (inputInfo.getFirstPageRecordDoc() == null){
+        if (inputInfo.getFirstPageRecordDoc() == null) {
             status.set("0");
             return;
         }
         if (inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
             Map<String, String> firstpageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+            String nationality = firstpageStructureMap.get(Content.nationality);
+            if (StringUtil.isNotBlank(nationality) && !"中国".equals(nationality)) {
+                status.set("0");
+                return;
+            }
             String idNumber = firstpageStructureMap.get(Content.idNumber);
             if (!CatalogueUtil.isEmpty(idNumber)) {
                 status.set("0");

+ 3 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP0166.java

@@ -31,6 +31,9 @@ public class FIRP0166 extends QCCatalogue {
             }
             firstAdmissionMarry = firstAdmissionMarry.replace("离异","离婚");
             admissionMarry = admissionMarry.replace("离异","离婚");
+            if (firstAdmissionMarry.equals("丧偶") && admissionMarry.contains("已故")) {
+                return;
+            }
             if (!CatalogueUtil.compareToken(firstAdmissionMarry, admissionMarry)) {
                 status.set("-1");
             }

+ 31 - 7
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP0184.java

@@ -5,8 +5,13 @@ 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.BeHospitalizedDoc;
+import com.lantone.qc.pub.model.entity.AllergyMedicine;
+import com.lantone.qc.pub.model.label.PastLabel;
+import com.lantone.qc.pub.util.StringUtil;
 import org.springframework.stereotype.Component;
 
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -18,16 +23,35 @@ import java.util.Map;
 @Component
 public class FIRP0184 extends QCCatalogue {
     public void start(InputInfo inputInfo, OutputInfo outputInfo) {
-        if (inputInfo.getFirstPageRecordDoc() == null){
-            status.set("0");
+        status.set("0");
+        BeHospitalizedDoc beHospitalizedDoc = inputInfo.getBeHospitalizedDoc();
+        if (inputInfo.getFirstPageRecordDoc() == null || beHospitalizedDoc == null) {
             return;
         }
-        if (inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
-            Map<String, String> firstpageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+        Map<String, String> firstpageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+        PastLabel pastLabel = beHospitalizedDoc.getPastLabel();
+        if (pastLabel == null) {
+            return;
+        }
+        List<AllergyMedicine> allergyMedicines = pastLabel.getAllergyMedicines();
+        if (allergyMedicines == null) {
+            return;
+        }
+
+        long count = allergyMedicines.stream().filter(allergyMedicine -> {
+            boolean flag = false;
+            if (allergyMedicine.getNegative() == null
+                    && StringUtil.isNotBlank(allergyMedicine.getName())) {
+                flag = true;
+            }
+            return flag;
+        }).count();
+
+        if (count > 0 && firstpageStructureMap != null) {
             String drugAllergy = firstpageStructureMap.get(Content.drugAllergy);
-//            String allergyDrug = firstpageStructureMap.get(Content.allergyDrug);
-            if (!CatalogueUtil.isEmpty(drugAllergy)) {
-                status.set("0");
+            if (CatalogueUtil.isEmpty(drugAllergy)) {
+                status.set("-1");
+                return;
             }
         }
     }

+ 11 - 12
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP0193.java

@@ -33,19 +33,18 @@ public class FIRP0193 extends QCCatalogue {
         List<OperationDoc> operationDocs = inputInfo.getOperationDocs();
         List<String> operations = new ArrayList<>();
         List<String> operations_first = new ArrayList<>();
-        if (operationDocs == null) {
-            return;
-        }
-        for (OperationDoc opd : operationDocs) {
-            OperationDiscussionDoc operationDiscussionDoc = opd.getOperationDiscussionDoc();
-            if (operationDiscussionDoc == null) {
-                continue;
-            }
-            String operativeMethod = operationDiscussionDoc.getStructureMap().get("手术方式");
-            if (StringUtil.isBlank(operativeMethod)) {
-                continue;
+        if (ListUtil.isNotEmpty(operationDocs)) {
+            for (OperationDoc opd : operationDocs) {
+                OperationDiscussionDoc operationDiscussionDoc = opd.getOperationDiscussionDoc();
+                if (operationDiscussionDoc == null) {
+                    continue;
+                }
+                String operativeMethod = operationDiscussionDoc.getStructureMap().get("手术方式");
+                if (StringUtil.isBlank(operativeMethod)) {
+                    continue;
+                }
+                operations.add(operativeMethod);
             }
-            operations.add(operativeMethod);
         }
         Map<String, Object> firstPageRecordDocStructureMap = firstPageRecordDoc.getStructureExtMap();
         List<Map<String, String>> mapList = (List<Map<String, String>>) firstPageRecordDocStructureMap.get(Content.operative_information);

+ 1 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP0196.java

@@ -19,6 +19,7 @@ import java.util.Map;
 public class FIRP0196 extends QCCatalogue {
     public void start(InputInfo inputInfo, OutputInfo outputInfo) {
         /**
+         * 入院记录中现病史未描述昏迷,不提示规则
          * 如果入院前天数和入院后天数不为空,且不是数字,例如是“-”,就不报错
          * 如果天数是数字,那么小时和分都不能为空
          */

+ 6 - 2
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP0255.java

@@ -5,6 +5,8 @@ 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.LeaveHospitalDoc;
+import com.lantone.qc.pub.util.StringUtil;
 import org.springframework.stereotype.Component;
 
 import java.util.Map;
@@ -19,10 +21,12 @@ import java.util.Map;
 public class FIRP0255 extends QCCatalogue {
     public void start(InputInfo inputInfo, OutputInfo outputInfo) {
         status.set("0");
-        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+        LeaveHospitalDoc leaveHospitalDoc = inputInfo.getLeaveHospitalDoc();
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null && leaveHospitalDoc != null) {
+            Map<String, String> leaveHospitalStructureMap = leaveHospitalDoc.getStructureMap();
             Map<String, String> firstpageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
             String name = firstpageStructureMap.get(Content.outcome);
-            if (CatalogueUtil.isEmpty(name)){
+            if (CatalogueUtil.isEmpty(name) && StringUtil.isNotBlank(leaveHospitalStructureMap.get("治疗结果"))) {
                 status.set("-1");
             }
         }

+ 10 - 9
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03038.java

@@ -23,27 +23,28 @@ import java.util.Map;
 public class FIRP03038 extends QCCatalogue {
     @Autowired
     private SpecialStorageUtil specialStorageUtil;
+
     public void start(InputInfo inputInfo, OutputInfo outputInfo) {
         status.set("0");
         if (inputInfo.getFirstPageRecordDoc() == null) {
             return;
         }
-        Map<String, Map<String,String>> hostpital_standDiag = specialStorageUtil.getJsonStringValue(KernelConstants.HOSPITAL_DIAG_MAP);
+        Map<String, Map<String, String>> hostpital_standDiag = specialStorageUtil.getJsonStringValue(KernelConstants.HOSPITAL_DIAG_MAP);
         if (inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
             Map<String, Object> firstpageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureExtMap();
-            JSONArray out_diag = (JSONArray)firstpageStructureMap.get("出院诊断");
+            JSONArray out_diag = (JSONArray) firstpageStructureMap.get("出院诊断");
             if (out_diag.size() > 0) {
-                for (int i=0;i<out_diag.size();i++) {
+                for (int i = 0; i < out_diag.size(); i++) {
                     JSONObject jsonObject = out_diag.getJSONObject(i);
-                    String diag_code = (String)jsonObject.get("诊断编码");
+                    String diag_code = (String) jsonObject.get("诊断编码");
                     String diag_name = (String) jsonObject.get("诊断名称");
-                    if(StringUtils.isNotBlank(diag_code) && hostpital_standDiag.containsKey(diag_name)){
-                        Map<String,String> s = hostpital_standDiag.get(diag_name);
-                        if(s != null){
+                    if (StringUtils.isNotBlank(diag_code) && hostpital_standDiag.containsKey(diag_name)) {
+                        Map<String, String> s = hostpital_standDiag.get(diag_name);
+                        if (s != null) {
                             String icd10 = s.get("icd10");
-                            if(StringUtils.isNotBlank(icd10) && icd10.equals(diag_code)){
+                            if (StringUtils.isNotBlank(icd10) && icd10.equals(diag_code)) {
                                 status.set("0");
-                            }else {
+                            } else {
                                 status.set("-1");
                                 return;
                             }

+ 33 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03200.java

@@ -0,0 +1,33 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03200
+ * @Description :治疗类别未填写
+ * @Author : wsy
+ * @Date: 2022-03-16 20:11
+ */
+@Component
+public class FIRP03200 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getFirstPageRecordDoc() == null) {
+            status.set("0");
+            return;
+        }
+        if (inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+            Map<String, String> firstPageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+            String treatmentType = firstPageStructureMap.get(Content.treatmentType);//治疗类别
+            if (StringUtil.isNotBlank(treatmentType)) {
+                status.set("0");
+            }
+        }
+    }
+}

+ 40 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03201.java

@@ -0,0 +1,40 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03201
+ * @Description : 治疗类别填写错误
+ * @Author : wsy
+ * @Date: 2022-03-15 16:13
+ */
+@Component
+public class FIRP03201 extends QCCatalogue {
+    public List<String> wordList = Arrays.asList("中医", "民族医", "中西医", "西医");
+
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() == null) {
+            return;
+        }
+        if (inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+            Map<String, String> firstPageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+            String treatmentType = firstPageStructureMap.get(Content.treatmentType);//治疗类别
+            if (StringUtil.isBlank(treatmentType)) {
+                return;
+            }
+            if (!wordList.contains(treatmentType)) {
+                status.set("-1");
+            }
+        }
+    }
+}

+ 33 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03202.java

@@ -0,0 +1,33 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03202
+ * @Description :门(急)诊诊断(中医)未填写
+ * @Author : wsy
+ * @Date: 2022-03-16 20:11
+ */
+@Component
+public class FIRP03202 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getFirstPageRecordDoc() == null) {
+            status.set("0");
+            return;
+        }
+        if (inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+            Map<String, String> firstPageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+            String outpatientEmrChDiagnose = firstPageStructureMap.get(Content.outpatientEmrChDiagnose);//门急诊诊断(中医)
+            if (StringUtil.isNotBlank(outpatientEmrChDiagnose)) {
+                status.set("0");
+            }
+        }
+    }
+}

+ 37 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03203.java

@@ -0,0 +1,37 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03203
+ * @Description : 门(急)诊诊断(中医)填写不标准
+ * @Author : wsy
+ * @Date: 2022-03-15 16:13
+ */
+@Component
+public class FIRP03203 extends QCCatalogue {
+    public List<String> wordlist = Arrays.asList("中医", "民族医", "中西医", "西医");
+
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+//        if (inputInfo.getFirstPageRecordDoc() == null) {
+//            return;
+//        }
+//        if (inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+//            Map<String, String> firstPageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+//            String outpatientEmrChDiagnose = firstPageStructureMap.get(Content.outpatientEmrChDiagnose);//门急诊诊断(中医)
+//            if (StringUtil.isBlank(treatmentType)) {
+                return;
+//            }
+//        }
+    }
+}

+ 33 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03204.java

@@ -0,0 +1,33 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03204
+ * @Description :门(急)诊诊断(中医)疾病编码未填写
+ * @Author : wsy
+ * @Date: 2022-03-16 20:11
+ */
+@Component
+public class FIRP03204 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getFirstPageRecordDoc() == null) {
+            status.set("0");
+            return;
+        }
+        if (inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+            Map<String, String> firstPageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+            String outpatientEmrChDiagnoseCode = firstPageStructureMap.get(Content.outpatientEmrChDiagnoseCode);//门急诊诊断编码(中医)
+            if (StringUtil.isNotBlank(outpatientEmrChDiagnoseCode)) {
+                status.set("0");
+            }
+        }
+    }
+}

+ 34 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03205.java

@@ -0,0 +1,34 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @ClassName : FIRP03205
+ * @Description : 门(急)诊诊断(中医)疾病编码填写不标准
+ * @Author : wsy
+ * @Date: 2022-03-15 16:13
+ */
+@Component
+public class FIRP03205 extends QCCatalogue {
+    public List<String> wordlist = Arrays.asList("中医", "民族医", "中西医", "西医");
+
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+//        if (inputInfo.getFirstPageRecordDoc() == null) {
+//            return;
+//        }
+//        if (inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+//            Map<String, String> firstPageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+//            String outpatientEmrChDiagnose = firstPageStructureMap.get(Content.outpatientEmrChDiagnose);//门急诊诊断(中医)
+//            if (StringUtil.isBlank(treatmentType)) {
+                return;
+//            }
+//        }
+    }
+}

+ 39 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03206.java

@@ -0,0 +1,39 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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.ListUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03206
+ * @Description : 出院中医主病名称未填写
+ * @Author : wsy
+ * @Date: 2022-03-06 17:28
+ */
+@Component
+public class FIRP03206 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+            Map<String, Object> firstpageStructureMapExt = inputInfo.getFirstPageRecordDoc().getStructureExtMap();
+            List<Map<String, String>> dischargeDiag = (List) firstpageStructureMapExt.get(Content.dischargeDiag);
+            if (ListUtil.isEmpty(dischargeDiag)) {
+                return;
+            }
+            for (Map<String, String> stringStringMap : dischargeDiag) {
+                if ("中医".equals(stringStringMap.get(Content.chinese_western_type))) {
+                    if ("主病".equals(stringStringMap.get(Content.diagnose_type)) && CatalogueUtil.isEmpty(stringStringMap.get(Content.diagnose_name))) {
+                        status.set("-1");
+                    }
+                }
+            }
+        }
+    }
+}

+ 39 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03207.java

@@ -0,0 +1,39 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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.ListUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03207
+ * @Description : 出院中医主病名称填写不标准
+ * @Author : wsy
+ * @Date: 2022-03-06 17:28
+ */
+@Component
+public class FIRP03207 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+//        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+//            Map<String, Object> firstpageStructureMapExt = inputInfo.getFirstPageRecordDoc().getStructureExtMap();
+//            List<Map<String, String>> dischargeDiag = (List) firstpageStructureMapExt.get(Content.dischargeDiag);
+//            if (ListUtil.isEmpty(dischargeDiag)) {
+//                return;
+//            }
+//            for (Map<String, String> stringStringMap : dischargeDiag) {
+//                if ("中医".equals(stringStringMap.get(Content.chinese_western_type))) {
+//                    if ("主病".equals(stringStringMap.get(Content.diagnose_type)) && CatalogueUtil.isEmpty(stringStringMap.get(Content.diagnose_name))) {
+//
+//                    }
+//                }
+//            }
+//        }
+    }
+}

+ 40 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03208.java

@@ -0,0 +1,40 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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.ListUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03208
+ * @Description : 出院中医主病编码未填写
+ * @Author : wsy
+ * @Date: 2022-03-06 17:28
+ */
+@Component
+public class FIRP03208 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+            Map<String, Object> firstpageStructureMapExt = inputInfo.getFirstPageRecordDoc().getStructureExtMap();
+            List<Map<String, String>> dischargeDiag = (List) firstpageStructureMapExt.get(Content.dischargeDiag);
+            if (ListUtil.isEmpty(dischargeDiag)) {
+                return;
+            }
+            for (Map<String, String> stringStringMap : dischargeDiag) {
+                if ("中医".equals(stringStringMap.get(Content.chinese_western_type))) {
+                    if ("主病".equals(stringStringMap.get(Content.diagnose_type)) && !CatalogueUtil.isEmpty(stringStringMap.get(Content.diagnose_name))
+                            && CatalogueUtil.isEmpty(stringStringMap.get(Content.icd_code))) {
+                        status.set("-1");
+                    }
+                }
+            }
+        }
+    }
+}

+ 40 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03209.java

@@ -0,0 +1,40 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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.ListUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03209
+ * @Description : 出院中医主病编码填写不标准
+ * @Author : wsy
+ * @Date: 2022-03-06 17:28
+ */
+@Component
+public class FIRP03209 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+//        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+//            Map<String, Object> firstpageStructureMapExt = inputInfo.getFirstPageRecordDoc().getStructureExtMap();
+//            List<Map<String, String>> dischargeDiag = (List) firstpageStructureMapExt.get(Content.dischargeDiag);
+//            if (ListUtil.isEmpty(dischargeDiag)) {
+//                return;
+//            }
+//            for (Map<String, String> stringStringMap : dischargeDiag) {
+//                if ("中医".equals(stringStringMap.get(Content.chinese_western_type))) {
+//                    if ("主病".equals(stringStringMap.get(Content.diagnose_type)) && !CatalogueUtil.isEmpty(stringStringMap.get(Content.diagnose_name))
+//                            && CatalogueUtil.isEmpty(stringStringMap.get(Content.icd_code))) {
+//
+//                    }
+//                }
+//            }
+//        }
+    }
+}

+ 39 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03210.java

@@ -0,0 +1,39 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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.ListUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03210
+ * @Description : 出院主病入院病情未填写
+ * @Author : wsy
+ * @Date: 2022-03-06 17:28
+ */
+@Component
+public class FIRP03210 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+            Map<String, Object> firstpageStructureMapExt = inputInfo.getFirstPageRecordDoc().getStructureExtMap();
+            List<Map<String, String>> dischargeDiag = (List) firstpageStructureMapExt.get(Content.dischargeDiag);
+            if (ListUtil.isEmpty(dischargeDiag)) {
+                return;
+            }
+            for (Map<String, String> stringStringMap : dischargeDiag) {
+                if ("中医".equals(stringStringMap.get(Content.chinese_western_type))) {
+                    if ("主病".equals(stringStringMap.get(Content.diagnose_type)) && CatalogueUtil.isEmpty(stringStringMap.get(Content.inStatus))) {
+                        status.set("-1");
+                    }
+                }
+            }
+        }
+    }
+}

+ 51 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03211.java

@@ -0,0 +1,51 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03211
+ * @Description : 主病“入院病情”不在编码范围内
+ * @Author : wsy
+ * @Date: 2022-03-15 16:13
+ */
+@Component
+public class FIRP03211 extends QCCatalogue {
+    public List<String> wordList = Arrays.asList("有", "临床未确定", "情况不明", "无");
+
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        String inStatus = "";
+        if (inputInfo.getFirstPageRecordDoc() == null) {
+            return;
+        }
+        if (inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+            Map<String, Object> firstpageStructureMapExt = inputInfo.getFirstPageRecordDoc().getStructureExtMap();
+            List<Map<String, String>> dischargeDiag = (List) firstpageStructureMapExt.get(Content.dischargeDiag);
+            if (ListUtil.isEmpty(dischargeDiag)) {
+                return;
+            }
+            for (Map<String, String> stringStringMap : dischargeDiag) {
+                if ("中医".equals(stringStringMap.get(Content.chinese_western_type))) {
+                    if ("主病".equals(stringStringMap.get(Content.diagnose_type))) {
+                        inStatus = stringStringMap.get(Content.inStatus);
+                    }
+                }
+            }
+
+            if (StringUtil.isNotBlank(inStatus) && !wordList.contains(inStatus)) {
+                status.set("-1");
+                return;
+            }
+        }
+    }
+}

+ 40 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03212.java

@@ -0,0 +1,40 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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.ListUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03212
+ * @Description : 出院中医主证名称未填写
+ * @Author : Wsy
+ * @Date: 2022-03-06 17:28
+ */
+@Component
+public class FIRP03212 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+            Map<String, Object> firstpageStructureMapExt = inputInfo.getFirstPageRecordDoc().getStructureExtMap();
+            List<Map<String, String>> dischargeDiag = (List) firstpageStructureMapExt.get(Content.dischargeDiag);
+            if (ListUtil.isEmpty(dischargeDiag)) {
+                return;
+            }
+            for (Map<String, String> stringStringMap : dischargeDiag) {
+                if ("中医".equals(stringStringMap.get(Content.chinese_western_type))) {
+                    if ("主症".equals(stringStringMap.get(Content.diagnose_type)) && CatalogueUtil.isEmpty(stringStringMap.get(Content.diagnose_name))) {
+                        status.set("-1");
+                        return;
+                    }
+                }
+            }
+        }
+    }
+}

+ 80 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03213.java

@@ -0,0 +1,80 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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.Content;
+import com.lantone.qc.pub.model.InputInfo;
+import com.lantone.qc.pub.model.OutputInfo;
+import com.lantone.qc.pub.model.doc.FirstPageRecordDoc;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03213
+ * @Description :  出院中医主病诊断编码与性别不符
+ * @Author : Wsy
+ * @Date: 2022-3-13 15:51
+ */
+@Component
+public class FIRP03213 extends QCCatalogue {
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        FirstPageRecordDoc firstPageRecordDoc = inputInfo.getFirstPageRecordDoc();
+        if (firstPageRecordDoc == null) {
+            return;
+        }
+        Map<String, Object> structureExtMap = firstPageRecordDoc.getStructureExtMap();
+        if (structureExtMap == null) {
+            return;
+        }
+        String icdCode = "";
+        List<Map<String, String>> outpatientEmergencyDiag = (List) structureExtMap.get(Content.dischargeDiag);
+        if (outpatientEmergencyDiag == null || outpatientEmergencyDiag.size() == 0) {
+            return;
+        }
+
+        for (Map<String, String> map : outpatientEmergencyDiag) {
+            if (StringUtil.isNotBlank(map.get(Content.diagnose_type)) && "主病".equals(map.get(Content.diagnose_type))) {
+                icdCode = map.get(Content.icd_code);
+            }
+        }
+
+        if (StringUtil.isBlank(icdCode)) {
+            return;
+        }
+
+        String gender = (String) structureExtMap.get("性别");
+        if (StringUtil.isBlank(gender)) {
+            return;
+        }
+        List<String> noMatchWords = null;
+        if (gender.contains("男")) {
+            /* 男性不合理诊断编码 */
+            noMatchWords = Lists.newArrayList("BF", "BFY", "BFY010", "BFY020", "BFY030", "BFY040", "BFY050", "BFY060", "BFY080", "BFY090", "BFY100", "BFY110", "BFY120", "BFY130", "BFY140",
+                    "BFY150", "BFY160", "BFY170", "BFY180", "BFY190", "BFY200", "BFY210", "BFY220", "BFY70", "BFD", "BFD010", "BFR", "BFR010", "BFR020", "BFR030", "BFR040", "BFR050", "BFR051", "BFR052",
+                    "BFR060", "BFR070", "BFR080", "BFR090", "BFR100", "BFR110", "BFR120", "BFR130", "BFR140", "BFR150", "BFR160", "BFR170", "BFR180", "BFR190", "BFR200", "BFC", "BFC010", "BFC011", "BFC020",
+                    "BFC030", "BFC040", "BFC050", "BFC060", "BFC070", "BFC080", "BFC081", "BFC090", "BFC091", "BFC100", "BFC110", "BFC120", "BFC130", "BFC140", "BFC150", "BFC160", "BFC170", "BFC180", "BFL",
+                    "BFL000", "BFA", "BFA000", "BFZ", "BFZ010", "BFZ020", "BFZ030", "BFZ040", "BFZ050", "BFZ060", "BFZ070", "BFZ080");
+        } else if (gender.contains("女")) {
+            /* 女性不合理诊断编码 */
+            noMatchWords = Lists.newArrayList("BNS160", "BNS161", "BNS162", "BNS170", "BNS180", "BWN", "BWN050", "BWN010", "BWN020", "BWN030", "BWN040",
+                    "BWN060", "BWN070", "BWN080", "ZBMRD1", "ZBRS20", "ZYV071", "ZYV231", "ZYV252", "ZYX111", "ZZPF11", "ZZS110", "ZZS120", "ZZSM20", "ZLHR20");
+        }
+        if (noMatchWords == null || noMatchWords.size() == 0) {
+            return;
+        }
+
+        for (String noMatchWord : noMatchWords) {
+            if (icdCode.contains(noMatchWord)) {
+                status.set("-1");
+                info.set(noMatchWord);
+                return;
+            }
+        }
+    }
+}

+ 41 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03214.java

@@ -0,0 +1,41 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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.ListUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @ClassName : FIRP03214
+ * @Description : 出院中医主证编码未填写
+ * @Author : cy
+ * @Date: 2022-03-06 17:28
+ */
+@Component
+public class FIRP03214 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+            Map<String, Object> firstpageStructureMapExt = inputInfo.getFirstPageRecordDoc().getStructureExtMap();
+            List<Map<String, String>> dischargeDiag = (List) firstpageStructureMapExt.get(Content.dischargeDiag);
+            if (ListUtil.isEmpty(dischargeDiag)) {
+                return;
+            }
+            for (Map<String, String> stringStringMap : dischargeDiag) {
+                if ("中医".equals(stringStringMap.get(Content.chinese_western_type))) {
+                    if ("主症".equals(stringStringMap.get(Content.diagnose_type)) && !CatalogueUtil.isEmpty(stringStringMap.get(Content.diagnose_name))
+                            && CatalogueUtil.isEmpty(stringStringMap.get(Content.icd_code))) {
+                        status.set("-1");
+                    }
+                }
+            }
+        }
+    }
+}

+ 40 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03215.java

@@ -0,0 +1,40 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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.ListUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03215
+ * @Description : 出院主证入院病情未填写
+ * @Author : cy
+ * @Date: 2022-03-06 17:28
+ */
+@Component
+public class FIRP03215 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+            Map<String, Object> firstpageStructureMapExt = inputInfo.getFirstPageRecordDoc().getStructureExtMap();
+            List<Map<String, String>> dischargeDiag = (List) firstpageStructureMapExt.get(Content.dischargeDiag);
+            if (ListUtil.isEmpty(dischargeDiag)) {
+                return;
+            }
+            for (Map<String, String> stringStringMap : dischargeDiag) {
+                if ("中医".equals(stringStringMap.get(Content.chinese_western_type))) {
+                    if ("主症".equals(stringStringMap.get(Content.diagnose_type)) && !CatalogueUtil.isEmpty(stringStringMap.get(Content.diagnose_name))
+                            && CatalogueUtil.isEmpty(stringStringMap.get(Content.inStatus))) {
+                        status.set("-1");
+                    }
+                }
+            }
+        }
+    }
+}

+ 43 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03216.java

@@ -0,0 +1,43 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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.ListUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03216
+ * @Description : 出院主证入院病情填写错误
+ * @Author : cy
+ * @Date: 2022-03-06 17:28
+ */
+@Component
+public class FIRP03216 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+            Map<String, Object> firstpageStructureMapExt = inputInfo.getFirstPageRecordDoc().getStructureExtMap();
+            List<Map<String, String>> dischargeDiag = (List) firstpageStructureMapExt.get(Content.dischargeDiag);
+            if (ListUtil.isEmpty(dischargeDiag)) {
+                return;
+            }
+            for (Map<String, String> stringStringMap : dischargeDiag) {
+                if ("中医".equals(stringStringMap.get(Content.chinese_western_type))) {
+                    if ("主症".equals(stringStringMap.get(Content.diagnose_type)) && !CatalogueUtil.isEmpty(stringStringMap.get(Content.diagnose_name))
+                            && !CatalogueUtil.isEmpty(stringStringMap.get(Content.inStatus))) {
+                        String inStatus = stringStringMap.get(Content.inStatus);
+                        if(!Content.ADMISSIONCONDITION.stream().anyMatch(obj->inStatus.equals(obj))){
+                            status.set("-1");
+                        }
+                    }
+                }
+            }
+        }
+    }
+}

+ 32 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03217.java

@@ -0,0 +1,32 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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.ListUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03217
+ * @Description : 实施临床路径未填写
+ * @Author : cy
+ * @Date: 2022-03-06 17:28
+ */
+@Component
+public class FIRP03217 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+
+            Map<String, String> structureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+            if(CatalogueUtil.isEmpty(structureMap.get(Content.implementation_clinical_pathway))){
+                status.set("-1");
+            }
+        }
+    }
+}

+ 35 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03218.java

@@ -0,0 +1,35 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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 org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+import static com.lantone.qc.pub.Content.inStatus;
+
+/**
+ * @ClassName : FIRP03218
+ * @Description : 实施临床路径填写错误
+ * @Author : cy
+ * @Date: 2022-03-06 17:28
+ */
+@Component
+public class FIRP03218 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+
+            Map<String, String> structureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+            if(!CatalogueUtil.isEmpty(structureMap.get(Content.implementation_clinical_pathway))){
+                String str = structureMap.get(Content.implementation_clinical_pathway);
+                if(!Content.CLINICALPATHWAY.stream().anyMatch(obj->str.equals(obj))){
+                    status.set("-1");
+                }
+            }
+        }
+    }
+}

+ 29 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03219.java

@@ -0,0 +1,29 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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 org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03219
+ * @Description : 使用医疗机构中药制剂未填写
+ * @Author : cy
+ * @Date: 2022-03-06 17:28
+ */
+@Component
+public class FIRP03219 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+            Map<String, String> structureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+            if(CatalogueUtil.isEmpty(structureMap.get(Content.is_chinese_medicine_preparation))){
+                    status.set("-1");
+            }
+        }
+    }
+}

+ 47 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03220.java

@@ -0,0 +1,47 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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 org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03220
+ * @Description : 使用医疗机构中药制剂填写错误
+ * @Author : cy
+ * @Date: 2022-03-06 17:28
+ */
+@Component
+public class FIRP03220 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+
+            Map<String, String> structureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+            if(!CatalogueUtil.isEmpty(structureMap.get(Content.is_chinese_medicine_preparation))){
+                String str = structureMap.get(Content.is_chinese_medicine_preparation);
+                if(! Content.MARK.stream().anyMatch(obj->str.equals(obj))){
+                    status.set("-1");
+                }
+                String feeStr = structureMap.get(Content.chn_med_fee);
+                String feeSec = structureMap.get(Content.chn_herb_fee);
+                Double feeStrDou = 0D;
+                Double feeSecDou = 0D;
+               if( !CatalogueUtil.isEmpty(feeStr)){
+                   feeStrDou = Double.valueOf(feeStr);
+               }
+                if( !CatalogueUtil.isEmpty(feeSec)){
+                    feeSecDou = Double.valueOf(feeSec);
+                }
+                if((feeStrDou+feeSecDou)>0 &&  "否".equals(str)){
+                    status.set("-1");
+                }
+            }
+        }
+    }
+}

+ 29 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03221.java

@@ -0,0 +1,29 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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 org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03221
+ * @Description : 使用中医诊疗设备未填写
+ * @Author : cy
+ * @Date: 2022-03-06 17:28
+ */
+@Component
+public class FIRP03221 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+            Map<String, String> structureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+            if(CatalogueUtil.isEmpty(structureMap.get(Content.is_chinese_diagnose_equipment))){
+                    status.set("-1");
+            }
+        }
+    }
+}

+ 34 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03222.java

@@ -0,0 +1,34 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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 org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03218
+ * @Description : 使用中医诊疗设备填写错误
+ * @Author : cy
+ * @Date: 2022-03-06 17:28
+ */
+@Component
+public class FIRP03222 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+
+            Map<String, String> structureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+            if(!CatalogueUtil.isEmpty(structureMap.get(Content.is_chinese_diagnose_equipment))){
+                String str = structureMap.get(Content.is_chinese_diagnose_equipment);
+                if(!Content.MARK.stream().anyMatch(obj->str.equals(obj))){
+                    status.set("-1");
+                }
+            }
+        }
+    }
+}

+ 29 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03223.java

@@ -0,0 +1,29 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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 org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03223
+ * @Description : 使用中医诊疗技术未填写
+ * @Author : cy
+ * @Date: 2022-03-06 17:28
+ */
+@Component
+public class FIRP03223 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+            Map<String, String> structureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+            if(CatalogueUtil.isEmpty(structureMap.get(Content.is_chinese_diagnose_technology))){
+                    status.set("-1");
+            }
+        }
+    }
+}

+ 47 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03224.java

@@ -0,0 +1,47 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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 org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03224
+ * @Description : 使用中医诊疗技术填写错误
+ * @Author : cy
+ * @Date: 2022-03-06 17:28
+ */
+@Component
+public class FIRP03224 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+
+            Map<String, String> structureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+            if(!CatalogueUtil.isEmpty(structureMap.get(Content.is_chinese_diagnose_technology))){
+                String str = structureMap.get(Content.is_chinese_diagnose_technology);
+                if(! Content.MARK.stream().anyMatch(obj->str.equals(obj))){
+                    status.set("-1");
+                }
+                String feeStr = structureMap.get(Content.chn_med_fee);
+                String feeSec = structureMap.get(Content.chn_herb_fee);
+                Double feeStrDou = 0D;
+                Double feeSecDou = 0D;
+               if( !CatalogueUtil.isEmpty(feeStr)){
+                   feeStrDou = Double.valueOf(feeStr);
+               }
+                if( !CatalogueUtil.isEmpty(feeSec)){
+                    feeSecDou = Double.valueOf(feeSec);
+                }
+                if((feeStrDou+feeSecDou)>0 &&  "否".equals(str)){
+                    status.set("-1");
+                }
+            }
+        }
+    }
+}

+ 29 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03225.java

@@ -0,0 +1,29 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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 org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03225
+ * @Description : 辩证施护未填写
+ * @Author : cy
+ * @Date: 2022-03-06 17:28
+ */
+@Component
+public class FIRP03225 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+            Map<String, String> structureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+            if(CatalogueUtil.isEmpty(structureMap.get(Content.dialectical_nursing))){
+                    status.set("-1");
+            }
+        }
+    }
+}

+ 34 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03226.java

@@ -0,0 +1,34 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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 org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03226
+ * @Description : 辩证施护填写错误
+ * @Author : cy
+ * @Date: 2022-03-06 17:28
+ */
+@Component
+public class FIRP03226 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+
+            Map<String, String> structureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+            if(!CatalogueUtil.isEmpty(structureMap.get(Content.dialectical_nursing))){
+                String str = structureMap.get(Content.dialectical_nursing);
+                if(!Content.MARK.stream().anyMatch(obj->str.equals(obj))){
+                    status.set("-1");
+                }
+            }
+        }
+    }
+}

+ 50 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/firstpagerecord/FIRP03229.java

@@ -0,0 +1,50 @@
+package com.lantone.qc.kernel.catalogue.firstpagerecord;
+
+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.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP03229
+ * @Description : 身份证号与性别不符合
+ * @Author : wsy
+ * @Date: 2022-04-12 16:13
+ */
+@Component
+public class FIRP03229 extends QCCatalogue {
+    /**
+     * 1.获取病案首页的患者性别和身份证号,若任一不存在则通过
+     * 2.根据18位数的身份证号码的第十七位(倒数第二位)判断性别,如果为奇数则为男性,偶数则为女性
+     * 3.校验首页填写的性别是否和身份证性别一致
+     */
+
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() == null) {
+            return;
+        }
+        if (inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+            Map<String, String> firstPageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+            String idNumber = firstPageStructureMap.get(Content.idNumber);//身份证号
+            String gender = firstPageStructureMap.get(Content.gender);//性别
+            if (StringUtil.isBlank(idNumber) || StringUtil.isBlank(gender)) {
+                return;
+            }
+            if (idNumber.length() > 17) {
+                int num = Integer.parseInt(idNumber.substring(16, 17));
+                //奇数表示男性,偶数表示女性;
+                if (gender.contains("男") && num % 2 == 0) {
+                    status.set("-1");
+                }
+                if (gender.contains("女") && num % 2 == 1) {
+                    status.set("-1");
+                }
+            }
+        }
+    }
+}

+ 2 - 2
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/changshaxy/behospitalized/BEH02966.java

@@ -51,11 +51,11 @@ public class BEH02966 extends QCCatalogue {
         if (gender.contains("男")) {
             /* 男性不合理词 */
             noMatchWords = Lists.newArrayList("阴道", "宫颈", "子宫", "宫底", "胎位", "胎数", "胎心",
-                    "宫缩", "宫口", "输卵管", "卵巢", "输卵管", "阴唇", "阴蒂", "阴道前庭", "前庭大腺", "处女膜");
+                    "宫缩", "宫口", "输卵管", "卵巢", "输卵管", "阴唇", "阴蒂", "阴道前庭", "前庭大腺", "处女膜", "女");
         } else if (gender.contains("女")) {
             /* 女性不合理词 */
             noMatchWords = Lists.newArrayList("睾丸", "阴茎", "精索", "包皮", "附睾", "输精管",
-                    "射精管", "尿道海绵体", "冠状沟", "精阜", "精囊腺", "阴囊");
+                    "射精管", "尿道海绵体", "冠状沟", "精阜", "精囊腺", "阴囊", "男");
         }
         if (noMatchWords == null || noMatchWords.size() == 0) {
             return;

+ 2 - 2
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/changshaxy/clinicalblood/CLI0301.java

@@ -36,8 +36,8 @@ public class CLI0301 extends QCCatalogue {
                 informedConsentDoc -> {
                     boolean flag = false;
                     if (informedConsentDoc.getStructureMap() != null
-                            && StringUtil.isBlank(informedConsentDoc.getStructureMap().get("标题"))
-                            && Content.BLOODRECORDLIST.contains(informedConsentDoc.getStructureMap().get("标题"))) {
+                            && StringUtil.isNotBlank(informedConsentDoc.getStructureMap().get("标题"))
+                            && Content.BLOODRECORDLIST.stream().anyMatch(obj -> informedConsentDoc.getStructureMap().get("标题").contains(obj))) {
                         flag = true;
                     }
                     return flag;

+ 21 - 5
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/changshaxy/firstcourserecord/FIRC0093.java

@@ -12,8 +12,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Component;
 
 import java.text.ParseException;
-import java.util.Date;
-import java.util.Map;
+import java.util.*;
 
 /**
  * @ClassName : FIRC0093
@@ -23,6 +22,9 @@ import java.util.Map;
  */
 @Component
 public class FIRC0093 extends QCCatalogue {
+
+    private List<String> labelList = Arrays.asList("诊断依据", "鉴别诊断", "初步诊断", "病例分型", "入院诊断", "诊疗计划");
+
     public void start(InputInfo inputInfo, OutputInfo outputInfo) throws ParseException {
         status.set("0");
         FirstCourseRecordDoc firstCourseRecordDoc = inputInfo.getFirstCourseRecordDoc();
@@ -43,9 +45,11 @@ public class FIRC0093 extends QCCatalogue {
                     if (date_in == null || date_out == null) {
                         return;
                     }
+                    boolean empty = isEmpty(courseRecordDocStructureMap);
+
                     boolean firc = CatalogueUtil.compareTime(date_in, date_out, 8 * 60L);
-                    if (firc) {
-                        info.set("("+admisTime+"-"+couDate+")");
+                    if (firc || !empty) {
+                        info.set("(" + admisTime + "-" + couDate + ")");
                         status.set("-1");
                     }
                 }
@@ -60,7 +64,7 @@ public class FIRC0093 extends QCCatalogue {
                     }
                     boolean firc = CatalogueUtil.compareTime(date_in, date_out, 8 * 60L);
                     if (firc) {
-                        info.set("("+admisTime+"-"+date_out.toString()+")");
+                        info.set("(" + admisTime + "-" + date_out.toString() + ")");
                         status.set("-1");
                     }
                 }
@@ -68,6 +72,18 @@ public class FIRC0093 extends QCCatalogue {
         }
     }
 
+    private boolean isEmpty(Map<String, String> courseRecordDocStructureMap) {
+        for (String label : labelList) {
+            if (StringUtil.isBlank(courseRecordDocStructureMap.get(label))) {
+                String labelStr = courseRecordDocStructureMap.get(label).replaceAll(",?,?[0-9]\\.", "").replaceAll("[\\p{Punct}\\pP。-]", "").replace(" ", "");
+                if (StringUtil.isNotBlank(labelStr) && labelStr.length() > 1) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     private String getKeyByHospitalId() {
         switch (Content.hospital_Id) {
             case "1":               //长兴

+ 61 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/changshaxy/firstcourserecord/FIRC03086.java

@@ -0,0 +1,61 @@
+package com.lantone.qc.kernel.catalogue.hospital.changshaxy.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.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @ClassName : FIRC03086
+ * @Description : 治疗措施不具体(缺护理级别)
+ * @Author : wsy
+ * @Date: 2021-01-07 15:21
+ */
+@Component
+public class FIRC03086 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) {
+            status.set("0");
+            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 (structureV.contains("一级") || structureV.contains("二级") || structureV.contains("三级")) {
+            status.set("0");
+            return;
+        }
+        if (StringUtil.isNotBlank(structureV) && structureV.contains("护理")) {
+            findText = true;
+        }
+        if (treatPlanLabel.getNursingLevel() != null) {
+            if (findText && !treatPlanLabel.getNursingLevel().getName().contains("护理常规")) {
+                status.set("0");
+                return;
+            }
+        }
+        if (treatPlanLabel.getNursingLevel() == null || treatPlanLabel.getNursingLevel().getName().contains("护理常规")) {
+            status.set("-1");
+            return;
+        }
+    }
+}

+ 36 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/changshaxy/firstpagerecord/FIRP0170.java

@@ -0,0 +1,36 @@
+package com.lantone.qc.kernel.catalogue.hospital.changshaxy.firstpagerecord;
+
+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 org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP0170
+ * @Description :转科科别未填写
+ * @Author : 胡敬
+ * @Date: 2020-03-16 11:33
+ */
+@Component
+public class FIRP0170 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() == null) {
+            return;
+        }
+        if (inputInfo.getTransferRecordDocs() == null) {
+            return;
+        }
+        if (inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
+            Map<String, String> firstpageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+            String transferDept = firstpageStructureMap.get(Content.transferDept);
+            if (StringUtils.isEmpty(transferDept) || "【转科科室】".equals(transferDept)) {
+                status.set("-1");
+            }
+        }
+    }
+}

+ 0 - 1
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/changshaxy/firstpagerecord/FIRP03242.java

@@ -32,7 +32,6 @@ public class FIRP03242 extends QCCatalogue {
             }
             if (rehospitalization.equals("有") && objective.equals("-")) {
                 status.set("-1");
-                return;
             }
         }
     }

+ 0 - 2
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/changshaxy/firstpagerecord/FIRP03282.java

@@ -22,11 +22,9 @@ public class FIRP03282 extends QCCatalogue {
         }
         if (inputInfo.getFirstPageRecordDoc().getStructureMap()!=null){
             Map<String, String> structureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
-            Map<String, String> structureMap1 = inputInfo.getFirstPageRecordDoc().getStructureMap();
             if (structureMap != null){
                 String diagnosisFee = structureMap.get("病理诊断费");
                 if (StringUtil.isEmpty(diagnosisFee) || diagnosisFee.equals(Integer.valueOf(0))){
-                    status.set("-1");
                     return;
                 }
             }

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

@@ -0,0 +1,171 @@
+package com.lantone.qc.kernel.catalogue.hospital.changshaxy.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;
+
+/**
+ * @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("查房日期");
+                String illnessRecords = firstDirector.getStructureMap().get("病情记录");
+                if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(wardDateStr), 72 * 60L)) {
+                    if (StringUtil.isNotBlank(illnessRecords)) {
+                        status.set("0");
+                        return;
+                    } else {
+                        info.set("病情未记录内容");
+                        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;
+//    }
+}

+ 36 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/changshaxy/threelevelward/THR03199.java

@@ -0,0 +1,36 @@
+package com.lantone.qc.kernel.catalogue.hospital.changshaxy.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.Map;
+
+/**
+ * @ClassName : THR03199
+ * @Description : 查房中存在未书写病情(湘雅三院)
+ * @Author : 胡敬
+ * @Date: 2022-03-04 13:51
+ */
+@Component
+public class THR03199 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        ThreeLevelWardDoc threeLevelWardDoc = inputInfo.getThreeLevelWardDocs().get(0);
+        List<ThreeLevelWardDoc> allDoctorWradDocs = threeLevelWardDoc.getAllDoctorWradDocs();
+        for (ThreeLevelWardDoc threeLevelWard : allDoctorWradDocs) {
+            Map<String, String> structureMap = threeLevelWard.getStructureMap();
+            String wardDateStr = structureMap.get("查房日期");
+            String illnessRecords = structureMap.get("病情记录");
+            if (StringUtil.isBlank(illnessRecords)) {
+                info.set(wardDateStr);
+                status.set("-1");
+                return;
+            }
+        }
+    }
+}

+ 173 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ningbozhenhai/firstpagerecord/FIRP0178.java

@@ -0,0 +1,173 @@
+package com.lantone.qc.kernel.catalogue.hospital.ningbozhenhai.firstpagerecord;
+
+import com.alibaba.fastjson.JSONArray;
+import com.lantone.qc.kernel.catalogue.QCCatalogue;
+import com.lantone.qc.kernel.client.ChiefPresentSimilarityServiceClient;
+import com.lantone.qc.kernel.client.SimilarityServiceClient;
+import com.lantone.qc.kernel.structure.ai.ModelAI;
+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.ThreeLevelWardDoc;
+import com.lantone.qc.pub.util.ListUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP0178
+ * @Description :出院其他诊断不完全
+ * @Author : 胡敬
+ * @Date: 2020-03-16 14:01
+ */
+@Component
+public class FIRP0178 extends QCCatalogue {
+    @Autowired
+    SimilarityServiceClient similarityServiceClient;
+    @Autowired
+    ChiefPresentSimilarityServiceClient chiefPresentSimilarityServiceClient;
+
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getLeaveHospitalDoc() != null) {
+            String mainDiagnosis = "";
+            Map<String, Object> firstpageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureExtMap();
+            List<Map<String, String>> dischargeDiag = (List) firstpageStructureMap.get(Content.dischargeDiag);
+            if (ListUtil.isEmpty(dischargeDiag)) {
+                return;
+            }
+            if (dischargeDiag.get(0) != null) {
+                mainDiagnosis = dischargeDiag.get(0).get("诊断名称");
+            }
+
+            /* 病案首页出院小结诊断 除去主诊断*/
+            List<String> firstpageLeaveDiags = getFirstPageDiag(dischargeDiag);
+            if (ListUtil.isEmpty(firstpageLeaveDiags)) {
+                return;
+            }
+            List<ThreeLevelWardDoc> threeLevelWardDocs = inputInfo.getThreeLevelWardDocs();
+            /*DiagLabel leaveDiagLabel = inputInfo.getLeaveHospitalDoc().getLeaveDiagLabel();
+            if (leaveDiagLabel == null) {
+                return;
+            }
+            List<Diag> leaveDiags = leaveDiagLabel.getDiags();
+            List<String> leaveDiagsStr = putDiagToList(leaveDiags);*/
+            //出院小结得出院诊断,模型提取出现问题,需要手动以1.2.3.为界限切开
+            Map<String, String> leavehospitalStructureMap = inputInfo.getLeaveHospitalDoc().getStructureMap();
+            String leaveDiag = leavehospitalStructureMap.get("出院诊断");
+
+            List<String> leaveDiagsStr = cut(leaveDiag, mainDiagnosis);
+
+            /* 修改为疾病相似度模型 */
+            ModelAI modelAI = new ModelAI();
+            String infoStr = "";
+            //最主要是给医生提醒,看是否有出院诊断漏写
+            for (int i = 1; i < leaveDiagsStr.size(); i++) {
+                JSONArray jsonArray = modelAI.loadChiefPresentSimilarAI(leaveDiagsStr.get(i), firstpageLeaveDiags, false
+                        , "diagnose", chiefPresentSimilarityServiceClient);
+                if (jsonArray.size() == 2) {
+                    /* 相似度分数 */
+                    double likeRate = jsonArray.getDoubleValue(1);
+                    if (likeRate < 0.9) {
+                        infoStr = CatalogueUtil.concatInfo(infoStr, leaveDiagsStr.get(i));
+                    }
+                } else if (jsonArray.size() == 0) {
+                    infoStr = CatalogueUtil.concatInfo(infoStr, leaveDiagsStr.get(i));
+                }
+            }
+            if (StringUtil.isNotBlank(infoStr)) {
+                status.set("-1");
+                info.set(infoStr);
+            }
+            //补记病理
+            if (ListUtil.isNotEmpty(threeLevelWardDocs)) {
+                for (ThreeLevelWardDoc threeLevelWardDoc : threeLevelWardDocs) {
+                    List<ThreeLevelWardDoc> allDoctorWradDocs = threeLevelWardDoc.getAllDoctorWradDocs();
+                    if (ListUtil.isNotEmpty(allDoctorWradDocs)) {
+                        for (ThreeLevelWardDoc allDoctorWradDoc : allDoctorWradDocs) {
+                            String text = allDoctorWradDoc.getText();
+                            if (StringUtil.isBlank(text)) {
+                                Map<String, String> structureMap = allDoctorWradDoc.getStructureMap();
+                                text = structureMap.get("病情记录");
+                            }
+                            if (isHavePathology(text)) {
+                                status.set("0");
+                                info.remove();
+                                return;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private List<String> getFirstPageDiag(List<Map<String, String>> dischargeDiag) {
+        List<String> firstpageDiag = new ArrayList<>();
+        for (int i = 0; i < dischargeDiag.size(); i++) {
+            if ("主要诊断".equals(dischargeDiag.get(i).get("诊断类别"))) {
+                continue;
+            }
+            String diagnoseName = dischargeDiag.get(i).get(Content.diagnoseName);
+            if (StringUtil.isBlank(diagnoseName) || "-".equals(diagnoseName)) { // 诊断名称为空不算
+                continue;
+            }
+            // 去重
+            if (!firstpageDiag.contains(diagnoseName)) {
+                firstpageDiag.add(diagnoseName);
+            }
+        }
+        return firstpageDiag;
+    }
+
+//    private List<String> putDiagToList(List<Diag> diagList) {
+//        List<String> diags = new ArrayList<>();
+//        for (Diag diag : diagList) {
+//            // 去重
+//            if (!diags.contains(diag.getHospitalDiagName())) {
+//                diags.add(diag.getHospitalDiagName());
+//            }
+//        }
+//        return diags;
+//    }
+
+    private List<String> cut(String leaveDiag, String mainDiagnosis) {
+        List<String> diags = new ArrayList<>();
+        if (leaveDiag != null) {
+            leaveDiag.replace("西医诊断:", "西医诊断:").replace("补充诊断", "");
+            if (leaveDiag.contains("西医诊断:")) {
+                leaveDiag = leaveDiag.substring(leaveDiag.indexOf("西医诊断:") + "西医诊断:".length());
+            }
+            String[] leaveDiags = leaveDiag.split(",?,?[0-9]\\.");
+            for (String string : leaveDiags) {
+                if (!string.isEmpty()) {
+                    if (string.equals(mainDiagnosis)) {
+                        diags.add(0, string);
+                    } else {
+                        // 去重
+                        if (!diags.contains(string)) {
+                            diags.add(string);
+                        }
+                    }
+                }
+            }
+        }
+        return diags;
+    }
+
+    public boolean isHavePathology(String text) {
+        String rex = "[\\s\\S]*(?=补)[\\s\\S].{0,5}(?=病理)[\\s\\S]*";
+        String rex2 = "[\\s\\S]*(?=病理)[\\s\\S].{0,5}(?=补)[\\s\\S]*";
+        if (StringUtil.isNotBlank(text) && (text.matches(rex) || text.matches(rex2))) {
+            return true;
+        }
+        return false;
+    }
+
+    ;
+}

+ 45 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ningbozhongyi/clinicalblood/CLI0571.java

@@ -0,0 +1,45 @@
+package com.lantone.qc.kernel.catalogue.hospital.ningbozhongyi.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 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 : CLI0571
+ * @Description :  输血记录Rh血型未填写
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28
+ */
+@Component
+public class CLI0571 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        List<ClinicalBloodDoc> clinicalBloodDocs = inputInfo.getClinicalBloodDocs();
+        if (ListUtil.isEmpty(clinicalBloodDocs)) {
+            status.set("0");
+            return;
+        }
+        if (clinicalBloodDocs != null && clinicalBloodDocs.size() > 0) {
+            for (ClinicalBloodDoc cliB : clinicalBloodDocs) {
+                Map<String, String> cliBStructureMap = cliB.getStructureMap();
+                if (cliBStructureMap.containsKey("病历内容")) {
+                    String bloodType = cliBStructureMap.get("病历内容");
+                    if (StringUtil.isNotBlank(bloodType)) {
+                        if (bloodType.contains("Rh") || bloodType.contains("RH")
+                                || bloodType.contains("白蛋白")) {
+                            status.set("0");
+                            return;
+                        }
+                    }
+                }
+            }
+        }
+    }
+}

+ 2 - 5
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ningbozhongyi/firstpagerecord/FIRP0178.java

@@ -60,10 +60,6 @@ public class FIRP0178 extends QCCatalogue {
             //出院小结得出院诊断,模型提取出现问题,需要手动以1.2.3.为界限切开
             Map<String, String> leavehospitalStructureMap = inputInfo.getLeaveHospitalDoc().getStructureMap();
             String leaveDiag = leavehospitalStructureMap.get("出院诊断");
-            if(leavehospitalStructureMap.containsKey("出院诊断规则") && StringUtil.isNotBlank(leavehospitalStructureMap.get("出院诊断规则"))){
-                 leaveDiag = leavehospitalStructureMap.get("出院诊断规则");
-                leavehospitalStructureMap.remove("出院诊断规则");
-            }
 
             List<String> leaveDiagsStr = cut(leaveDiag, mainDiagnosis);
 
@@ -143,8 +139,9 @@ public class FIRP0178 extends QCCatalogue {
     private List<String> cut(String leaveDiag, String mainDiagnosis) {
         List<String> diags = new ArrayList<>();
         if (leaveDiag != null) {
+            leaveDiag.replace("西医诊断:","西医诊断:");
             if(leaveDiag.contains("西医诊断:")){
-                leaveDiag = leaveDiag.substring(leaveDiag.indexOf("西医诊断:"));
+                leaveDiag = leaveDiag.substring(leaveDiag.indexOf("西医诊断:")+"西医诊断:".length());
             }
             String[] leaveDiags = leaveDiag.split(",?,?[0-9]\\.");
             for (String string : leaveDiags) {

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

@@ -0,0 +1,149 @@
+package com.lantone.qc.kernel.catalogue.hospital.ningbozhongyi.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.isBlank(startTime)){
+                    startTime = operationRecordDoc.getStructureMap().get("手术日期").replace(" 时","时");
+                }
+            }
+            if (StringUtil.isNotBlank(startTime) && StringUtil.isNotBlank(admisTime) &&
+                    StringUtil.parseDateTime(startTime) != null) {
+                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("0");
+//            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.isBlank(operationStartDateStr)){
+                operationStartDateStr = operationRecordDoc.getStructureMap().get("手术日期").replace(" 时","时");
+            }
+            if (StringUtil.isNotBlank(operationStartDateStr) && StringUtil.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();
+    }
+
+}

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

@@ -0,0 +1,110 @@
+package com.lantone.qc.kernel.catalogue.hospital.ningbozhongyi.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.*;
+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) {
+                    status.set("-1");
+                   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("病理报告") || title.contains("病理记录") || title.contains("化验记录")) {
+                continue;
+            }
+            conditionRecord = StringUtil.isBlank(conditionRecord) ? "" : conditionRecord;
+            conditionRecord = conditionRecord.replace(" ", "");
+            treatmentPlan = StringUtil.isBlank(treatmentPlan) ? "" : treatmentPlan;
+            //主任或主治查房 标题需要包含“主任”或“主治”,内容需要包含“出院”
+            if ((conditionRecord.contains("出院") || conditionRecord.contains("转上级医院") || treatmentPlan.contains("出院"))
+                    && (CatalogueUtil.subTitle(title).contains(Content.attend)
+                    || CatalogueUtil.subTitle(title).contains(Content.director)
+                    || CatalogueUtil.subTitle(title).contains("主刀"))) {
+                status.set("0");
+                return;
+            }
+            //普通查房 内容需要包含“上级”和“出院”
+            if (StringUtil.isNotBlank(title)
+                    || (title.contains("日常查房记录") || 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;
+            }
+        }
+    }
+}

+ 16 - 7
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ningbozhongyi/threelevelward/THR02900.java

@@ -51,22 +51,28 @@ public class THR02900 extends QCCatalogue {
                 continue;
             }
             Map<String, String> structureMap = operationRecordDoc.getStructureMap();
-            String opeAssName = structureMap.get("手术人员");
+            String opeAssName = structureMap.get("手术名称");
+            firstAssistant = structureMap.get("一助");
+            if(StringUtil.isBlank(firstAssistant)){
+                firstAssistant = 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)
                 String key = getKeyByHospitalId();
                 opeEndTime = structureMap.get(key);
                 opeEndTime = getTime(opeEndTime, structureMap);
             }
             String chiefSurgeon = structureMap.get("主刀医师");
+            if(StringUtil.isBlank(chiefSurgeon)){
+                chiefSurgeon = structureMap.get("手术者");
+            }
             if (opeEndTime.contains("年月日")) {
                 continue;
             }
+            opeEndTime = opeEndTime.replace(" 时","时");
             Date opeEndDate = CatalogueUtil.parseStringDate(opeEndTime);
             if (opeEndDate == null) {
                 continue;
@@ -74,14 +80,17 @@ public class THR02900 extends QCCatalogue {
             if (!CatalogueUtil.compareTime(
                     StringUtil.parseDateTime(opeEndTime),
                     StringUtil.parseDateTime(DateUtil.nowString()),
-                    Long.valueOf(24 * 60))) {//如果接收未超过6小时,规则不判断
+                    Long.valueOf(24 * 60))) {//如果接收未超过24小时,规则不判断
                 return;
-            } else {
+            }else {
                 if ((StringUtil.isNotEmpty(chiefSurgeon) || StringUtil.isNotEmpty(firstAssistant)) && ListUtil.isEmpty(allDoctorWradDocs)) {
                     status.set("-1");
                     return;
                 }
             }
+            // if (StringUtil.isNotBlank(chiefSurgeon) || StringUtil.isNotBlank(firstAssistant) && allDoctorWradDocs.size()==0){
+            //                    return;
+            //                }
             if (ListUtil.isNotEmpty(allDoctorWradDocs)) {
                 for (ThreeLevelWardDoc wardDoc : allDoctorWradDocs) {
                     Map<String, String> wardStructureMap = wardDoc.getStructureMap();
@@ -93,7 +102,7 @@ public class THR02900 extends QCCatalogue {
                     if (StringUtil.isBlank(recordTitle) || StringUtil.isBlank(pathography) || recordDate == null) {
                         continue;
                     }
-                    if (opeEndDate.before(recordDate) && !CatalogueUtil.compareTime(opeEndDate, recordDate, 24 * 60L)) {
+                    if (recordDate.before(opeEndDate) && !CatalogueUtil.compareTime(opeEndDate, recordDate, 24 * 60L)) {
                         allTitle += recordTitle;
                         allPathography += pathography;
                         if (StringUtil.isNotBlank(writTitle)) {
@@ -116,7 +125,7 @@ public class THR02900 extends QCCatalogue {
                     StringUtil.isNotBlank(firstAssistant) && !allTitle.contains(firstAssistant)) {
                 status.set("-1");
                 return;
-            } else if (StringUtil.isBlank(chiefSurgeon) && StringUtil.isBlank(firstAssistant) && split != null && split.length > 1) {
+            } else if (StringUtil.isBlank(chiefSurgeon) && StringUtil.isBlank(firstAssistant) && split != null && split.length > 1 && StringUtil.isNotBlank(opeAssName)) {
                 for (int i = 0; i < split.length; i++) {
                     if (allTitle.contains(split[i])) {
                         return;

+ 4 - 4
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/behospitalized/BEH02966.java

@@ -27,9 +27,9 @@ public class BEH02966 extends QCCatalogue {
         }
 
         //宁还妇幼新生儿不判断此规则
-        if(inputInfo.getFirstPageRecordDoc() != null){
+        if (inputInfo.getFirstPageRecordDoc() != null) {
             Map<String, String> firstPageRecordStructureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
-            if(StringUtil.isNotBlank(firstPageRecordStructureMap.get("新生儿出生天数"))){
+            if (StringUtil.isNotBlank(firstPageRecordStructureMap.get("新生儿出生天数"))) {
                 return;
             }
         }
@@ -43,11 +43,11 @@ public class BEH02966 extends QCCatalogue {
         if (gender.contains("男")) {
             /* 男性不合理词 */
             noMatchWords = Lists.newArrayList("阴道", "宫颈", "子宫", "宫底", "胎位", "胎数", "胎心",
-                    "宫缩", "宫口", "输卵管", "卵巢", "输卵管", "阴唇", "阴蒂", "阴道前庭", "前庭大腺", "处女膜");
+                    "宫缩", "宫口", "输卵管", "卵巢", "输卵管", "阴唇", "阴蒂", "阴道前庭", "前庭大腺", "处女膜", "女");
         } else if (gender.contains("女")) {
             /* 女性不合理词 */
             noMatchWords = Lists.newArrayList("睾丸", "阴茎", "精索", "包皮", "附睾", "输精管",
-                    "射精管", "尿道海绵体", "冠状沟", "精阜", "精囊腺");
+                    "射精管", "尿道海绵体", "冠状沟", "精阜", "精囊腺", "男");
         }
         if (noMatchWords == null || noMatchWords.size() == 0) {
             return;

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

@@ -0,0 +1,43 @@
+package com.lantone.qc.kernel.catalogue.hospital.ninghaifuyou.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.PastLabel;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Description: 既往史未填写
+ * @author: rengb
+ * @time: 2020/3/10 14:02
+ */
+@Component
+public class BEH0400 extends QCCatalogue {
+
+    @Override
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        List<String> Str =  Arrays.asList("咳嗽气喘史","胸闷心悸史","腹痛腹泻史","多饮多尿史","浮肿少尿史","尿频尿痛史","抽搐史","出血史","过敏史","药物过敏史","传染病史","外伤手术史","输血史","重大疾病史和治疗史");
+        Map<String, String> structureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+        for(String s : Str){
+            if(structureMap!=null &&structureMap.containsKey(s)){
+                status.set("0");
+                return;
+            }
+        }
+
+        PastLabel pastLabel = inputInfo.getBeHospitalizedDoc().getPastLabel();
+        if (pastLabel != null && StringUtil.isNotBlank(pastLabel.getText())) {
+            status.set("0");
+        }
+    }
+
+}

+ 5 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/firstpagerecord/FIRP0163.java

@@ -25,6 +25,11 @@ public class FIRP0163 extends QCCatalogue {
         }
         if (inputInfo.getFirstPageRecordDoc().getStructureMap() != null) {
             Map<String, String> firstpageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+            String nationality = firstpageStructureMap.get(Content.nationality);
+            if (StringUtil.isNotBlank(nationality) && !"中国".equals(nationality)) {
+                status.set("0");
+                return;
+            }
             String idNumber = firstpageStructureMap.get(Content.idNumber);
             String dept = firstpageStructureMap.get("入院科别");
             if (StringUtil.isNotBlank(dept) && "NICU".equals(dept)) {

+ 66 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/operationdiscussion/OPE0326.java

@@ -0,0 +1,66 @@
+package com.lantone.qc.kernel.catalogue.hospital.ninghaifuyou.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.operation.OperationDoc;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * @ClassName : OPE0326
+ * @Description : 无术后首程
+ * @Author : kwz
+ * @Date: 2020-05-30 17:07
+ */
+@Component
+public class OPE0326 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        //先判断有无手术记录
+        List<OperationDoc> operationDocs = inputInfo.getOperationDocs();
+        long count_oper = 0;
+        long count_discuss = 0;
+        if (operationDocs != null && operationDocs.size() > 0) {
+            //宁海妇幼引道助产手术记录(模板名852)不需要术后首程
+            long count = operationDocs.stream().filter(operationDoc -> {
+                boolean flag = false;
+                if (operationDoc.getOperationRecordDoc() != null
+                        && StringUtil.isNotBlank(operationDoc.getOperationRecordDoc().getStructureMap().get("mode_id"))
+                        && "852".equals(operationDoc.getOperationRecordDoc().getStructureMap().get("mode_id"))) {
+                    flag = true;
+                }
+                return flag;
+            }).count();
+            if (count > 0) {
+                return;
+            }
+
+            count_oper = operationDocs.stream().map(i -> i.getOperationRecordDoc()).filter(i -> i != null).count();
+
+            count_discuss = operationDocs.stream().map(i -> i.getOperationDiscussionDoc()).filter(i -> i != null).count();
+            if (count_oper > 0 && count_discuss == 0) {
+                status.set("-1");
+            }
+        }
+            /*List<OperationDoc> operationDocs = inputInfo.getOperationDocs();
+            if (operationDocs.size() == 0 || operationDocs == null) {
+                return;
+            }
+            for (OperationDoc operationDoc : operationDocs) {
+                OperationDiscussionDoc operationDiscussionDoc = operationDoc.getOperationDiscussionDoc();
+                if (operationDiscussionDoc == null) {
+                    continue;
+                }
+                Map<String, String> operationDiscussionStructureMap = operationDiscussionDoc.getStructureMap();
+                if (CatalogueUtil.isEmpty(operationDiscussionStructureMap.get("患方签名"))) {
+                    status.set("-1");
+                    return;
+                }
+            }*/
+
+
+    }
+}

+ 47 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/threelevelward/THR0123.java

@@ -0,0 +1,47 @@
+package com.lantone.qc.kernel.catalogue.hospital.ninghaifuyou.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 : THR0123
+ * @Description : 入院记录未在患者入院24小时内完成
+ * @Author : 胡敬
+ * @Date: 2020-03-19 13:51
+ */
+@Component
+public class THR0123 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getBeHospitalizedDoc() != null && inputInfo.getBeHospitalizedDoc().getStructureMap() != null) {
+            Map<String, String> beHospitalStructureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+            String admisDate = beHospitalStructureMap.get(Content.admisDate);
+            String recordTime = beHospitalStructureMap.get("记录日期");
+            if (CatalogueUtil.isEmpty(admisDate) || CatalogueUtil.isEmpty(recordTime)) {
+                return;
+            }
+            if(!CatalogueUtil.compareTime(
+                    StringUtil.parseDateTime(admisDate),
+                    StringUtil.parseDateTime(DateUtil.nowString()),
+                    Long.valueOf(24 * 60))){//如果入院还未过24小时规则不判断
+                return;
+            }
+
+            if (CatalogueUtil.compareTime(
+                    StringUtil.parseDateTime(admisDate),
+                    StringUtil.parseDateTime(recordTime),
+                    Long.valueOf(24 * 60))) {
+                status.set("-1");
+            }
+        }
+    }
+
+}

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

@@ -0,0 +1,203 @@
+package com.lantone.qc.kernel.catalogue.hospital.ninghaifuyou.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 < 2) {
+                        //每周无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("主刀") || 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.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/ninghaifuyou/threelevelward/THR0128.java

@@ -0,0 +1,229 @@
+package com.lantone.qc.kernel.catalogue.hospital.ninghaifuyou.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;
+    }
+}

+ 91 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/threelevelward/THR0140.java

@@ -0,0 +1,91 @@
+package com.lantone.qc.kernel.catalogue.hospital.ninghaifuyou.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.ThreeLevelWardDoc;
+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 : THR0140
+ * @Description : 查房记录无医师签名
+ * @Author : 胡敬
+ * @Date: 2020-03-19 19:20
+ */
+@Component
+public class THR0140 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");
+            return;
+        }
+
+        StringBuffer message = new StringBuffer();
+        //长兴:返回所有医师未签名的记录日期
+        int i = 0;
+        for (ThreeLevelWardDoc threeLevelWardDoc : allDoctorWradDocs) {
+            if (StringUtil.isBlank(threeLevelWardDoc.getStructureMap().get("记录医生"))) {
+                if (threeLevelWardDoc.getStructureMap() != null && threeLevelWardDoc.getStructureMap().get("查房日期") != null) {
+                    if (i > 1) {
+                        break;
+                    }
+                    if (message.toString().length() == 0) {
+                        message.append(threeLevelWardDoc.getStructureMap().get("查房日期"));
+                    } else {
+                        message.append(",").append(threeLevelWardDoc.getStructureMap().get("查房日期"));
+                    }
+                    i++;
+                }
+            }
+        }
+        info.set(message.append("...").toString());
+        //        if (inputInfo.getDifficultCaseDiscussDocs().size() > 0) {
+        //            processSign(inputInfo, "疑难患者");
+        //        }
+        //        if (inputInfo.getRescueDocs().size() > 0) {
+        //            processSign(inputInfo, "抢救患者");
+        //        }
+    }
+
+    private void processSign(InputInfo inputInfo, String message) {
+        List<ThreeLevelWardDoc> threeLevelWardDocs = inputInfo.getThreeLevelWardDocs();
+        for (ThreeLevelWardDoc threeLevelWardDoc : threeLevelWardDocs) {
+            Map<String, String> threeLevelWardDocStructureMap = threeLevelWardDoc.getStructureMap();
+            String title = threeLevelWardDocStructureMap.get("查房标题");
+            String recordDoctor = threeLevelWardDocStructureMap.get("记录医师");
+            if (CatalogueUtil.isEmpty(title)) {
+                continue;
+            }
+            if (CatalogueUtil.subTitle(title).contains(Content.director) && CatalogueUtil.isEmpty(recordDoctor)) {
+                status.set("-1");
+                if (StringUtil.isBlank(message)) {
+                    info.set(message);
+                } else {
+                    info.set(info.get() + "," + message);
+                }
+                break;
+            }
+        }
+    }
+}

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

@@ -0,0 +1,508 @@
+package com.lantone.qc.kernel.catalogue.hospital.ninghaifuyou.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.*;
+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.*;
+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",
+            "多西环素",
+            "夫西地酸",
+            "头孢丙烯",
+            "头孢他啶",
+            "头孢他啶阿维巴坦",
+            "头孢他美酯",
+            "头孢克洛",
+            "头孢克肟",
+            "头孢吡肟",
+            "头孢呋辛",
+            "头孢哌酮舒巴坦",
+            "头孢唑林",
+            "头孢噻肟",
+            "头孢地嗪",
+            "头孢地尼",
+            "头孢拉定",
+            "头孢曲松",
+            "头孢替安",
+            "头孢美唑",
+            "头孢西丁",
+            "奥硝唑",
+            "妥布霉素",
+            "妥布霉素地塞米松",
+            "左氧氟沙星",
+            "左氧氟沙星",
+            "庆大霉素",
+            "异帕米星",
+            "拉氧头孢",
+            "替加环素",
+            "替硝唑",
+            "替考拉宁",
+            "比阿培南",
+            "氟康唑",
+            "氟康唑",
+            "氟胞嘧啶",
+            "氨曲南",
+            "氨苄西林",
+            "泊沙康唑",
+            "特比萘芬",
+            "甲硝唑",
+            "甲硝唑",
+            "磷霉素",
+            "磷霉素氨丁三醇",
+            "米卡芬净",
+            "米诺环素",
+            "红霉素",
+            "美罗培南",
+            "苄星青霉素",
+            "莫西沙星",
+            "莫西沙星",
+            "达托霉素",
+            "阿奇霉素",
+            "阿奇霉素枸橼酸二氢钠",
+            "阿洛西林",
+            "阿米卡星",
+            "阿莫西林",
+            "阿莫西林克拉维酸",
+            "青霉素"
+    };
+}

+ 157 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/threelevelward/THR03014.java

@@ -0,0 +1,157 @@
+package com.lantone.qc.kernel.catalogue.hospital.ninghaifuyou.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.ThreeLevelWardDoc;
+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 : THR03014
+ * @Description : 每周无1次主任医师查房记录(Attending少于每周一次查房记录)
+ * @Author : 胡敬
+ * @Date: 2020-03-19 15:52
+ */
+@Component
+public class THR03014 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getLeaveHospitalDoc() != null) {
+            Map<String, String> leaveHospitalStructureMap = inputInfo.getLeaveHospitalDoc().getStructureMap();
+            String admisTime = leaveHospitalStructureMap.get(Content.admisTime);
+            String dischargeTime = leaveHospitalStructureMap.get(Content.dischargeTime);
+            //如果住院天数小于7天则不判断该条规则
+            if (!CatalogueUtil.isEmpty(admisTime) && !CatalogueUtil.isEmpty(dischargeTime)) {
+                if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(dischargeTime), (long) (7 * 24 * 60))) {
+                    return;
+                }
+            }
+        }
+
+        if (inputInfo.getBeHospitalizedDoc() != null && inputInfo.getThreeLevelWardDocs().size() > 0) {
+            Map<String, String> beHospitalStructureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+            String admisTime = beHospitalStructureMap.get("入院日期");
+            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<>();
+            //每7天的病历记录
+            while (i >= 1) {
+                roundRecordThisWeek = extractWardRecord(inputInfo, allDoctorWradDocs, beginDate, hoursPerWeek, lastRecordDate);
+                if (CatalogueUtil.isEmpty(roundRecordThisWeek)) {
+                    break;
+                }
+                lastWardDateRange = DateUtil.formatDate(beginDate) + "    ->    " + DateUtil.formatDate(DateUtil.addDate(beginDate, 6));
+                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 attendNum = CatalogueUtil.appearNumber(roundRecordEveryWeek.get(j).split(","), Content.director);
+                if (attendNum == 0) {
+                    //每7天无1次主治医师查房记录
+                    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.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 "";
+    }
+
+}

+ 157 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/threelevelward/THR03016.java

@@ -0,0 +1,157 @@
+package com.lantone.qc.kernel.catalogue.hospital.ninghaifuyou.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.ThreeLevelWardDoc;
+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 : THR03016
+ * @Description : 每3天无1次主治医师查房记录(Fellow查房记录每3天1次)
+ * @Author : 胡敬
+ * @Date: 2020-03-19 15:52
+ */
+@Component
+public class THR03016 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getLeaveHospitalDoc() != null) {
+            Map<String, String> leaveHospitalStructureMap = inputInfo.getLeaveHospitalDoc().getStructureMap();
+            String admisTime = leaveHospitalStructureMap.get(Content.admisTime);
+            String dischargeTime = leaveHospitalStructureMap.get(Content.dischargeTime);
+            //如果住院天数小于3天则不判断该条规则
+            if (!CatalogueUtil.isEmpty(admisTime) && !CatalogueUtil.isEmpty(dischargeTime)) {
+                if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(dischargeTime), (long) (3 * 24 * 60))) {
+                    return;
+                }
+            }
+        }
+
+        if (inputInfo.getBeHospitalizedDoc() != null && inputInfo.getThreeLevelWardDocs().size() > 0) {
+            Map<String, String> beHospitalStructureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+            String admisTime = beHospitalStructureMap.get("入院日期");
+            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 = 3 * 24 * 60;
+            String roundRecordThisWeek = "";
+            List<String> roundRecordEveryWeek = new ArrayList<>();
+            beginDate = DateUtil.dateZeroClear(DateUtil.addDate(beginDate, 1));//从入院时间第二天0点开始算
+            int i = 1;
+            String lastWardDateRange = "";
+            List<String> lastWardDateRangeList = new ArrayList<>();
+            //每3天的病历记录
+            while (i >= 1) {
+                roundRecordThisWeek = extractWardRecord(inputInfo, allDoctorWradDocs, beginDate, hoursPerWeek, lastRecordDate);
+                if (CatalogueUtil.isEmpty(roundRecordThisWeek)) {
+                    break;
+                }
+                lastWardDateRange = DateUtil.formatDate(beginDate) + "    ->    " + DateUtil.formatDate(DateUtil.addDate(beginDate, 2));
+                lastWardDateRangeList.add(lastWardDateRange);
+                roundRecordEveryWeek.add(roundRecordThisWeek);
+                beginDate = DateUtil.addDate(beginDate, 3);
+                i++;
+            }
+            if (roundRecordEveryWeek.size() == 0) {
+                status.set("0");
+                return;
+            }
+            List<String> resultInfos = new ArrayList<>();
+            for (int j = 0; j < roundRecordEveryWeek.size(); j++) {
+                int attendNum = CatalogueUtil.appearNumber(roundRecordEveryWeek.get(j).split(","), Content.attend);
+                if (attendNum == 0) {
+                    //每3天无1次主治医师查房记录
+                    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分钟内所有查房标题
+     * 抽取一周内所有查房标题,若一周内记录少于2天,则返回""
+     *
+     * @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(2 * 24 * 60))) {
+                return recordTitle;
+            }
+        }
+        return "";
+    }
+
+}

+ 57 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/threelevelward/THR03020.java

@@ -0,0 +1,57 @@
+package com.lantone.qc.kernel.catalogue.hospital.ninghaifuyou.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.ThreeLevelWardDoc;
+import com.lantone.qc.pub.model.doc.ward.DirectorDoctorWardDoc;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : THR03020
+ * @Description : 入院72小时内无Attending查房记录(要有Attending标示) 首次查房时间最早,如果不在72小时之内,那么所有查房肯定都不在
+ * @Author : 胡敬
+ * @Date: 2020-03-19 13:51
+ */
+@Component
+public class THR03020 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getThreeLevelWardDocs().size() == 0) {
+            status.set("0");
+            return;
+        }
+        if (inputInfo.getLeaveHospitalDoc() != null && inputInfo.getLeaveHospitalDoc().getStructureMap() != null) {
+            Map<String, String> leaveHospitalStructureMap = inputInfo.getLeaveHospitalDoc().getStructureMap();
+            String admisTime = leaveHospitalStructureMap.get(Content.admisTime);
+            String dischargeTime = leaveHospitalStructureMap.get(Content.dischargeTime);
+            if (CatalogueUtil.isEmpty(admisTime) || CatalogueUtil.isEmpty(dischargeTime)) {
+                status.set("0");
+                return;
+            }
+            //如果住院天数小于3天则不判断该条规则
+            if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(dischargeTime), (long) (72 * 60))) {
+                status.set("0");
+                return;
+            }
+            ThreeLevelWardDoc threeLevelWardDoc = inputInfo.getThreeLevelWardDocs().get(0);
+            List<DirectorDoctorWardDoc> directorDoctorWardDocs = threeLevelWardDoc.getDirectorDoctorWardDocs();
+            if (directorDoctorWardDocs.size() > 0) {
+                DirectorDoctorWardDoc firstDirectorg = directorDoctorWardDocs.get(0);
+                String wardDateStr = firstDirectorg.getStructureMap().get("查房日期");
+                if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(wardDateStr), 72 * 60L)) {
+                    status.set("0");
+                }
+            }
+        } else {
+            //没有出院小结,这条直接不报错
+            status.set("0");
+        }
+    }
+
+}

+ 67 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/threelevelward/THR03021.java

@@ -0,0 +1,67 @@
+package com.lantone.qc.kernel.catalogue.hospital.ninghaifuyou.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.ThreeLevelWardDoc;
+import com.lantone.qc.pub.model.doc.ward.AttendingDoctorWardDoc;
+import com.lantone.qc.pub.model.doc.ward.DirectorDoctorWardDoc;
+import com.lantone.qc.pub.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : THR03021
+ * @Description : 入院48小时内无Fellow以上的医生查房记录
+ * @Author : 胡敬
+ * @Date: 2020-03-19 15:50
+ */
+@Component
+public class THR03021 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getThreeLevelWardDocs().size() == 0) {
+            status.set("0");
+            return;
+        }
+        if (inputInfo.getLeaveHospitalDoc() != null && inputInfo.getLeaveHospitalDoc().getStructureMap() != null
+                && inputInfo.getThreeLevelWardDocs().size() > 0) {
+            Map<String, String> getLeaveHospitalStructureMap = inputInfo.getLeaveHospitalDoc().getStructureMap();
+            String admisTime = getLeaveHospitalStructureMap.get(Content.admisTime);
+            String dischargeTime = getLeaveHospitalStructureMap.get(Content.dischargeTime);
+            if (CatalogueUtil.isEmpty(admisTime) || CatalogueUtil.isEmpty(dischargeTime)) {
+                status.set("0");
+                return;
+            }
+            //如果住院天数小于2天则不判断该条规则
+            if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(dischargeTime), (long) (48 * 60))) {
+                status.set("0");
+                return;
+            }
+            ThreeLevelWardDoc threeLevelWardDoc = inputInfo.getThreeLevelWardDocs().get(0);
+            List<AttendingDoctorWardDoc> attendingDoctorWardDocs = threeLevelWardDoc.getAttendingDoctorWardDocs();
+            List<DirectorDoctorWardDoc> directorDoctorWardDocs = threeLevelWardDoc.getDirectorDoctorWardDocs();
+            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");
+                }
+            }
+            if (directorDoctorWardDocs.size() > 0) {
+                DirectorDoctorWardDoc firstDirector = directorDoctorWardDocs.get(0);
+                String wardDateStr = firstDirector.getStructureMap().get("查房日期");
+                if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime), StringUtil.parseDateTime(wardDateStr), 48 * 60L)) {
+                    status.set("0");
+                }
+            }
+        } else {
+            //没有出院小结,这条直接不报错
+            status.set("0");
+        }
+    }
+
+}

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

@@ -0,0 +1,342 @@
+package com.lantone.qc.kernel.catalogue.hospital.ninghaifuyou.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",
+            "关节腔注射", "宫颈注射", "皮下注射", "皮下注射(儿童)", "皮下注射(免费)", "皮下注射(成人)", "皮内", "皮内注射",
+            "结膜下注射", "肌注", "肌肉注射(儿童)", "肌肉注射(公卫专用)", "肌肉注射(成人)", "胸腔注射", "腹腔内注射", "腹腔注射",
+            "静滴(儿童)", "静滴(成人)", "静脉注射", "静脉注射(儿童)", "静脉注射(免费)", "静脉注射(成人)", "静脉注射(泵)",
+            "静脉滴注", "静脉滴注(泵)", "鞘内注射", "微泵");
+
+}

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

@@ -0,0 +1,598 @@
+package com.lantone.qc.kernel.catalogue.hospital.ninghaifuyou.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.*;
+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",
+            "关节腔注射", "宫颈注射", "皮下注射", "皮下注射(儿童)", "皮下注射(免费)", "皮下注射(成人)", "皮内", "皮内注射",
+            "结膜下注射", "肌注", "肌肉注射(儿童)", "肌肉注射(公卫专用)", "肌肉注射(成人)", "胸腔注射", "腹腔内注射", "腹腔注射",
+            "静滴(儿童)", "静滴(成人)", "静脉注射", "静脉注射(儿童)", "静脉注射(免费)", "静脉注射(成人)", "静脉注射(泵)",
+            "静脉滴注", "静脉滴注(泵)", "鞘内注射", "微泵");
+
+}

+ 8 - 1
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaifuyou/threelevelward/THR03090.java

@@ -6,8 +6,8 @@ import com.lantone.qc.pub.model.OutputInfo;
 import com.lantone.qc.pub.model.doc.DoctorAdviceDoc;
 import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
 import com.lantone.qc.pub.model.doc.operation.OperationDoc;
-import com.lantone.qc.pub.util.DateUtil;
 import com.lantone.qc.pub.util.StringUtil;
+import com.lantone.qc.trans.comsis.CommonAnalysisUtil;
 import org.springframework.stereotype.Component;
 
 import java.util.List;
@@ -41,6 +41,13 @@ public class THR03090 extends QCCatalogue {
         if (operationDocs.get(operationDocs.size() - 1).getOperationRecordDoc() != null) {
             Map<String, String> operationDocStructureMap = operationDocs.get(operationDocs.size() - 1).getOperationRecordDoc().getStructureMap();
             operationStartDate = operationDocStructureMap.get("手术开始时间");
+            if (StringUtil.isBlank(operationStartDate) && StringUtil.isNotBlank(operationDocStructureMap.get("胎儿娩出"))) {
+                operationStartDate = CommonAnalysisUtil.NHExtractDate(operationDocStructureMap.get("胎儿娩出").replace(".", "-"));
+            }
+        }
+        //手术时间为空,则不质控
+        if (StringUtil.isBlank(operationStartDate)) {
+            return;
         }
 
         List<ThreeLevelWardDoc> allDoctorWradDocs = threeLevelWardDocs.get(0).getAllDoctorWradDocs();

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaiyiyi/behospitalized/BEH0439.java

@@ -33,7 +33,7 @@ public class BEH0439 extends QCCatalogue {
             if (birthDate_bh != null && birthDate_fpr != null) {
                 if (!CatalogueUtil.isEmpty(birthDate_bh) && !CatalogueUtil.isEmpty(birthDate_fpr)) {
                     if(!DateUtils.isSameInstant(StringUtil.parseDateTime(birthDate_bh, dateFormats)
-                            ,StringUtil.parseDateTime(birthDate_fpr, dateFormats)))
+                            , StringUtil.parseDateTime(birthDate_fpr, dateFormats)))
                     {
                         status.set("-1");
                     }

+ 81 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaiyiyi/firstpagerecord/FIRP0250.java

@@ -0,0 +1,81 @@
+package com.lantone.qc.kernel.catalogue.hospital.ninghaiyiyi.firstpagerecord;
+
+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.RescueDoc;
+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 : FIRP0250
+ * @Description : 抢救成功次数填写错误
+ * @Author : 楼辉荣
+ * @Date: 2020-03-06 17:28ss
+ */
+@Component
+public class FIRP0250 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getRescueDocs().size() > 0) {
+            List<RescueDoc> rescueDocs = inputInfo.getRescueDocs();
+            int rescueNum = getRescueNum(rescueDocs);/* 抢救记录中抢救成功次数 */
+            boolean match = false;
+
+            Map<String, String> firstpageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+            String successfulRescueTimes = firstpageStructureMap.get("病人抢救成功次数");
+            int successfulRescueTimesTZ = 0;
+            if (StringUtil.isNotBlank(successfulRescueTimes) && CatalogueUtil.numbersOnly(successfulRescueTimes)) {
+                successfulRescueTimesTZ = Integer.parseInt(successfulRescueTimes);
+            }
+            if (rescueNum == successfulRescueTimesTZ) {
+                match = true;
+            }
+            String saveNum = firstpageStructureMap.get("病人抢救次数");
+            if (successfulRescueTimes == saveNum) {
+                match = true;
+            }
+            String name = firstpageStructureMap.get(Content.rescue_condition);
+            if (StringUtil.isNotBlank(name)) {
+                String[] split = name.split("\\s+");
+                Pattern compile = Pattern.compile("(?<=成功).*(?=次)");
+                Matcher matcher = compile.matcher(split[0]);
+                while (matcher.find()) {
+                    try {
+                        String number = matcher.group(0);
+                        int num = Integer.parseInt(number);
+                        if (num == rescueNum) {
+                            match = true;
+                        }
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+
+            if (!match) {
+                status.set("-1");
+            }
+        }
+    }
+
+    private int getRescueNum(List<RescueDoc> rescueDocs) {
+        int i = 0;
+        for (RescueDoc re : rescueDocs) {
+            Map<String, String> structureMap = re.getStructureMap();
+            // 跟医学部确认,从抢救措施中读取数据
+            String qjgc = structureMap.get("抢救内容");
+            if (StringUtil.isNotBlank(qjgc) && !qjgc.contains("死亡")) {
+                i++;
+            }
+        }
+        return i;
+    }
+}

+ 3 - 5
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaiyiyi/threelevelward/THR0125.java

@@ -89,15 +89,13 @@ public class THR0125 extends QCCatalogue {
             }
 
             //===========三级医师相当于主治医生==========
-            List<ThreeLevelWardDoc>  allDoctorWradDocs =  threeLevelWardDoc.getAllDoctorWradDocs();
-            if(allDoctorWradDocs.size()>0)
-            {
+            List<ThreeLevelWardDoc> allDoctorWradDocs = threeLevelWardDoc.getAllDoctorWradDocs();
+            if (allDoctorWradDocs.size() > 0) {
 
                 for (ThreeLevelWardDoc threeLevelWard : allDoctorWradDocs) {
                     Map<String, String> structureMap = threeLevelWard.getStructureMap();
                     String makeTitle = structureMap.get("查房标题");
-                    if(StringUtil.isNotBlank(makeTitle)&&makeTitle.contains("三级"))
-                    {
+                    if (StringUtil.isNotBlank(makeTitle) && makeTitle.contains("三级")) {
                         String recordDateStr = structureMap.get("查房日期");
                         if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime),
                                 StringUtil.parseDateTime(recordDateStr), 72 * 60L)) {

+ 4 - 6
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaiyiyi/threelevelward/THR0126.java

@@ -107,15 +107,13 @@ public class THR0126 extends QCCatalogue {
                 return;
             }
             //===========三级医师相当于主治医生==========
-            List<ThreeLevelWardDoc>  allDoctorWradDocs =  threeLevelWardDoc.getAllDoctorWradDocs();
-            if(allDoctorWradDocs.size()>0)
-            {
+            List<ThreeLevelWardDoc> allDoctorWradDocs = threeLevelWardDoc.getAllDoctorWradDocs();
+            if (allDoctorWradDocs.size() > 0) {
 
                 for (ThreeLevelWardDoc threeLevelWard : allDoctorWradDocs) {
                     Map<String, String> structureMap = threeLevelWard.getStructureMap();
                     String makeTitle = structureMap.get("查房标题");
-                    if(StringUtil.isNotBlank(makeTitle)&&makeTitle.contains("三级"))
-                    {
+                    if (StringUtil.isNotBlank(makeTitle) && makeTitle.contains("三级")) {
                         String recordDateStr = structureMap.get("查房日期");
                         if (!CatalogueUtil.compareTime(StringUtil.parseDateTime(admisTime),
                                 StringUtil.parseDateTime(recordDateStr), 48 * 60L)) {
@@ -164,7 +162,7 @@ public class THR0126 extends QCCatalogue {
         }
     }
 
-//    /**
+    //    /**
 //     * 判断查房记录是否含有主治医师查房
 //     *
 //     * @param operatorName     主刀医师

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

@@ -0,0 +1,508 @@
+package com.lantone.qc.kernel.catalogue.hospital.ninghaiyiyi.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.*;
+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.*;
+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",
+            "多西环素",
+            "夫西地酸",
+            "头孢丙烯",
+            "头孢他啶",
+            "头孢他啶阿维巴坦",
+            "头孢他美酯",
+            "头孢克洛",
+            "头孢克肟",
+            "头孢吡肟",
+            "头孢呋辛",
+            "头孢哌酮舒巴坦",
+            "头孢唑林",
+            "头孢噻肟",
+            "头孢地嗪",
+            "头孢地尼",
+            "头孢拉定",
+            "头孢曲松",
+            "头孢替安",
+            "头孢美唑",
+            "头孢西丁",
+            "奥硝唑",
+            "妥布霉素",
+            "妥布霉素地塞米松",
+            "左氧氟沙星",
+            "左氧氟沙星",
+            "庆大霉素",
+            "异帕米星",
+            "拉氧头孢",
+            "替加环素",
+            "替硝唑",
+            "替考拉宁",
+            "比阿培南",
+            "氟康唑",
+            "氟康唑",
+            "氟胞嘧啶",
+            "氨曲南",
+            "氨苄西林",
+            "泊沙康唑",
+            "特比萘芬",
+            "甲硝唑",
+            "甲硝唑",
+            "磷霉素",
+            "磷霉素氨丁三醇",
+            "米卡芬净",
+            "米诺环素",
+            "红霉素",
+            "美罗培南",
+            "苄星青霉素",
+            "莫西沙星",
+            "莫西沙星",
+            "达托霉素",
+            "阿奇霉素",
+            "阿奇霉素枸橼酸二氢钠",
+            "阿洛西林",
+            "阿米卡星",
+            "阿莫西林",
+            "阿莫西林克拉维酸",
+            "青霉素"
+    };
+}

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/ninghaiyiyi/threelevelward/THR03090.java

@@ -45,7 +45,7 @@ public class THR03090 extends QCCatalogue {
                 if (operationStartDate.contains("结束")) {
                     operationStartDate = operationStartDate.substring(0, operationStartDate.indexOf("结束")).replace("开始:", "");
                 }
-                if (operationStartDate.contains("年月日")) {
+                if (StringUtil.parseDateTime(operationStartDate) == null) {
                     operationStartDate = DateUtil.nowString();
                 }
                 //取不到时间不判断规则

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/shengzhouyy/behospitalized/BEH02902.java

@@ -66,7 +66,7 @@ public class BEH02902 extends QCCatalogue {
         /* 如果模型没找到时间实体,则直接取辅助检查前20个字,判断有没有院字 */
         if (!findPlace) {
             String prefixText = pacsText.trim().substring(0, Math.min(35, pacsText.length()));
-            if (prefixText.contains("院") || prefixText.contains("当地") || prefixText.contains("嵊州") || prefixText.contains("科")) {
+            if (prefixText.contains("新昌") ||prefixText.contains("门诊") || prefixText.contains("院") || prefixText.contains("当地") || prefixText.contains("嵊州") || prefixText.contains("科")) {
                 findPlace = true;
             }
         }

+ 125 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/shengzhouyy/clinicalblood/CLI0301.java

@@ -0,0 +1,125 @@
+package com.lantone.qc.kernel.catalogue.hospital.shengzhouyy.clinicalblood;
+
+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.ClinicalBloodDoc;
+import com.lantone.qc.pub.model.doc.DoctorAdviceDoc;
+import com.lantone.qc.pub.model.doc.FirstPageRecordDoc;
+import com.lantone.qc.pub.model.doc.InformedConsentDoc;
+import com.lantone.qc.pub.model.doc.ThreeLevelWardDoc;
+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;
+
+/**
+ * @ClassName : CLI0301
+ * @Description : 无输血或使用血液制品知情同意书
+ * @Author : cy
+ * @Date: 2021-04-18 14:49
+ */
+@Component
+public class CLI0301 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        boolean flag=false;
+        List<ClinicalBloodDoc> clinicalBloodDocs = inputInfo.getClinicalBloodDocs();
+        List<DoctorAdviceDoc> doctorAdviceDocs = inputInfo.getDoctorAdviceDocs();
+        List<ThreeLevelWardDoc> threeLevelWardDocs = inputInfo.getThreeLevelWardDocs();
+        /**
+         *是否输血了
+         */
+        //输血记录
+        if(ListUtil.isNotEmpty(clinicalBloodDocs)){
+            flag=true;
+        }
+        //血费
+        FirstPageRecordDoc firstPageRecordDoc = inputInfo.getFirstPageRecordDoc();
+        if(firstPageRecordDoc!=null&&firstPageRecordDoc.getStructureMap()!=null){
+            String bloodFee = firstPageRecordDoc.getStructureMap().get("血费");
+            if(StringUtil.isNotEmpty(bloodFee) && !bloodFee.equals("0")){
+                double blood = Double.parseDouble(bloodFee);
+                if(blood > 0){
+                    flag=true;
+                }
+            }
+        }
+        //医嘱
+        if(ListUtil.isNotEmpty(doctorAdviceDocs)){
+            for (DoctorAdviceDoc doctorAdviceDoc : doctorAdviceDocs) {
+                Map<String, String> doctorAdviceDocStrMap = doctorAdviceDoc.getStructureMap();
+                String daStatus = doctorAdviceDocStrMap.get(Content.doctorAdviceState);
+                if (StringUtil.isNotEmpty(daStatus)) {
+                    if (!Content.cancellationOrderList.contains(daStatus)) {
+                        //取临时医嘱
+                        String doctorAsks = doctorAdviceDocStrMap.get(Content.doctorAdviceType);
+                        if (StringUtil.isEmpty(doctorAsks)) {
+                            continue;
+                        }
+                        if (Content.statOrder.equals(doctorAsks)) {
+                            String daItemName = doctorAdviceDocStrMap.get(Content.medicalOrderName);
+                                if(StringUtil.isNotEmpty(daItemName)) {
+                                    if (dateStr(daItemName)) {
+                                        flag = true;
+                                        break;
+                                    }
+                                }
+                        }
+                    }
+                }
+            }
+        }
+//判断是否含有知情同意书
+        if(flag) {
+            status.set("-1");
+            List<InformedConsentDoc> informedConsentDocList = inputInfo.getInformedConsentDoc();
+            if (ListUtil.isNotEmpty(informedConsentDocList)) {
+                for (InformedConsentDoc informedConsentDoc : informedConsentDocList) {
+                    String str = informedConsentDoc.getStructureMap().get("标题");
+                    if(StringUtil.isBlank(str)){
+                        continue;
+                    }
+                    String rex="[\\s\\S]*(?=输血)[^,;,;。]{0,10}(?=知情同意书)[\\s\\S]*";
+                    if( Content.BLOODRECORDLIST.stream().anyMatch(obj -> str.contains(obj))||str.matches(rex)){
+                        status.set("0");
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+    private boolean dateStr(String str){
+        if(StringUtil.isEmpty(str)){
+            return false;
+        }
+        str = str.replaceAll("\\*", "\\\\*");
+        str = str.replaceAll("\\)", "\\\\)");
+        str = str.replaceAll("\\.", "\\\\.");
+        str = str.replaceAll("\\?", "\\\\?");
+        str = str.replaceAll("\\+", "\\\\+");
+        str = str.replaceAll("\\$", "\\\\$");
+        str = str.replaceAll("\\^", "\\\\^");
+        str = str.replaceAll("\\[", "\\\\[");
+        str = str.replaceAll("\\]", "\\\\]");
+        str = str.replaceAll("\\(", "\\\\(");
+        str = str.replaceAll("\\{", "\\\\{");
+        str = str.replaceAll("\\}", "\\\\}");
+        str = str.replaceAll("\\|", "\\\\|");
+        str = str.replaceAll("\\/", "\\\\/");
+        String rex1="[\\s\\S]*(?=输)[^,;,;。]{0,6}(?=血)[\\s\\S]*";
+        String rex2="[\\s\\S]*(?=输)[^,;,;。]{0,6}(?=红细胞)[\\s\\S]*";
+        String rex3="[\\s\\S]*(?=输)[^,;,;。]{0,6}(?=血小板)[\\s\\S]*";
+        String rex4="[\\s\\S]*(?=输)[^,;,;。]{0,6}(?=血浆)[\\s\\S]*";
+        String rex5="[\\s\\S]*(?=输)[^,;,;。]{0,6}(?=冷沉淀因子)[\\s\\S]*";
+        String rex6="[\\s\\S]*(?=输血)[^,;,;。]{0,6}((?=前检测)|(?=前检查))[\\s\\S]*";
+        if( !str.matches(rex6) && ( str.matches(rex1)|| str.matches(rex2) || str.matches(rex3)|| str.matches(rex4)|| str.matches(rex5))){
+            return true;
+        }
+        return false;
+    }
+}

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

@@ -0,0 +1,54 @@
+package com.lantone.qc.kernel.catalogue.hospital.shengzhouyy.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();
+        long inCou = inputInfo.getInvasiveOperationDocs().stream().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("手术") && inCou > 0) {
+                return;
+            }
+            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");
+        }*/
+    }
+
+}

+ 68 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xszyy/firstpagerecord/FIRP0190.java

@@ -0,0 +1,68 @@
+package com.lantone.qc.kernel.catalogue.hospital.xszyy.firstpagerecord;
+
+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.ClinicalBloodDoc;
+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 : FIRP0190
+ * @Description :Rh填写错误
+ * @Author : 胡敬
+ * @Date: 2020-03-18 13:35
+ */
+@Component
+public class FIRP0190 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        if (inputInfo.getFirstPageRecordDoc() == null || inputInfo.getFirstPageRecordDoc().getStructureMap() == null
+                || inputInfo.getClinicalBloodDocs().size() == 0) {
+            return;
+        }
+        Map<String, String> firstpageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+        List<ClinicalBloodDoc> clinicalBloodDocList = inputInfo.getClinicalBloodDocs();
+        String rhFactor = firstpageStructureMap.get(Content.rhFactor);
+        if (CatalogueUtil.isEmpty(rhFactor)) {
+            return;
+        }
+        int matchSum = 0, noRhSum = 0;
+        for (ClinicalBloodDoc clinicalBloodDoc : clinicalBloodDocList) {
+            String bloodType = clinicalBloodDoc.getText();
+            if (StringUtil.isBlank(bloodType)) {
+                // 台州无“输注种类、血型、数量”,匹配“Rh血型”
+                bloodType = clinicalBloodDoc.getStructureMap().get("Rh血型");
+            }
+            if (StringUtils.isEmpty(bloodType)) {
+                continue;
+            }
+            if (!bloodType.contains("阴") && !bloodType.contains("阳")) {
+                noRhSum++;
+            }
+            if (bloodType.contains("白蛋白") || bloodType.contains("凝血酶原复合物")) {
+                continue;
+            }
+            bloodType = bloodType.toUpperCase();
+            String rh = Content.rhFactor.toUpperCase();
+            if (bloodType.contains(rh) ||
+                    bloodType.contains(CatalogueUtil.removeSpecialChar(rhFactor))) {
+                matchSum++;
+                return;
+            }
+        }
+        /* 如果所有输血记录都没有rh记录(阴、阳),则不报错 */
+        if (noRhSum == clinicalBloodDocList.size()) {
+            return;
+        }
+        if (matchSum == 0) {
+            status.set("-1");
+        }
+    }
+}

+ 45 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xszyy/firstpagerecord/FIRP0220.java

@@ -0,0 +1,45 @@
+package com.lantone.qc.kernel.catalogue.hospital.xszyy.firstpagerecord;
+
+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.util.StringUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * @ClassName : FIRP0220
+ * @Description : 入院时间与入院记录时间不一致
+ * @Author : 胡敬
+ * @Date: 2020-03-14 17:10
+ */
+@Component
+public class FIRP0220 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        if (inputInfo.getFirstPageRecordDoc() == null || inputInfo.getBeHospitalizedDoc() == null) {
+            status.set("0");
+            return;
+        }
+        Map<String, String> firstpageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureMap();
+        Map<String, String> beHospitalStructureMap = inputInfo.getBeHospitalizedDoc().getStructureMap();
+        String firstAdmissionDate = firstpageStructureMap.get(Content.admisTime);
+        String admissionDate = beHospitalStructureMap.get(Content.admisDate);
+        if (StringUtil.isEmpty(firstAdmissionDate) || StringUtil.isEmpty(admissionDate)) {
+            status.set("0");
+            return;
+        }
+        String[] dateFormats = new String[]{"yyyy年MM月dd日HH时mm分ss", "yyyy年MM月dd日HH时mm分","yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm"};
+        Date firstDate = StringUtil.parseDateTime(firstAdmissionDate);
+        Date admisDate = StringUtil.parseDateTime(admissionDate, dateFormats);
+        if (firstDate != null && admisDate != null) {
+            if (firstDate.getYear() == admisDate.getYear() &&
+                    firstDate.getMonth() == admisDate.getMonth() &&
+                    firstDate.getDay() == admisDate.getDay()) {
+                status.set("0");
+            }
+        }
+    }
+}

+ 74 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xszyy/operationdiscussion/OPE03142.java

@@ -0,0 +1,74 @@
+package com.lantone.qc.kernel.catalogue.hospital.xszyy.operationdiscussion;
+
+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.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.List;
+import java.util.Map;
+
+/**
+ * @Description: 手术记录出血情况未填写
+ * @author: kwz
+ * @time: 2020/06/29 11:22
+ */
+@Component
+public class OPE03142 extends QCCatalogue {
+    /**
+     * 1.手术记录中包含文本形式【失血/出血】
+     * 或2.标题形式包含【失血/出血】判断是否为空
+     *
+     * @param inputInfo
+     * @param outputInfo
+     */
+
+    @Override
+    protected void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        int operationNum = 0;
+        int bleedingNum = 0;
+        //先判断有无手术记录
+        List<OperationDoc> operationDocs = inputInfo.getOperationDocs();
+        if (operationDocs != null && operationDocs.size() > 0) {
+            ss:
+            for (OperationDoc operationDoc : operationDocs) {
+                if (operationDoc == null) {
+                    continue;
+                }
+                OperationRecordDoc operationRecordDoc = operationDoc.getOperationRecordDoc();
+                if (operationRecordDoc != null) {
+                    operationNum++;
+                    Map<String, String> structureMap = operationRecordDoc.getStructureMap();
+                    if (structureMap == null) {
+                        continue;
+                    }
+                    String lossOfBlood = structureMap.get("失血");
+                    String bleeding = structureMap.get("出血");
+                    if (StringUtil.isNotBlank(lossOfBlood) || StringUtil.isNotBlank(bleeding)) {
+                        bleedingNum++;
+                        break ss;
+                    }
+                    String afterOperation = structureMap.get("手术经过及处理");
+                    List<String> bleedingRecordList = Content.bleedingRecordList;
+                    if (StringUtil.isNotBlank(afterOperation)) {
+                        for (String bleedingRecord : bleedingRecordList) {
+                            if (afterOperation.contains(bleedingRecord)) {
+                                bleedingNum++;
+                                break ss;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if (operationNum != bleedingNum) {
+            status.set("-1");
+            return;
+        }
+    }
+}

+ 64 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xszyy/operationdiscussion/OPE03143.java

@@ -0,0 +1,64 @@
+package com.lantone.qc.kernel.catalogue.hospital.xszyy.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.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.List;
+import java.util.Map;
+
+/**
+ * @Description: 手术记录输血情况未填写
+ * @author: kwz
+ * @time: 2020/06/29 11:22
+ */
+@Component
+public class OPE03143 extends QCCatalogue {
+    /**
+     * 标题形式包含【输血】判断是否为空
+     *
+     * @param inputInfo
+     * @param outputInfo
+     */
+    @Override
+    protected void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        boolean flag = true;
+        //先判断有无手术记录
+        List<OperationDoc> operationDocs = inputInfo.getOperationDocs();
+        if (operationDocs != null && operationDocs.size() > 0) {
+            for (OperationDoc operationDoc : operationDocs) {
+                if (operationDoc == null) {
+                    continue;
+                }
+                OperationRecordDoc operationRecordDoc = operationDoc.getOperationRecordDoc();
+                if (operationRecordDoc != null) {
+                    Map<String, String> structureMap = operationRecordDoc.getStructureMap();
+                    if (structureMap == null) {
+                        continue;
+                    }
+                    String bloodTransfusion = structureMap.get("输血情况");
+                    if (StringUtil.isNotBlank(bloodTransfusion)) {
+                        flag = false;
+                    }
+
+                    String afterOperation = structureMap.get("手术经过及处理");
+                    if (StringUtil.isNotBlank(afterOperation)) {
+                        if (afterOperation.contains("输血")) {
+                            flag = false;
+                        }
+                    }
+                }
+            }
+        }
+
+        if (flag) {
+            status.set("-1");
+            return;
+        }
+    }
+}

+ 36 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/hospital/xszyy/threelevelward/THR0685.java

@@ -0,0 +1,36 @@
+package com.lantone.qc.kernel.catalogue.hospital.xszyy.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.RescueDoc;
+import com.lantone.qc.pub.util.ListUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @ClassName : THR0685
+ * @Description : 抢救记录未记录参加抢救医务人员姓名及职称
+ * @Author : 胡敬
+ * @Date: 2020-03-30 13:15
+ */
+@Component
+public class THR0685 extends QCCatalogue {
+    public void start(InputInfo inputInfo, OutputInfo outputInfo) {
+        status.set("0");
+        List<RescueDoc> rescueDocs = inputInfo.getRescueDocs();
+        if (ListUtil.isEmpty(rescueDocs)) {
+            return;
+        }
+        for (RescueDoc rescueDoc : rescueDocs) {
+            Map<String, String> rescueStructureMap = rescueDoc.getStructureMap();
+            if (CatalogueUtil.isEmpty(rescueStructureMap.get("参加抢救的医务人员姓名及专业技术职称"))) {
+                status.set("-1");
+                return;
+            }
+        }
+    }
+}

+ 2 - 2
kernel/src/main/java/com/lantone/qc/kernel/catalogue/leavehospital/LEA02968.java

@@ -36,11 +36,11 @@ public class LEA02968 extends QCCatalogue {
         if (gender.contains("男")) {
             /* 男性不合理词 */
             noMatchWords = Lists.newArrayList("阴道", "宫颈", "子宫", "宫底", "胎位", "胎数", "胎心",
-                    "宫缩", "宫口", "输卵管", "卵巢", "输卵管", "阴唇", "阴蒂", "阴道前庭", "前庭大腺", "处女膜");
+                    "宫缩", "宫口", "输卵管", "卵巢", "输卵管", "阴唇", "阴蒂", "阴道前庭", "前庭大腺", "处女膜", "女");
         } else if (gender.contains("女")) {
             /* 女性不合理词 */
             noMatchWords = Lists.newArrayList("睾丸", "阴茎", "精索", "包皮", "附睾", "输精管",
-                    "射精管", "尿道海绵体", "冠状沟", "精阜", "精囊腺");
+                    "射精管", "尿道海绵体", "冠状沟", "精阜", "精囊腺", "男");
         }
 
         if (noMatchWords == null || noMatchWords.size() == 0) {

+ 0 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/operationdiscussion/OPE03143.java


Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików