Browse Source

fix(dan): 修复 A1/B4 认知维度解析失效

A1 parseA1Report:
- 方法2 改用「取下一行全部数字,第一个=得分,最后一个=百分位」,
  绕开 PDF 实际使用 U+FF5C 全角竖线(非 ASCII |)作分隔符的问题
- 方法3 缩短窗口至维度名后 300 字符内定位百分位,避免贪婪匹配
  到全文第一个百分位(总分 70%)导致 6 维全部取错值
- 方法1 增加 DOTALL 支持跨行描述文本

B4 parseB4Report:
- 新增报告前半部分认知维度提取(推理能力/空间能力/加工速度),
  category=cognitive,与 A1 共用 ReportBlockAssembler 的认知能力块,
  修复 B4 认知雷达图无数据源的问题

PDF 实测验证:A1 6/6 命中、B4 3/3 命中(含 35|35|89% 重复分场景)
mvn clean compile BUILD SUCCESS
liaoxg 6 ngày trước cách đây
mục cha
commit
c611ec55db

+ 37 - 3
cfc-backend/src/main/java/com/etotem/cfc/service/DanReportParseService.java

@@ -220,6 +220,37 @@ public class DanReportParseService {
         extra.put("name", name);
         extra.put("reportDate", reportDate);
 
+        // 1.5 认知能力维度(B4 报告前半部分:推理能力/空间能力/加工速度)
+        // 格式: "我的推理能力得分\n38|92%"(分隔符为 U+FF5C 全角竖线)
+        String[][] b4CogDims = {
+            {"推理能力", "reasoning"},
+            {"空间能力", "spatial"},
+            {"加工速度", "processingSpeed"}
+        };
+        for (String[] dc : b4CogDims) {
+            String dim = dc[0];
+            String code = dc[1];
+            int idx = fullText.indexOf("我的" + dim + "得分");
+            if (idx < 0) continue;
+            int lineStart = fullText.indexOf('\n', idx);
+            if (lineStart < 0) continue;
+            lineStart++;
+            int lineEnd = fullText.indexOf('\n', lineStart);
+            if (lineEnd < 0) lineEnd = Math.min(lineStart + 30, fullText.length());
+            String line = fullText.substring(lineStart, lineEnd);
+            java.util.regex.Matcher numMatcher = Pattern.compile("\\d+").matcher(line);
+            java.util.List<String> nums = new java.util.ArrayList<>();
+            while (numMatcher.find()) {
+                nums.add(numMatcher.group());
+            }
+            if (nums.size() >= 2) {
+                items.add(new DataItem(code + "_score", dim + "得分", nums.get(0), "cognitive"));
+                extra.put(code + "_score", nums.get(0));
+                items.add(new DataItem(code + "_pct", dim + "百分位", nums.get(nums.size() - 1), "cognitive"));
+                extra.put(code + "_pct", nums.get(nums.size() - 1));
+            }
+        }
+
         // 2. 自我概念 (Self-Concept)
         int selfConceptStart = findLineIndex(lines, "自我概念");
         int mindsetStart = findLineIndex(lines, "成长型思维模式");
@@ -315,7 +346,10 @@ public class DanReportParseService {
 
         // 方法2: 从detail页面提取原始分和百分位
         // PDF 格式: "我的感知觉得分\n41|46%"(分隔符为 U+FF5C 全角竖线,非 ASCII |)
-        // 策略:取「我的xxx得分」下一行的所有数字,取前两个
+        // 策略:取「我的xxx得分」下一行的所有数字
+        //   - 第一个数字 = 原始分(score)
+        //   - 最后一个数字 = 百分位(pct)
+        // 说明:个别 PDF 行会出现重复分(如 "35|35|89%"),取第一个+最后一个更稳
         for (int i = 0; i < cognitiveDims.length; i++) {
             String dim = cognitiveDims[i];
             String code = dimCodes[i];
@@ -331,12 +365,12 @@ public class DanReportParseService {
             java.util.regex.Matcher numMatcher =
                     Pattern.compile("\\d+").matcher(line);
             java.util.List<String> nums = new java.util.ArrayList<>();
-            while (numMatcher.find() && nums.size() < 2) {
+            while (numMatcher.find()) {
                 nums.add(numMatcher.group());
             }
             if (nums.size() >= 2) {
                 String score = nums.get(0);
-                String pct = nums.get(1);
+                String pct = nums.get(nums.size() - 1);
                 items.add(new DataItem(code + "_score", dim + "得分", score, "cognitive"));
                 extra.put(code + "_score", score);
                 if (!extra.containsKey(code + "_pct")) {