diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrMobileController.java b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrMobileController.java index 9fffdc0e..57a20763 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrMobileController.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrMobileController.java @@ -173,7 +173,7 @@ public class AihrMobileController { @PostMapping("/practice/reviews/{id}/reviewed") public R markReviewed(@PathVariable Long id, @RequestBody(required = false) ReviewAdviceRequest request) { - return mobileSeedService.markReviewed(id, request, supervisorScopeExtPartyId()) ? R.ok() : R.fail("复盘记录不存在"); + return mobileSeedService.markReviewed(id, bindReviewOperator(request), supervisorScopeExtPartyId()) ? R.ok() : R.fail("复盘记录不存在"); } @GetMapping("/profile") @@ -254,6 +254,24 @@ public class AihrMobileController { return username == null ? "" : username.trim(); } + private static ReviewAdviceRequest bindReviewOperator(ReviewAdviceRequest request) { + return new ReviewAdviceRequest( + currentOperatorUsername(), + request == null ? null : request.advice(), + request == null ? null : request.incentivePoint(), + request == null ? null : request.nextScenarioId(), + request == null ? null : request.nextReason() + ); + } + + private static String currentOperatorUsername() { + LoginUser loginUser = LoginHelper.getLoginUser(); + if (loginUser == null || loginUser.getUsername() == null) { + return ""; + } + return loginUser.getUsername().trim(); + } + private static boolean supervisorRoleRequested(String role) { if (role == null) { return false; diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrPracticeController.java b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrPracticeController.java index 961cac82..f46374b7 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrPracticeController.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrPracticeController.java @@ -149,10 +149,22 @@ public class AihrPracticeController { @SaCheckRole(value = {TenantConstants.SUPER_ADMIN_ROLE_KEY, HR_OPERATOR_ROLE}, mode = SaMode.OR) @PostMapping("/sessions/{sessionId}/calibration") public R calibration(@PathVariable String sessionId, @RequestBody(required = false) CalibrationRequest request) { - CalibrationResponse response = practiceSeedService.calibrate(sessionId, request); + CalibrationResponse response = practiceSeedService.calibrate(sessionId, bindCalibrationReviewer(request)); return response == null ? R.fail("训练会话不存在") : R.ok(response); } + private static CalibrationRequest bindCalibrationReviewer(CalibrationRequest request) { + return new CalibrationRequest( + currentOperatorUsername(), + request == null ? null : request.correctedTotal(), + request == null ? null : request.correctedCompliance(), + request == null ? null : request.correctedEmotion(), + request == null ? null : request.correctedCommunication(), + request == null ? null : request.correctedMarketing(), + request == null ? null : request.reason() + ); + } + private static StartRequest bindMobileStartIdentity(StartRequest request) { if (request == null || !"mobile".equalsIgnoreCase(request.mode())) { return request; @@ -172,4 +184,12 @@ public class AihrPracticeController { String username = loginUser.getUsername(); return username == null ? "" : username.trim(); } + + private static String currentOperatorUsername() { + LoginUser loginUser = LoginHelper.getLoginUser(); + if (loginUser == null || loginUser.getUsername() == null) { + return ""; + } + return loginUser.getUsername().trim(); + } } 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 07e229db..2a818010 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 @@ -552,7 +552,7 @@ public class AihrPracticeSeedServiceTest { assertTrue(controllerSource.contains("mobileSeedService.practiceReviews(supervisorScopeExtPartyId(),")); assertTrue(controllerSource.contains("mobileSeedService.practiceTeam(supervisorScopeExtPartyId())")); assertTrue(controllerSource.contains("mobileSeedService.practiceReview(id, supervisorScopeExtPartyId())")); - assertTrue(controllerSource.contains("mobileSeedService.markReviewed(id, request, supervisorScopeExtPartyId())")); + assertTrue(controllerSource.contains("mobileSeedService.markReviewed(id, bindReviewOperator(request), supervisorScopeExtPartyId())")); assertTrue(controllerSource.contains("mobileSeedService.practiceAlerts(supervisorScopeExtPartyId())")); assertTrue(controllerSource.contains("mobileSeedService.createPracticeAssignment(request, supervisorScopeExtPartyId())")); assertTrue(controllerSource.contains("orgSyncService.snapshot(phone, null, null, \"active\", 1, 500, 500)")); @@ -602,6 +602,8 @@ public class AihrPracticeSeedServiceTest { assertTrue(controllerSource.contains("import cn.dev33.satoken.annotation.SaCheckLogin;")); assertTrue(controllerSource.contains("@SaCheckLogin\npublic class AihrPracticeController")); + assertTrue(controllerSource.contains("bindCalibrationReviewer(request)")); + assertTrue(controllerSource.contains("private static String currentOperatorUsername()")); } @Test diff --git a/docs/BRD_IMPLEMENTATION_AUDIT.md b/docs/BRD_IMPLEMENTATION_AUDIT.md index 85837d75..eb95b600 100644 --- a/docs/BRD_IMPLEMENTATION_AUDIT.md +++ b/docs/BRD_IMPLEMENTATION_AUDIT.md @@ -280,3 +280,4 @@ - 2026-07-14 BRD 4.4 任务来源展示补齐:首页“今日安排”和练习页“最近练过”此前只把非每日任务显示为场景名/“专项训练”,会遮蔽主管派发的错题再练与训练营来源;现统一显示“每日三题/错题再练/训练营/专项训练”标签。该修复只补来源可见性,不把 `source='camp'` 扩展为尚未确认的训练营计划、进度或完成规则。 - 2026-07-14 BRD 4.5/B5 训练时长口径修复:能力画像此前用“完成次数 × 8 分钟”估算训练时长,无法作为真实时长证据;现复用 `started_time/finished_time` 按实际秒数聚合并换算分钟,无时间证据的历史记录按 0 计。未新增表字段;正式试点仍需核对时间来源、异常时长和课程学习时长是否纳入统一口径。 - 2026-07-14 BRD 4.5/B5 人工贡献分默认值修复:管理端主管复盘表单此前默认填入 `10` 分,单纯点击“标记已复盘”可能产生未经主管确认的贡献分;现改为可选空值,只有明确填写的 `0–100` 分才提交并计入画像,页面文案同步为“人工贡献分”。后端既有空值保留逻辑不变,未新增积分来源;正式激励规则仍需 HR 确认。 +- 2026-07-14 BRD G3/4.5 人工评审身份留痕修复:对练校准和主管复盘接口此前接受客户端传入的 `reviewer`,可能把人工证据归到伪造的操作人;现由控制器从当前登录用户绑定校准人/复盘人,请求字段仅保留兼容,不再作为身份来源。补源码契约回归和 `demo-check` marker;正式试点仍需抽查校准记录、复盘建议与实际主管/HR 账号的对应关系。 diff --git a/mobile-uni/src/types/api.ts b/mobile-uni/src/types/api.ts index 6c267a44..170e686c 100644 --- a/mobile-uni/src/types/api.ts +++ b/mobile-uni/src/types/api.ts @@ -280,7 +280,7 @@ export interface ReviewDetail extends PracticeRecord { mentorRewrite: string; aiComment: string; reviewAdvice?: string; - incentivePoint?: number; + incentivePoint?: number | null; scoreItems: CompetencyDimension[]; dialogue: ReviewDialogue[]; annotations: ReviewAnnotation[]; diff --git a/scripts/demo-check.sh b/scripts/demo-check.sh index 5016674a..632269ec 100755 --- a/scripts/demo-check.sh +++ b/scripts/demo-check.sh @@ -459,6 +459,8 @@ 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 "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" +contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrPracticeController.java "bindCalibrationReviewer(request)" +contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrMobileController.java "bindReviewOperator(request)" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrPromptTemplateController.java "/api/aihr/prompt-templates" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrPromptTemplateController.java "public R> list" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "mobileCompletedCount"