Browse Source

Merge remote-tracking branch 'origin/beilun/dev' into beilun/dev

zhangzw 4 years ago
parent
commit
25a53d717f

+ 424 - 0
dbanaly/src/main/java/com/lantone/qc/dbanaly/facade/yiwu/YiWuFirstPageRecordXmlUtil.java

@@ -0,0 +1,424 @@
+package com.lantone.qc.dbanaly.facade.yiwu;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.collect.ImmutableMap;
+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.MapUtil;
+import com.lantone.qc.pub.util.StringUtil;
+import org.dom4j.Document;
+import org.dom4j.DocumentHelper;
+import org.dom4j.Element;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @Description: xml解析工具
+ * @author: rengb
+ * @time: 2020/3/28 14:23
+ */
+public class YiWuFirstPageRecordXmlUtil {
+    public static Map<String, String> leaveDiagMap = ImmutableMap.<String, String>builder()
+            .put("出院诊断", "诊断名称")
+            .put("出院诊断编码", "诊断编码")
+            .put("出院诊断_入院病情", "入院情况")
+            .put("诊断类型", "出院情况")
+            .build();
+
+    public static Map<String, String> operationMap = ImmutableMap.<String, String>builder()
+            .put("手术名称", "手术名称")
+            .put("手术开始日期", "手术日期")
+            .put("手术切口愈合等级", "愈合等级")
+            .put("手术及操作编码", "手术编码")
+            .put("手术级别", "手术级别")
+            .put("手术切口等级", "切口等级")
+            .put("主刀医师", "手术医生ID")
+            .put("Ⅰ助姓名", "一助医生ID")
+            .put("Ⅱ助姓名", "二助医生ID")
+            .put("麻醉方式", "麻醉方式")
+            .put("麻醉医师签名", "麻醉医师")
+            .build();
+
+    public static Map<String, Object> process(String xml) {
+        Map<String, String> sourceMap = xmlToMap(xml);
+        Map<String, String> structureMap = mapKeyContrast(sourceMap, keyContrasts);
+        Map<String, Object> structureExtMap = Maps.newHashMap();
+        structureExtMap.putAll(structureMap);
+        JSONArray leaveDiags = new JSONArray();
+        specialProcess(structureMap, leaveDiagMap, leaveDiags);
+        structureExtMap.put("出院诊断", leaveDiags);
+
+        JSONArray operations = new JSONArray();
+        specialProcess(structureMap, operationMap, operations);
+        structureExtMap.put("手术信息", operations);
+        return structureExtMap;
+    }
+
+    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 -> {
+                        List<Element> xTextTable = findElement(cellElement.element("XElements"), "XTextTable");
+                        if (xTextTable.size() > 0) {
+                            xTextTable.forEach(stableElement -> {
+                                String stablePreTxt = getElementPreVal(stableElement);
+                                findElement(stableElement.element("XElements"), "XTextTableRow").forEach(srowElement -> {
+                                    findElement(srowElement.element("XElements"), "XTextTableCell").forEach(scellElement -> {
+                                        findElement(scellElement.element("XElements"), "XInputField").forEach(xInputFieldElement -> {
+                                            xInputField(map, xInputFieldElement, stablePreTxt);
+                                        });
+                                    });
+                                });
+                            });
+                        } else {
+                            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();
+                        }
+                    }
+                }
+            }
+        }
+        if (StringUtil.isBlank(value)) {
+            innerValueElement = xInputFieldElement.element("BackgroundText");
+            if (innerValueElement != null) {
+                value = innerValueElement.getTextTrim();
+            }
+        }
+        if (StringUtil.isBlank(value)) {
+            value = "";
+        }
+        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;
+    }
+
+    /**
+     * 根据给定key映射
+     *
+     * @param sourceMap
+     * @param keyContrasts
+     * @return
+     */
+    public static Map<String, String> mapKeyContrast(Map<String, String> sourceMap, List<String> keyContrasts) {
+        Map<String, String> retMap = Maps.newHashMap();
+        mapKeyContrastCommon(sourceMap, keyContrasts, retMap);
+        return retMap;
+    }
+
+    public static void mapKeyContrastCommon(Map sourceMap, List<String> keyContrasts, Map<String, String> retMap) {
+        Map<String, String> sourceMap_ = MapUtil.copyMap(sourceMap);
+        String[] arry = null;
+        String sourceKey = null, targetKey;
+        Set<String> removeKey = new HashSet<>();
+        for (String keyContrast : keyContrasts) {
+            arry = keyContrast.split("=");
+            sourceKey = arry[0];
+            if (arry.length == 1) {
+                targetKey = arry[0];
+            } else {
+                targetKey = arry[1];
+            }
+            if (StringUtil.isNotBlank(sourceMap_.get(sourceKey))
+                    && (!retMap.containsKey(targetKey) || StringUtil.isBlank(retMap.get(targetKey)))) {
+                retMap.put(targetKey, sourceMap_.get(sourceKey));
+            }
+            removeKey.add(sourceKey);
+            //            sourceMap_.remove(sourceKey); // 如果直接remove,多个标准key对应xml中同一个key就会出问题
+        }
+        //        retMap.putAll(sourceMap_); //如果key相同会覆盖之前的值,存在bug
+        Set<String> keySet = retMap.keySet();
+        for (String key : sourceMap_.keySet()) {
+            if (!keySet.contains(key) && !removeKey.contains(key)) { // 如果之前已放过key就不用放了
+                retMap.put(key, sourceMap_.get(key));
+            }
+        }
+    }
+
+    /**
+     * 特殊处理病案首页中出院诊断、手术
+     *
+     * @param structureMap
+     * @param leaveDiagMap
+     * @param array
+     */
+    public static void specialProcess(Map<String, String> structureMap, Map<String, String> leaveDiagMap, JSONArray array) {
+        JSONObject object;
+        int num = 0;
+        try {
+            for (Map.Entry<String, String> entry : leaveDiagMap.entrySet()) {
+                if (structureMap.containsKey(entry.getKey())) {
+                    String value = structureMap.get(entry.getKey());
+                    value = removeUseless(value);
+                    String[] values = value.split(" ");
+                    if (num == 0) {
+                        for (String v : values) {
+                            object = new JSONObject();
+                            object.put(entry.getValue(), v);
+                            array.add(object);
+                        }
+                    } else {
+                        boolean flag = false;
+                        if ("诊断类型".equals(entry.getKey()) && values[0].contains("诊断")) {
+                            array.getJSONObject(0).put("诊断类别", values[0].replace(":", ""));
+                            flag = true;
+                        }
+                        for (int i = 0; i < array.size(); i++) {
+                            if (flag) {
+                                array.getJSONObject(i).put(entry.getValue(), values[i + 1]);
+                            } else {
+                                array.getJSONObject(i).put(entry.getValue(), values[i]);
+                            }
+                        }
+                    }
+                }
+                num++;
+            }
+        } catch (Exception e) {
+            e.getMessage();
+        }
+    }
+
+    /**
+     * 去除末尾没用的“ -”或“ -”
+     *
+     * @param value
+     * @return
+     */
+    public static String removeUseless(String value) {
+        while (value.endsWith(" -") || value.endsWith(" -")) {
+            value = value.substring(0, value.length() - 2);
+        }
+        return value;
+    }
+
+    public static void main(String[] args) {
+        xmlToMap(FileUtil.fileRead("C:\\Users\\Administrator\\Desktop\\义务\\jiexi\\n5.xml"));
+    }
+
+    private static List<String> keyContrasts = Lists.newArrayList(
+            "过敏源=过敏药物",
+            "患者姓名=姓名",
+            "出院日期=出院时间",
+            "颅脑损伤患者入院后昏迷时间_天=颅脑损伤患者昏迷后天数",
+            "耗材类_检查用一次性医用材料费=检查用一次性医用材料费",
+            "联系人电话号码=联系人电话",
+            "入院途径=入院途径",
+            "婚姻状况=婚姻",
+            "入院科室=入院科别",
+            "治疗类_非手术治疗项目费=非手术治疗项目费",
+            "转科科别=转科科别",
+            "Rh血型=Rh",
+            "住院总费用_自付金额=自付金额",
+            "诊断符合情况_术前与术后=术前与术后",
+            "出院科室=出院科别",
+            "康复类_康复费=康复类",
+            "户口地址邮编=户口地址邮编",
+            "病案质量=病案质量",
+            "质控护士=质控护士",
+            "离院方式=离院方式",
+            "诊断符合情况_入院与出院=入院与出院",
+            "住院医师=住院医师",
+            "联系人姓名=联系人姓名",
+            "中医治疗费=中医治疗费",
+            "诊断符合情况_门诊与住院=门诊与住院",
+            "入院病房=入院病房",
+            "质控日期=质控日期",
+            "医疗机构代码=",
+            "颅脑损伤患者入院前昏迷时间_天=颅脑损伤患者昏迷前天数",
+            "治疗类_手术治疗费_麻醉费=麻醉费",
+            "婴儿年龄=",
+            "职业=职业",
+            "户口地址_其它=户口地址其它",
+            "出院病房=出院病房",
+            "综合医疗服务类_一般治疗操作费=一般治疗服务费",
+            "质控医师=质控医师",
+            "西药类_西药费=西药费",
+            "现住址_市=",
+            "病理诊断编码=病理诊断编码",
+            "责任护士111=责任护士",
+            "出院31天内再住院目的=再住院目的",
+            "现住址_省=",
+            "损伤中毒外部因素编码=损伤中毒因素编码",
+            "诊断类_影像学诊断费=影像学诊断费",
+            "体重11111=体重",
+            "转入医疗机构科室=接收机构名称",
+            "中药类_中成药费=中成药费",
+            "身份证件号码=身份证号",
+            "入院日期=入院时间",
+            "进修医师=进修医师",
+            "治疗类_手术治疗费=手术治疗费",
+            "血液和血液制品类_血费=血费",
+            "治疗类_手术治疗费_手术费=手术治疗费",
+            "血液和血液制品类_球蛋白类制品费=球蛋白类制品费",
+            "病理诊断=病理诊断",
+            "出院31天内再住院计划=三十一天内再住院计划",
+            "血液和血液制品类_凝血因子类制品费=凝血因子类制品费",
+            "工作单位电话=工作单位电话",
+            "药物过敏标志=药物过敏",
+            "联系电话=现住址电话",
+            "损伤中毒外部因素=损伤中毒因素",
+            "诊断类_实验室诊断费=实验室诊断费",
+            "年龄=新生儿年龄",
+            "诊断类_临床诊断项目费=临床诊断项目费",
+            "耗材类_治疗用一次性医用材料费=治疗用一次性医用材料费",
+            "诊断符合情况_临床与病理=临床与病理",
+            "诊断类_病理诊断费=病理诊断费",
+            "其他类_其他费=其他类其他费",
+            "患者工作单位地址=工作单位",
+            "死亡患者尸检标志=死亡患者尸检",
+            "现住址_其它=现住址其它",
+            "血液和血液制品类_白蛋白类制品费=白蛋白类制品费",
+            "综合医疗服务类_其他费用=其他费用",
+            "医疗付费方式代码=",
+            "医疗付费方式=",
+            "综合医疗服务类_护理费=护理费",
+            "(副)主任11=",
+            "住院总费用=总费用",
+            "门诊诊断=门急诊诊断",
+            "主治医生AAA=",
+            "现住址邮编=现住址邮编",
+            "颅脑损伤患者入院前昏迷时间_分=颅脑损伤患者昏迷前分钟",
+            "西药类_西药费_抗菌药物费用=抗菌药物费用",
+            "新生儿出生体重=新生儿出生体重",
+            "民族=民族",
+            "颅脑损伤患者入院后昏迷时间_时=颅脑损伤患者昏迷后小时",
+            "住院天数=实际住院天数",
+            "耗材类_手术用一次性医用材料费=手术用一次性医用材料费",
+            "ABO血型=血型",
+            "颅脑损伤患者入院前昏迷时间_时=颅脑损伤患者昏迷前小时",
+            "联系人住址=联系人地址",
+            "综合医疗服务类_一般医疗服务费=一般医疗服务费",
+            "血液和血液制品类_细胞因子类制品费=细胞因子类制品费",
+            "编码员=编码员",
+            "治疗类_非手术治疗项目费_临床物理治疗费=临床物理治疗费",
+            "颅脑损伤患者入院后昏迷时间_分=颅脑损伤患者昏迷后分钟",
+            "住院次数=",
+            "性别=性别",
+            "诊断符合情况_放射与病理=放射与病理",
+            "转入医疗机构_乡镇社区=接收机构名称",
+            "病案号=",
+            "中药类_中草药费=中草药费",
+            "出生日期=出生日期",
+            "联系人关系=联系人关系",
+            "科主任222=科主任",
+            "实习医师=实习医师",
+            "国籍=国籍",
+            "工作单位邮政编码=工作单位邮编"
+    );
+
+}

