Просмотр исходного кода

fix(展望报告): 调整真题生词量入参契约

金逸霄 1 неделя назад
Родитель
Сommit
b6997daa6a

+ 2 - 4
abilities/exam-sprint/application/src/main/java/cn/yunzhixue/ability/center/examsprint/application/report/DefaultExamSprintReportApplicationService.java

@@ -558,8 +558,7 @@ public class DefaultExamSprintReportApplicationService implements ExamSprintRepo
         requireOutlookIntegralField(payload, "ExamineStrangeWordCount");
         requireOutlookArrayField(payload, "TestPaperWordIdArray");
         requireOutlookTextualField(payload, "TestPaperTitle");
-        requireOutlookArrayField(payload, "TestPaperUnMasterWords");
-        requireOutlookArrayField(payload, "TestPaperMastedWords");
+        requireOutlookIntegralField(payload, "TestPaperUnMasterWordCount");
         requireOutlookIntegralField(payload, "TestPaperMastedWordCount");
         requireOutlookIntegralField(payload, "TestPaperWordCount");
         requireOutlookBooleanField(payload, "Complex");
@@ -842,8 +841,7 @@ public class DefaultExamSprintReportApplicationService implements ExamSprintRepo
             case "examineStrangeWordCount" -> "ExamineStrangeWordCount";
             case "testPaperWordIdArray" -> "TestPaperWordIdArray";
             case "testPaperTitle" -> "TestPaperTitle";
-            case "testPaperUnMasterWords" -> "TestPaperUnMasterWords";
-            case "testPaperMastedWords" -> "TestPaperMastedWords";
+            case "testPaperUnMasterWordCount" -> "TestPaperUnMasterWordCount";
             case "testPaperMastedWordCount" -> "TestPaperMastedWordCount";
             case "testPaperWordCount" -> "TestPaperWordCount";
             case "complex" -> "Complex";

+ 1 - 8
abilities/exam-sprint/application/src/main/resources/warmup/outlook-exam-sprint-report.json

@@ -48,14 +48,7 @@
     1164567
   ],
   "TestPaperTitle": "文章2.jpg",
-  "TestPaperUnMasterWords": [
-    "lot",
-    "lot",
-    "father",
-    "father",
-    "catch"
-  ],
-  "TestPaperMastedWords": [],
+  "TestPaperUnMasterWordCount": 15,
   "TestPaperMastedWordCount": 0,
   "TestPaperWordCount": 15,
   "Complex": false

+ 40 - 8
abilities/exam-sprint/application/src/test/java/cn/yunzhixue/ability/center/examsprint/application/report/ExamSprintReportApplicationServiceTest.java

