2 Commity 45c60d6899 ... 62004d8c22

Autor SHA1 Wiadomość Data
  jiapu 62004d8c22 Merge remote-tracking branch 'origin/cfclub' into cfclub 2 tygodni temu
  jiapu a2750a26d9 优化修复 2 tygodni temu

+ 43 - 16
cfc-backend/src/main/java/com/etotem/cfc/service/PdfParseService.java

@@ -613,21 +613,50 @@ public ParsedReportResult parseText(String fullText) {
         return null;
     }
 
-    private String findReportNumber(List<String> lines) {
-        String value = findTextAfter(lines, "报告编号:");
-        if (value != null && !value.isEmpty()) return value.trim();
+    /**
+     * 读取标签对应的值。兼容募极报告封面常见排版:
+     * 1) 标签与值分行、无冒号(「姓名」下一行「马智强」)
+     * 2) 标签带半角/全角冒号且值在下一行(「姓名:」)
+     * 3) 标签与值同行(「姓名:马智强」)
+     */
+    private String findLabeledValue(List<String> lines, String... labels) {
         for (int i = 0; i < lines.size(); i++) {
             String line = lines.get(i).trim();
-            if (line.equals("编号:") && i + 1 < lines.size()) {
-                String next = lines.get(i + 1).trim();
-                if (!next.isEmpty() && next.length() <= 20) {
-                    return next;
+            for (String label : labels) {
+                String ascii = label + ":";
+                String fullwidth = label + "\uFF1A";
+                if (line.equals(label) || line.equals(ascii) || line.equals(fullwidth)) {
+                    if (i + 1 < lines.size()) {
+                        String next = lines.get(i + 1).trim();
+                        if (!next.isEmpty()) {
+                            return next;
+                        }
+                    }
+                } else if (line.startsWith(ascii) || line.startsWith(fullwidth)) {
+                    int colonIdx = line.indexOf(':');
+                    if (colonIdx < 0) {
+                        colonIdx = line.indexOf('\uFF1A');
+                    }
+                    if (colonIdx >= 0 && colonIdx + 1 < line.length()) {
+                        String val = line.substring(colonIdx + 1).trim();
+                        if (!val.isEmpty()) {
+                            return val;
+                        }
+                    }
                 }
             }
         }
         return null;
     }
 
+    private String findReportNumber(List<String> lines) {
+        String value = findLabeledValue(lines, "报告编号", "检测编号", "编号");
+        if (value != null && !value.isEmpty() && value.length() <= 30) {
+            return value.trim();
+        }
+        return null;
+    }
+
     private String findReportDate(List<String> lines) {
         String[] keywords = {"采样日期:", "报告日期:", "检测日期:"};
         for (String keyword : keywords) {
@@ -651,15 +680,13 @@ public ParsedReportResult parseText(String fullText) {
     }
 
     private String findPersonName(List<String> lines) {
-        String[] keywords = {"姓名:", "宝宝姓名:", "受检人姓名:"};
-        for (String keyword : keywords) {
-            String value = findTextAfter(lines, keyword);
-            if (value != null && !value.isEmpty()) {
-                String name = value.trim();
-                if (name.length() <= 20 && !name.matches(".*[0-9]{5,}.*")) {
-                    return name;
-                }
-            }
+        String value = findLabeledValue(lines, "受检人姓名", "宝宝姓名", "姓名");
+        if (value == null || value.isEmpty()) {
+            return null;
+        }
+        String name = value.trim().replaceAll("(编号|年龄|性别|备注|肠道).*", "").trim();
+        if (name.length() >= 2 && name.length() <= 20 && !name.matches(".*[0-9]{5,}.*")) {
+            return name;
         }
         return null;
     }

+ 13 - 0
cfc-backend/src/test/java/com/etotem/cfc/integration/service/PdfParseServiceTest.java

@@ -56,6 +56,19 @@ public class PdfParseServiceTest {
         assertEquals("AKK型", result.getGutType());
     }
 
+    @Test
+    public void parseText_mujiCoverWithoutColon_extractsPersonName() {
+        // 募极封面实际排版:标签与值分行且无冒号;「马」常被抽成康熙部首 ⻢ (U+2EE2)
+        String text = "报告生成:2026-08-01\n姓名\n\u2ee2智强\n编号\n503458261\n年龄\n43岁\n备注\n性别\n男\n"
+                + "肠道预测年龄:\n48.70岁\n肠型:\n拟杆菌型\n健康总分\n58\n菌群健康\n67";
+        ParsedReportResult result = service.parseText(text);
+        assertEquals("马智强", result.getPersonName());
+        assertEquals("503458261", result.getReportNumber());
+        assertEquals(Integer.valueOf(43), result.getAge());
+        assertEquals("male", result.getGender());
+        assertEquals(Integer.valueOf(58), result.getOverallScore());
+    }
+
     @Test
     public void parseText_withDiseaseRiskSection_parsesCorrectly() {
         // 模拟疾病风险表格格式