+ 1 - 0
kernel/src/main/java/com/lantone/qc/kernel/analysis/QCAnalysis.java

@@ -47,6 +47,7 @@ public class QCAnalysis {
         try {
             aiAnalyze.aiProcess(inputInfo);
         } catch (Exception e) {
+            log.error(e.getMessage(), e);
             System.out.println("出错病历号:" + inputInfo.getMedicalRecordInfoDoc().getStructureMap().get("behospitalCode"));
             throw new AIException("AI模型执行错误:" + e.getMessage());
         }

+ 3 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/beilun/operationdiscussion/OPE0369.java

@@ -55,6 +55,9 @@ public class OPE0369 extends QCCatalogue {
                 if (operationDoc.getOperationRecordDoc() != null) {
                     Map<String, String> operationDocStructureMap = operationDoc.getOperationRecordDoc().getStructureMap();
                     operationStartDate = operationDocStructureMap.get("手术开始时间");
+                    if (operationStartDate.contains("年月日")) {
+                        continue;
+                    }
                     if (StringUtil.isNotBlank(operationStartDate)) {
                         if (!CatalogueUtil.compareTime(
                                 StringUtil.parseDateTime(admisTime),

+ 5 - 5
kernel/src/main/java/com/lantone/qc/kernel/catalogue/beilun/preoperativediscussion/PRE0328.java

@@ -45,7 +45,8 @@ public class PRE0328 extends QCCatalogue {
             if (operationRecordDoc != null) {
                 startTime = operationRecordDoc.getStructureMap().get("手术开始时间");
             }
-            if (StringUtil.isNotBlank(startTime) && StringUtil.isNotBlank(admisTime)) {
+            if (StringUtil.isNotBlank(startTime) && StringUtil.isNotBlank(admisTime) &&
+                    !startTime.contains("年月日")) {
                 if (!CatalogueUtil.compareTime(
                         StringUtil.parseDateTime(admisTime),
                         StringUtil.parseDateTime(startTime),
@@ -64,9 +65,9 @@ public class PRE0328 extends QCCatalogue {
         }
         //医嘱中包含“冠状动脉造影术”,且无术前讨论.则报规则
         for (DoctorAdviceDoc doctorAdviceDoc : doctorAdviceDocs) {
-            Map<String,String> doctorAdviceStructuerMap = doctorAdviceDoc.getStructureMap();
+            Map<String, String> doctorAdviceStructuerMap = doctorAdviceDoc.getStructureMap();
             String advicename = doctorAdviceStructuerMap.get("医嘱项目名称");
-            if(StringUtil.isNotBlank(advicename) && advicename.contains("冠状动脉造影术") &&  j==0){
+            if (StringUtil.isNotBlank(advicename) && advicename.contains("冠状动脉造影术") && j == 0) {
                 status.set("-1");
                 info.set("手术记录不一致");
             }
@@ -101,8 +102,7 @@ public class PRE0328 extends QCCatalogue {
             }
             Map<String, String> structureMap = operationRecordDoc.getStructureMap();
             String operationStartDateStr = structureMap.get("手术开始时间");
-            // String operationEndDateStr = structureMap.get("手术结束时间");
-            if (StringUtil.isNotBlank(operationStartDateStr)) {
+            if (StringUtil.isNotBlank(operationStartDateStr) && DateUtil.parseDateTime(operationStartDateStr) != null) {
                 Date operationStartDate = StringUtil.parseDateTime(operationStartDateStr);
                 operationStartDate = DateUtil.dateZeroClear(operationStartDate);
                 if (operationStartDate != null) {

+ 3 - 0
kernel/src/main/java/com/lantone/qc/kernel/catalogue/beilun/threelevelward/THR02900.java

@@ -62,6 +62,9 @@ public class THR02900 extends QCCatalogue {
                 opeEndTime = opeEndTime.substring(17);
             }
             String chiefSurgeon = structureMap.get("主刀医师");
+            if (opeEndTime.contains("年月日")) {
+                continue;
+            }
             Date opeEndDate = CatalogueUtil.parseStringDate(opeEndTime);
             if (opeEndDate == null) {
                 continue;