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 dce70497..6a340dde 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 @@ -1906,7 +1906,9 @@ public class AihrPracticeSeedService { String scenarioId = firstNonBlank(request == null ? null : request.scenarioId(), "fee-parking"); ScenarioSeed scenario = resolveScenario(scenarioId, null); String traineeName = firstNonBlank(request == null ? null : request.traineeName(), extPartyId); - String source = firstNonBlank(request == null ? null : request.source(), "manual"); + // Assignment source is a server-owned classification. Client supplied values + // must not turn a manual supervisor assignment into a daily/retry/camp record. + String source = "manual"; String reason = firstNonBlank(request == null ? null : request.reason(), "主管派发专项训练"); Timestamp createdAt = Timestamp.valueOf(now); jdbcTemplate.update(""" 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 04010c5e..b89b21e3 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 @@ -109,6 +109,17 @@ public class AihrPracticeSeedServiceTest { assertEquals("缺少员工ID,无法派发专项训练", error.getMessage()); } + @Test + public void supervisorAssignmentSourceIsServerOwned() throws Exception { + String source = Files.readString(Path.of("src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java")); + int methodStart = source.indexOf("public PracticeAssignmentResponse createAssignment(PracticeAssignmentRequest request)"); + int methodEnd = source.indexOf("public PracticeAssignmentResponse createAssignment(PracticeAssignmentRequest request, String supervisorExtPartyId)", methodStart); + String method = source.substring(methodStart, methodEnd); + + assertTrue(method.contains("String source = \"manual\"")); + assertFalse(method.contains("request.source()")); + } + @Test public void newHireWindowUsesInclusiveThreeMonthBoundary() { LocalDate asOf = LocalDate.of(2026, 7, 14); diff --git a/docs/BRD_IMPLEMENTATION_AUDIT.md b/docs/BRD_IMPLEMENTATION_AUDIT.md index 606c5def..767f8f60 100644 --- a/docs/BRD_IMPLEMENTATION_AUDIT.md +++ b/docs/BRD_IMPLEMENTATION_AUDIT.md @@ -269,3 +269,4 @@ - 2026-07-14 BRD 6.3 SOP 来源标识修复:SOP 检索成功时前端原先忽略 API 返回的 `records`,后端返回的内置记录也没有来源字段,可能把演示文档显示成真实知识库;现 API 成功态只使用响应记录,内置记录明确标记 `source=demo`,失败/未检索态继续保留已有回退提示。未修改知识库数据或生产环境。 - 2026-07-14 当前线上资源复核:生产根站、`/h5/` 和 `/prod-api/auth/tenant/list` 均返回 `200`;线上管理端 `index-CJZ3Ax3Z.js` SHA-256 为 `8b9278a26ccb760abce489b12a20b221748c64d4c4153613d2511777bb9677bc`,当前分支构建 `index-B3bSjqdi.js` SHA-256 为 `2ff13b11307631f9cd672247d6d08e395fb674ac5b9c6f7c4fb27832eacdf075`;线上 H5 `index-D4-NrEpb.js` SHA-256 为 `ab15bfd17cabe58e2f34b0ac61ee198a837128ed85dc6bb0ddf77bc3e22dcd9c`,当前分支构建 `index-8gZKJTho.js` SHA-256 为 `c6b01faeba4198cb7ff9f5c2ffa88f1cc97c8ecdf20be86f432ca7a1d673f3e1`。本轮只读核验,未执行生产静态资源同步、后端重启或业务数据写入。 - 2026-07-14 BRD 4.4 场景派发覆盖复核:数据库已有 12 个生活顾问场景,但移动端主管“指派专项”和“复盘后再练”此前只提供 3 个静态场景,导致其余已启用场景无法从主管入口使用;现改为 API 优先加载已启用场景,失败时保留 3 个本地兜底。BRD 所称 7–14 天专项训练营目前仍只有 `source='camp'` 标签,没有训练营计划、天数、每日任务、进度和完成规则,需 HR 确认内容与运营口径后再实现,不以标签冒充训练营闭环。 +- 2026-07-14 BRD G3/M5 派发来源完整性复核:主管派发接口此前信任客户端 `source`,理论上可把手工派发伪装成 `daily`、`retry` 或 `camp`,污染每日题、低分再练和训练营统计;现将主管创建任务的来源固定为服务端 `manual`,`daily/retry` 仍只由各自系统路径生成。新增服务源码回归测试与 `demo-check` marker,未修改生产数据。 diff --git a/scripts/demo-check.sh b/scripts/demo-check.sh index 2f1ddaff..d75909fc 100755 --- a/scripts/demo-check.sh +++ b/scripts/demo-check.sh @@ -517,6 +517,7 @@ contains mobile-uni/src/pages/supervisor/review/index.vue "人工贡献分" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/controller/AihrMobileController.java "/practice/reviews/{id}/reviewed" contains mobile-uni/src/pages/supervisor/review/index.vue "标记已复盘" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "source = 'retry'" +contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java 'String source = "manual"' contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "isWithinNewHireWindow" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "allow-legacy-daily-drill-fallback" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "isLegacyDailyDrillFallbackEnabled"