@@ -124,8 +124,6 @@ class ExamSprintReportApplicationServiceTest {
                 .contains("20260318测试")
                 .contains("TestPaperWordIdArraySize")
                 .contains("StudentWordsLatestSize")
-                .contains("TestPaperUnMasterWordsSize")
-                .contains("TestPaperMastedWordsSize")
                 .doesNotContain("TestPaperWordIdArray\":")
                 .doesNotContain("WordSpell\":\"w1")
                 .doesNotContain("lot")
@@ -255,6 +253,38 @@ class ExamSprintReportApplicationServiceTest {
                 .isEqualTo(ErrorCode.VALIDATION_ERROR);
     }
 
+    /** 覆盖展望报告新词汇契约校验场景,当 TestPaperUnMasterWordCount 缺失时,应返回字段级中文校验消息。 */
+    @Test
+    void createOutlookReportRejectsMissingTestPaperUnMasterWordCountWithChineseFieldMessage() throws Exception {
+        ObjectNode invalidPayload = callerVocabularyPayload().deepCopy();
+        invalidPayload.remove("TestPaperUnMasterWordCount");
+
+        assertThatThrownBy(() -> service(new TestRepository(), reportId -> { }, new TestStorage())
+                        .createOutlookReport(invalidPayload))
+                .isInstanceOf(BusinessException.class)
+                .hasMessageContaining("展望报告参数校验失败")
+                .hasMessageContaining("TestPaperUnMasterWordCount")
+                .hasMessageContaining("必须为数字")
+                .extracting(exception -> ((BusinessException) exception).getErrorCode())
+                .isEqualTo(ErrorCode.VALIDATION_ERROR);
+    }
+
+    /** 覆盖展望报告新词汇契约类型校验场景,当 TestPaperUnMasterWordCount 非数字时,应返回字段级中文校验消息。 */
+    @Test
+    void createOutlookReportRejectsTestPaperUnMasterWordCountTypeMismatchWithChineseFieldMessage() throws Exception {
+        ObjectNode invalidPayload = callerVocabularyPayload().deepCopy();
+        invalidPayload.put("TestPaperUnMasterWordCount", "3");
+
+        assertThatThrownBy(() -> service(new TestRepository(), reportId -> { }, new TestStorage())
+                        .createOutlookReport(invalidPayload))
+                .isInstanceOf(BusinessException.class)
+                .hasMessageContaining("展望报告参数校验失败")
+                .hasMessageContaining("TestPaperUnMasterWordCount")
+                .hasMessageContaining("必须为数字")
+                .extracting(exception -> ((BusinessException) exception).getErrorCode())
+                .isEqualTo(ErrorCode.VALIDATION_ERROR);
+    }
+
     /** 覆盖展望报告嵌套列表 Bean Validation 路径映射场景,应暴露请求 JSON 字段名并保留索引。 */
     @Test
     void createOutlookReportRejectsNestedStudentWordsLatestViolationWithApiFieldPath() throws Exception {
@@ -289,16 +319,15 @@ class ExamSprintReportApplicationServiceTest {
                 .isEqualTo(ErrorCode.VALIDATION_ERROR);
     }
 
-    /** 覆盖上游词汇报文允许无已掌握真题词的场景,当 TestPaperMastedWords 为空且计数为 0 时,应正常创建并分发。 */
+    /** 覆盖展望报告新词汇契约场景,当调用方不再传真题词数组但传 TestPaperUnMasterWordCount 时,应正常创建并分发。 */
     @Test
-    void createOutlookReportAcceptsCallerVocabularyPayloadWithNoMasteredPaperWords() throws Exception {
+    void createOutlookReportAcceptsCallerVocabularyPayloadWithoutPaperWordArrays() throws Exception {
         TestRepository repository = new TestRepository();
         TestStorage storage = new TestStorage();
         List<String> dispatchedReportIds = new ArrayList<>();
         DefaultExamSprintReportApplicationService service = service(repository, dispatchedReportIds::add, storage);
         ObjectNode payload = callerVocabularyPayload().deepCopy();
-        payload.putArray("TestPaperMastedWords");
-        payload.put("TestPaperMastedWordCount", 0);
+        payload.put("TestPaperUnMasterWordCount", 3);
 
         var response = service.createOutlookReport(payload);
 
@@ -307,6 +336,10 @@ class ExamSprintReportApplicationServiceTest {
         assertThat(saved.reportType()).isEqualTo(ReportType.OUTLOOK);
         assertThat(saved.generationStatus()).isEqualTo(ReportGenerationStatus.PENDING);
         assertThat(dispatchedReportIds).containsExactly(response.reportId());
+        JsonNode savedPayload = (JsonNode) ((UnmodeledReportContent) saved.content()).source();
+        assertThat(savedPayload.fieldNames()).toIterable()
+                .doesNotContain("TestPaper" + "UnMasterWords", "TestPaper" + "MastedWords");
+        assertThat(savedPayload.path("TestPaperUnMasterWordCount").asInt()).isEqualTo(3);
     }
 
     /** 覆盖上游词汇报文缺少词汇明细的场景,当 StudentWordsLatest 缺失时,应在保存前校验失败。 */
@@ -1139,8 +1172,7 @@ class ExamSprintReportApplicationServiceTest {
                   "ExamineStrangeWordCount": 3,
                   "TestPaperWordIdArray": [1, 2, 3, 4, 5],
                   "TestPaperTitle": "文章2.jpg",
-                  "TestPaperUnMasterWords": ["lot", "father", "catch"],
-                  "TestPaperMastedWords": ["a", "the"],
+                  "TestPaperUnMasterWordCount": 3,
                   "TestPaperMastedWordCount": 2,
                   "TestPaperWordCount": 5,
                   "Complex": false

+ 1 - 2
abilities/exam-sprint/contracts/src/main/java/cn/yunzhixue/ability/center/examsprint/contracts/report/OutlookExamSprintReportPayload.java

@@ -25,8 +25,7 @@ public record OutlookExamSprintReportPayload(
         @JsonProperty("ExamineStrangeWordCount") @NotNull @Min(0) Integer examineStrangeWordCount,
         @JsonProperty("TestPaperWordIdArray") @NotNull List<@NotNull @Min(0) Integer> testPaperWordIdArray,
         @JsonProperty("TestPaperTitle") @NotBlank String testPaperTitle,
-        @JsonProperty("TestPaperUnMasterWords") @NotNull List<@NotBlank String> testPaperUnMasterWords,
-        @JsonProperty("TestPaperMastedWords") @NotNull List<@NotBlank String> testPaperMastedWords,
+        @JsonProperty("TestPaperUnMasterWordCount") @NotNull @Min(0) Integer testPaperUnMasterWordCount,
         @JsonProperty("TestPaperMastedWordCount") @NotNull @Min(0) Integer testPaperMastedWordCount,
         @JsonProperty("TestPaperWordCount") @NotNull @Min(0) Integer testPaperWordCount,
         @JsonProperty("Complex") @NotNull Boolean complex) {

+ 1 - 1
abilities/exam-sprint/infrastructure/src/main/java/cn/yunzhixue/ability/center/examsprint/infrastructure/report/rendering/outlook/ClasspathOutlookExamSprintReportRenderer.java

@@ -99,7 +99,7 @@ public class ClasspathOutlookExamSprintReportRenderer implements ExamSprintRepor
                         "优先补齐高频和核心常考词。"),
                 new PastPaperVocabularyChart(
                         payload.testPaperWordCount(),
-                        payload.testPaperWordCount() - payload.testPaperMastedWordCount(),
+                        payload.testPaperUnMasterWordCount(),
                         null),
                 new HighFrequencyVocabularyChart(
                         roundedMasteryPercent(words, 0, basicUpper),

+ 1 - 2
abilities/exam-sprint/infrastructure/src/test/java/cn/yunzhixue/ability/center/examsprint/infrastructure/report/pdf/OpenHtmlToPdfExamSprintReportPdfGeneratorTest.java

@@ -318,8 +318,7 @@ class OpenHtmlToPdfExamSprintReportPdfGeneratorTest {
                   "ExamineStrangeWordCount": 3,
                   "TestPaperWordIdArray": [1, 2, 3, 4, 5],
                   "TestPaperTitle": "文章2.jpg",
-                  "TestPaperUnMasterWords": ["lot", "father", "catch"],
-                  "TestPaperMastedWords": ["a", "the"],
+                  "TestPaperUnMasterWordCount": 3,
                   "TestPaperMastedWordCount": 2,
                   "TestPaperWordCount": 5,
                   "Complex": false

+ 3 - 7
abilities/exam-sprint/infrastructure/src/test/java/cn/yunzhixue/ability/center/examsprint/infrastructure/report/rendering/outlook/ClasspathOutlookExamSprintReportRendererTest.java

@@ -103,7 +103,7 @@ class ClasspathOutlookExamSprintReportRendererTest {
                 .contains("考纲总量:<span class='highlight'>10词</span>")
                 .contains("已掌握:<span class='highlight'>4词(40.00%)</span>")
                 .contains("未掌握:<span class='highlight'>6词(60.00%)</span>")
-                .contains("真题总词:5词 | 生词量:1词(20.00%)")
+                .contains("真题总词:5词 | 生词量:3词(60.00%)")
                 .doesNotContain("冲刺后生词:")
                 .doesNotContain("先压降真题生词占比。")
                 .doesNotContain("拉分词是提分核心突破项")
@@ -499,8 +499,7 @@ class ClasspathOutlookExamSprintReportRendererTest {
                   "ExamineStrangeWordCount": 3,
                   "TestPaperWordIdArray": [1, 2, 3, 4, 5],
                   "TestPaperTitle": "文章2.jpg",
-                  "TestPaperUnMasterWords": ["lot", "father", "catch"],
-                  "TestPaperMastedWords": ["a", "the"],
+                  "TestPaperUnMasterWordCount": 3,
                   "TestPaperMastedWordCount": 2,
                   "TestPaperWordCount": 5,
                   "Complex": false
@@ -528,10 +527,7 @@ class ClasspathOutlookExamSprintReportRendererTest {
     private JsonNode callerVocabularyPayloadWithMismatchedPastPaperCounts() throws Exception {
         ObjectNode payload = (ObjectNode) callerVocabularyPayloadWithComplex(true);
         payload.put("TestPaperMastedWordCount", 4);
-        payload.putArray("TestPaperUnMasterWords")
-                .add("lot")
-                .add("father")
-                .add("catch");
+        payload.put("TestPaperUnMasterWordCount", 3);
         return payload;
     }
 

+ 1 - 2
ability-center-runtime/scripts/outlook-report-demo.sh

@@ -74,8 +74,7 @@ http_code="$({
   "ExamineStrangeWordCount": 3,
   "TestPaperWordIdArray": [1, 2, 3, 4, 5],
   "TestPaperTitle": "文章2.jpg",
-  "TestPaperUnMasterWords": ["lot", "father", "catch"],
-  "TestPaperMastedWords": ["a", "the"],
+  "TestPaperUnMasterWordCount": 3,
   "TestPaperMastedWordCount": 2,
   "TestPaperWordCount": 5,
   "Complex": false

+ 1 - 2
ability-center-runtime/src/test/resources/requests/exam-sprint-outlook-report-request.json

@@ -52,8 +52,7 @@
   "ExamineStrangeWordCount": 3,
   "TestPaperWordIdArray": [1, 2, 3, 4, 5],
   "TestPaperTitle": "文章2.jpg",
-  "TestPaperUnMasterWords": ["lot", "father", "catch"],
-  "TestPaperMastedWords": ["a", "the"],
+  "TestPaperUnMasterWordCount": 3,
   "TestPaperMastedWordCount": 2,
   "TestPaperWordCount": 5,
   "Complex": false