From c4f98b9ab6c485c9039dadc47a7cb9c9968df968 Mon Sep 17 00:00:00 2001 From: let5sne Date: Tue, 14 Jul 2026 14:31:54 +0800 Subject: [PATCH] fix(aihr): require interview answers before scoring --- .../aihr/service/AihrInterviewService.java | 3 +++ .../aihr/service/AihrInterviewServiceTest.java | 18 ++++++++++++++++++ docs/BRD_IMPLEMENTATION_AUDIT.md | 1 + scripts/demo-check.sh | 1 + 4 files changed, 23 insertions(+) diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrInterviewService.java b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrInterviewService.java index b7ac960d..ae958d9c 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrInterviewService.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrInterviewService.java @@ -110,6 +110,9 @@ public class AihrInterviewService { } }); } + if (session.questions().stream().noneMatch(question -> !isBlank(session.answers().get(question.questionId())))) { + throw new IllegalArgumentException("请先提交至少一条有效面试回答"); + } ScoreResult score = scoreWithModel(session).orElseGet(() -> localScore(session)); String time = LocalDateTime.now().format(TIME_FORMAT); List questions = questionRecords(session); diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrInterviewServiceTest.java b/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrInterviewServiceTest.java index d1767bd8..c278d275 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrInterviewServiceTest.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrInterviewServiceTest.java @@ -22,6 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyDouble; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -185,6 +186,23 @@ class AihrInterviewServiceTest { assertTrue(serviceSource.contains("reviewed_time = NULL")); } + @Test + @Tag("dev") + void interviewFinishRequiresAtLeastOneRealAnswer() { + JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class); + AihrModelSeedService modelService = mock(AihrModelSeedService.class); + when(modelService.tryChat(anyString(), anyString(), anyDouble())).thenReturn(Optional.empty()); + AihrInterviewService service = new AihrInterviewService(new ObjectMapper(), modelService, jdbcTemplate); + var started = service.start(new StartRequest("candidate-empty", "候选人", "customer-service", "mobile")); + + IllegalArgumentException error = assertThrows(IllegalArgumentException.class, () -> service.finish( + new FinishRequest(started.sessionId(), Map.of()) + )); + + assertEquals("请先提交至少一条有效面试回答", error.getMessage()); + verify(jdbcTemplate, never()).update(anyString(), org.mockito.ArgumentMatchers.any()); + } + @Test @Tag("dev") void reviewResultRejectsOutOfRangeScore() { diff --git a/docs/BRD_IMPLEMENTATION_AUDIT.md b/docs/BRD_IMPLEMENTATION_AUDIT.md index f9056b97..3ffa6e07 100644 --- a/docs/BRD_IMPLEMENTATION_AUDIT.md +++ b/docs/BRD_IMPLEMENTATION_AUDIT.md @@ -285,3 +285,4 @@ - 2026-07-14 BRD M5 人工校准样本完整性修复:校准接口此前在 `correctedTotal` 为空时自动复制 AI 原分数,空提交也会增加“人工校准样本”并可能虚高一致率;现要求明确提交人工总分,空值直接拒绝,前端请求类型同步改为必填。新增服务回归测试和 `demo-check` marker,不改变已有校准记录。 - 2026-07-14 BRD G2 面试复核证据状态边界修复:AI 面试复核此前只按租户和 `session_id` 更新,未显式要求结果已完成且存在 AI 总分;现要求 `finished_time IS NOT NULL` 且 `total_score IS NOT NULL`,避免对未完成或不完整结果写入人工复核证据。新增服务回归断言和 `demo-check` marker,未修改业务数据。 - 2026-07-14 BRD G2 面试复核版本一致性修复:同一面试会话重复 `finish` 时,AI 结果 upsert 此前会更新 AI 分数但保留旧人工复核分,可能把旧人工结论挂到新结果;现重复完成会清空人工复核分、复核人、意见和时间并恢复“待复核”,要求对新结果重新人工确认。新增服务回归断言和 `demo-check` marker,未修改业务数据。 +- 2026-07-14 BRD 4.1 面试作答完整性修复:面试 `finish` 此前允许没有任何对应题目有效回答仍生成本地 55 分结果并进入人工复核;现要求至少提交一条有效面试回答,空面试不落结果表。新增服务回归测试和 `demo-check` marker,未修改业务数据。 diff --git a/scripts/demo-check.sh b/scripts/demo-check.sh index 438b1be1..47dcd4a8 100755 --- a/scripts/demo-check.sh +++ b/scripts/demo-check.sh @@ -460,6 +460,7 @@ contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "人工校准必须明确填写总分" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrInterviewService.java "finished_time IS NOT NULL AND total_score IS NOT NULL" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrInterviewService.java "reviewed_score = NULL" +contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrInterviewService.java "请先提交至少一条有效面试回答" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "noneMatch(AihrPracticeSeedService::canSeeProject)" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrPracticeController.java "@SaCheckLogin" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrPracticeController.java "sessions/{sessionId}/annotations"