diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java index 104a070d..21171d60 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java @@ -1488,6 +1488,9 @@ public class AihrPracticeSeedService { } public CalibrationResponse calibrate(String sessionId, CalibrationRequest request) { + if (request == null || request.correctedTotal() == null) { + throw new ServiceException("人工校准必须明确填写总分"); + } ensurePracticeTable(); ensureCalibrationTable(); if (isBlank(sessionId)) { @@ -1509,7 +1512,7 @@ public class AihrPracticeSeedService { return null; } ScoreSnapshot score = rows.get(0); - int correctedTotal = request == null || request.correctedTotal() == null ? score.total() : clampScore(request.correctedTotal()); + int correctedTotal = clampScore(request.correctedTotal()); LocalDateTime now = LocalDateTime.now(); String reviewer = firstNonBlank(request == null ? null : request.reviewer(), "主管复盘"); String reason = firstNonBlank(request == null ? null : request.reason(), "人工校准AI评分"); diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrPracticeSeedServiceTest.java b/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrPracticeSeedServiceTest.java index 0157c8b1..3a2d69cb 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrPracticeSeedServiceTest.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrPracticeSeedServiceTest.java @@ -110,6 +110,15 @@ public class AihrPracticeSeedServiceTest { assertEquals("缺少员工ID,无法派发专项训练", error.getMessage()); } + @Test + public void calibrationRequiresExplicitCorrectedScore() { + AihrPracticeSeedService service = new AihrPracticeSeedService(new ObjectMapper(), null, null, null); + + ServiceException error = assertThrows(ServiceException.class, () -> service.calibrate("session-1", null)); + + assertEquals("人工校准必须明确填写总分", error.getMessage()); + } + @Test public void scenarioFilterKeepsRealEmptyDatabaseResultEmpty() { JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class); diff --git a/docs/BRD_IMPLEMENTATION_AUDIT.md b/docs/BRD_IMPLEMENTATION_AUDIT.md index 535d9d06..ccb4af96 100644 --- a/docs/BRD_IMPLEMENTATION_AUDIT.md +++ b/docs/BRD_IMPLEMENTATION_AUDIT.md @@ -282,3 +282,4 @@ - 2026-07-14 BRD 4.5/B5 人工贡献分默认值修复:管理端主管复盘表单此前默认填入 `10` 分,单纯点击“标记已复盘”可能产生未经主管确认的贡献分;现改为可选空值,只有明确填写的 `0–100` 分才提交并计入画像,页面文案同步为“人工贡献分”。后端既有空值保留逻辑不变,未新增积分来源;正式激励规则仍需 HR 确认。 - 2026-07-14 BRD G3/4.5 人工评审身份留痕修复:对练校准和主管复盘接口此前接受客户端传入的 `reviewer`,可能把人工证据归到伪造的操作人;现由控制器从当前登录用户绑定校准人/复盘人,请求字段仅保留兼容,不再作为身份来源。补源码契约回归和 `demo-check` marker;正式试点仍需抽查校准记录、复盘建议与实际主管/HR 账号的对应关系。 - 2026-07-14 BRD 4.5/G1 复盘证据状态边界修复:人工校准此前只按 `session_id` 查询,主管复盘更新也未显式要求完成时间,理论上可对未完成训练或非移动对练记录写入复核证据;现统一要求 `mode='mobile'` 且 `finished_time IS NOT NULL`,历史已完成记录不受影响。补服务回归断言和 `demo-check` marker,未修改业务数据。 +- 2026-07-14 BRD M5 人工校准样本完整性修复:校准接口此前在 `correctedTotal` 为空时自动复制 AI 原分数,空提交也会增加“人工校准样本”并可能虚高一致率;现要求明确提交人工总分,空值直接拒绝,前端请求类型同步改为必填。新增服务回归测试和 `demo-check` marker,不改变已有校准记录。 diff --git a/frontend/src/api/aihr/practice.ts b/frontend/src/api/aihr/practice.ts index 57f7792c..42fc227e 100644 --- a/frontend/src/api/aihr/practice.ts +++ b/frontend/src/api/aihr/practice.ts @@ -151,7 +151,7 @@ export type PracticeFinishResponse = { export type PracticeCalibrationRequest = { reviewer?: string; - correctedTotal?: number; + correctedTotal: number; correctedCompliance?: number; correctedEmotion?: number; correctedCommunication?: number; diff --git a/scripts/demo-check.sh b/scripts/demo-check.sh index 8f93418a..1311217d 100755 --- a/scripts/demo-check.sh +++ b/scripts/demo-check.sh @@ -457,6 +457,7 @@ contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/control contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrPracticeController.java "practiceSeedService.finish(request, currentAppUsername())" 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/AihrPracticeSeedService.java "finished_time IS NOT NULL" +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/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"