diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java index 2965a36e..efe94483 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java @@ -238,7 +238,7 @@ public class AihrSopSeedService { throw new ServiceException("缺少片段ID"); } validateFeedbackFragmentOwnership(fragmentIds); - Long reviewId = normalizeFeedbackReviewId(request.reviewId()); + Long reviewId = normalizeFeedbackReviewId(request.reviewId(), queryText); ensureAnswerFeedbackTable(); String reviewStatus = "down".equals(verdict) ? "待复核" : "已复核"; Timestamp now = Timestamp.valueOf(java.time.LocalDateTime.now()); @@ -2119,7 +2119,7 @@ public class AihrSopSeedService { } } - private Long normalizeFeedbackReviewId(Long reviewId) { + private Long normalizeFeedbackReviewId(Long reviewId, String queryText) { if (reviewId == null || reviewId <= 0) { return null; } @@ -2127,8 +2127,8 @@ public class AihrSopSeedService { Integer count = jdbcTemplate.queryForObject(""" SELECT COUNT(*) FROM aihr_sop_answer_review - WHERE tenant_id = ? AND id = ? - """, Integer.class, tenantId(), reviewId); + WHERE tenant_id = ? AND id = ? AND query_text = ? + """, Integer.class, tenantId(), reviewId, truncate(AihrSensitiveText.forModel(queryText), 1000)); return count != null && count > 0 ? reviewId : null; } diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrSopSeedServiceTest.java b/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrSopSeedServiceTest.java index b3e4b6a2..55b8e55d 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrSopSeedServiceTest.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrSopSeedServiceTest.java @@ -187,8 +187,8 @@ public class AihrSopSeedServiceTest { } String code = Files.readString(source); - assertTrue(code.contains("Long reviewId = normalizeFeedbackReviewId(request.reviewId())")); - assertTrue(code.contains("WHERE tenant_id = ? AND id = ?")); + assertTrue(code.contains("Long reviewId = normalizeFeedbackReviewId(request.reviewId(), queryText)")); + assertTrue(code.contains("WHERE tenant_id = ? AND id = ? AND query_text = ?")); } private static AihrSopSeedService.KnowledgeHit hit(Long fragmentId, String title) { diff --git a/docs/BRD_IMPLEMENTATION_AUDIT.md b/docs/BRD_IMPLEMENTATION_AUDIT.md index 366f5f0e..bee41dc0 100644 --- a/docs/BRD_IMPLEMENTATION_AUDIT.md +++ b/docs/BRD_IMPLEMENTATION_AUDIT.md @@ -251,4 +251,5 @@ - 2026-07-14 BRD M5 导出指标语义复核:`formal_org_login_count` 原名会把按安全手机号映射统计的在职组织身份误读为登录次数;现统一更名为 `formal_org_identity_count`,统计 SQL 不变,CSV 契约、严格校验和验证脚本同步更新。AIHR 目标测试 `34/34`、CSV 契约测试 `5/5` 通过;不改变真实试点数据门槛,也未发布生产。 - 2026-07-14 BRD G3/M5 评审样本绕过复核:SOP 搜索的 `source=verify_demo_questions` 原由客户端直接控制,普通登录用户可借此跳过评审样本写入,稀释正式可用率分母;现仅超级管理员保留该内部验证来源,其他请求自动归一为普通 `knowledge_search`,并补预检标记与回归测试。未修改生产环境。 - 2026-07-14 M5 试点输出口径复核:严格预检的组织映射数量已与 CSV 的 `formal_org_identity_count` 统一显示为 `org_identity`,并同步行为测试断言;统计逻辑不变,避免把在职组织身份映射数误读为登录次数。未修改生产环境。 +- 2026-07-14 BRD 4.7/G3 反馈追溯复核:答案反馈原先只校验客户端传入的 `reviewId` 属于当前租户,可能把其他问题的同租户评审记录绑定到当前反馈;现同时校验评审记录中的脱敏问题文本与反馈问题一致,不一致时仅清空关联、不阻断正常反馈写入,并补源码契约与预检标记。未修改生产环境。 - 2026-07-14 线上只读核对:生产根站、`/h5/` 和 `/prod-api/auth/tenant/list` 均返回 `200`,线上仍加载管理端 `index-CJZ3Ax3Z.js` 与 H5 `index-D4-NrEpb.js`;本轮 `aa7e1508`、`5d85d63c` 两个 BRD 修复提交尚未发布。未执行生产同步、重启或业务数据写入。 diff --git a/scripts/demo-check.sh b/scripts/demo-check.sh index 3bb2e8ef..ce034c60 100755 --- a/scripts/demo-check.sh +++ b/scripts/demo-check.sh @@ -535,6 +535,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/AihrSopSeedService.java "hasExplicitSopReviewDecision" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java "validateFeedbackFragmentOwnership" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java "normalizeFeedbackReviewId" +contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java "AND query_text = ?" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrVideoService.java "处理输出已隐藏" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrUploadQueueService.java "资料加工失败,请重试或联系管理员" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java "目录导入失败,请重试或联系管理员"