|
@@ -0,0 +1,144 @@
|
|
|
+package com.lantone.qc.kernel.catalogue.hospital.yiwu.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 com.lantone.qc.pub.util.StringUtil;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.regex.Matcher;
|
|
|
+import java.util.regex.Pattern;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @ClassName : FIRP03260
|
|
|
+ * @Description : 首页-专病-主诊断-年龄-不符 乳腺良性肿瘤年龄年龄应大于28天小于14周岁错误
|
|
|
+ */
|
|
|
+@Component
|
|
|
+public class FIRP03260 extends QCCatalogue {
|
|
|
+
|
|
|
+ // 增强版正则表达式,支持组合单位和更多书写形式
|
|
|
+ private static final Pattern AGE_PATTERN = Pattern.compile(
|
|
|
+ "(\\d+\\.?\\d*)\\s*([岁年yY]|个?月|m|M|天|日|d|D)(?=\\s*(?:\\d|$))"
|
|
|
+ );
|
|
|
+
|
|
|
+ // 单位转换基准(医疗常用标准)
|
|
|
+ private static final double MONTHS_PER_YEAR = 12.0;
|
|
|
+
|
|
|
+ private static final double DAYS_PER_MONTH = 30.0;
|
|
|
+ private static final double DAYS_PER_YEAR = 365.2425; // 格里高利年平均值
|
|
|
+
|
|
|
+ public void start(InputInfo inputInfo, OutputInfo outputInfo) {
|
|
|
+ status.set("0");
|
|
|
+ if (inputInfo.getFirstPageRecordDoc() != null && inputInfo.getFirstPageRecordDoc().getStructureExtMap() != null) {
|
|
|
+ Map<String, Object> firstpageStructureMap = inputInfo.getFirstPageRecordDoc().getStructureExtMap();
|
|
|
+ List<Map<String, String>> outpatientEmergencyDiagList = (List) firstpageStructureMap.get(Content.dischargeDiag);
|
|
|
+ if (ListUtil.isEmpty(outpatientEmergencyDiagList)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ List<String> firstpageDischargeDiag = getFirstpageDischargeDiag(outpatientEmergencyDiagList);
|
|
|
+ if (!firstpageDischargeDiag.contains("包茎")) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String admissionAge = (String)firstpageStructureMap.get(Content.age);
|
|
|
+ if (!isUnder14Years(admissionAge) || isUnder28Days(admissionAge)) {
|
|
|
+ status.set("-1");
|
|
|
+ info.set("患者年龄:" + admissionAge);
|
|
|
+ String xmlId = CatalogueUtil.getXmlId(firstpageStructureMap, Content.age);
|
|
|
+ id.set(xmlId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<String> getFirstpageDischargeDiag(List<Map<String, String>> outpatientEmergencyDiagList) {
|
|
|
+ List<String> firstpageDischargeDiag = new ArrayList<>();
|
|
|
+ for (Map<String, String> outpatientEmergencyDiag : outpatientEmergencyDiagList) {
|
|
|
+ String diag = outpatientEmergencyDiag.get(Content.diagnoseName);
|
|
|
+ if (StringUtil.isNotBlank(diag)) {
|
|
|
+ firstpageDischargeDiag.add(diag);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return firstpageDischargeDiag;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static boolean isUnder14Years(String ageString) {
|
|
|
+ if (ageString == null || ageString.trim().isEmpty()) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ double totalYears = 0.0;
|
|
|
+ Matcher matcher = AGE_PATTERN.matcher(ageString);
|
|
|
+
|
|
|
+ while (matcher.find()) {
|
|
|
+ try {
|
|
|
+ double value = Double.parseDouble(matcher.group(1));
|
|
|
+ String unit = normalizeUnit(matcher.group(2));
|
|
|
+
|
|
|
+ switch (unit) {
|
|
|
+ case "year":
|
|
|
+ totalYears += value;
|
|
|
+ break;
|
|
|
+ case "month":
|
|
|
+ totalYears += value / MONTHS_PER_YEAR;
|
|
|
+ break;
|
|
|
+ case "day":
|
|
|
+ totalYears += value / DAYS_PER_YEAR;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ // 记录无效数值日志
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 四舍五入保留4位小数处理精度问题
|
|
|
+ return Math.round(totalYears * 10000.0) / 10000.0 < 14.0;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static boolean isUnder28Days(String ageString) {
|
|
|
+ if (ageString == null || ageString.trim().isEmpty()) {
|
|
|
+ return false; // 无效输入处理
|
|
|
+ }
|
|
|
+
|
|
|
+ double totalDays = 0.0;
|
|
|
+ Matcher matcher = AGE_PATTERN.matcher(ageString);
|
|
|
+
|
|
|
+ while (matcher.find()) {
|
|
|
+ try {
|
|
|
+ double value = Double.parseDouble(matcher.group(1));
|
|
|
+ String unit = matcher.group(2).toLowerCase();
|
|
|
+
|
|
|
+ switch (unit) {
|
|
|
+ case "年": case "岁": case "y":
|
|
|
+ totalDays += value * DAYS_PER_YEAR;
|
|
|
+ break;
|
|
|
+ case "个月": case "月": case "m":
|
|
|
+ totalDays += value * DAYS_PER_MONTH;
|
|
|
+ break;
|
|
|
+ case "天": case "日": case "d":
|
|
|
+ totalDays += value;
|
|
|
+ break;
|
|
|
+ // 可扩展周等单位
|
|
|
+ }
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ // 记录日志或处理异常数值
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 精确浮点数比较(保留两位小数)
|
|
|
+ return Math.round(totalDays * 100) / 100.0 <= 28.0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 单位标准化方法
|
|
|
+ private static String normalizeUnit(String rawUnit) {
|
|
|
+ String unit = rawUnit.toLowerCase();
|
|
|
+ if (unit.matches("[岁年y]")) return "year";
|
|
|
+ if (unit.matches("个?月|m")) return "month";
|
|
|
+ if (unit.matches("[天日d]")) return "day";
|
|
|
+ return "unknown";
|
|
|
+ }
|
|
|
+}
|