diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrDashboardService.java b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrDashboardService.java index 6c14cb26..381dc6e4 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrDashboardService.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrDashboardService.java @@ -9,6 +9,7 @@ import org.dromara.aihr.domain.AihrDashboardDto.PipelineSummaryResponse; import org.dromara.aihr.domain.AihrDashboardDto.RiskResponse; import org.dromara.aihr.domain.AihrDashboardDto.StageResponse; import org.dromara.aihr.domain.AihrDashboardDto.TrainingRecordResponse; +import org.dromara.common.satoken.utils.LoginHelper; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; @@ -80,7 +81,7 @@ public class AihrDashboardService { if (!tableExists("aihr_interview_result")) { return new InterviewStats(0); } - return new InterviewStats(count("SELECT COUNT(*) FROM aihr_interview_result WHERE tenant_id = ?", TENANT_ID)); + return new InterviewStats(count("SELECT COUNT(*) FROM aihr_interview_result WHERE tenant_id = ?", tenantId())); } private List risks(PracticeStats practice, KnowledgeStats knowledge, CandidateStats candidate, ModelStats models) { @@ -113,7 +114,7 @@ public class AihrDashboardService { WHERE tenant_id = ? AND finished_time IS NOT NULL ORDER BY finished_time DESC, id DESC LIMIT 5 - """, this::trainingRecord, TENANT_ID); + """, this::trainingRecord, tenantId()); } catch (DataAccessException e) { return List.of(); } @@ -143,7 +144,7 @@ public class AihrDashboardService { SUM(CASE WHEN DATE(finished_time) = CURRENT_DATE THEN 1 ELSE 0 END) today FROM aihr_practice_session WHERE tenant_id = ? AND finished_time IS NOT NULL - """, (rs, rowNum) -> new PracticeStats(rs.getInt("total"), rs.getInt("pending_review"), rs.getInt("today")), TENANT_ID); + """, (rs, rowNum) -> new PracticeStats(rs.getInt("total"), rs.getInt("pending_review"), rs.getInt("today")), tenantId()); } catch (DataAccessException e) { return new PracticeStats(0, 0, 0); } @@ -154,9 +155,9 @@ public class AihrDashboardService { return new KnowledgeStats(0, 0, 0); } return new KnowledgeStats( - count("SELECT COUNT(*) FROM aihr_knowledge_attach WHERE tenant_id = ?", TENANT_ID), - count("SELECT COUNT(*) FROM aihr_knowledge_attach WHERE tenant_id = ? AND status = 2", TENANT_ID), - count("SELECT COUNT(*) FROM aihr_knowledge_fragment WHERE tenant_id = ?", TENANT_ID) + count("SELECT COUNT(*) FROM aihr_knowledge_attach WHERE tenant_id = ?", tenantId()), + count("SELECT COUNT(*) FROM aihr_knowledge_attach WHERE tenant_id = ? AND status = 2", tenantId()), + count("SELECT COUNT(*) FROM aihr_knowledge_fragment WHERE tenant_id = ?", tenantId()) ); } @@ -179,7 +180,7 @@ public class AihrDashboardService { rs.getInt("organized"), rs.getInt("stored"), rs.getInt("today_new") - ), TENANT_ID); + ), tenantId()); } catch (DataAccessException e) { return new CaseStats(0, 0, 0, 0, 0); } @@ -195,7 +196,7 @@ public class AihrDashboardService { SUM(CASE WHEN status = '待审核' THEN 1 ELSE 0 END) pending FROM aihr_candidate_material WHERE tenant_id = ? - """, (rs, rowNum) -> new CandidateStats(rs.getInt("total"), rs.getInt("pending")), TENANT_ID); + """, (rs, rowNum) -> new CandidateStats(rs.getInt("total"), rs.getInt("pending")), tenantId()); } catch (DataAccessException e) { return new CandidateStats(0, 0); } @@ -209,7 +210,7 @@ public class AihrDashboardService { SELECT COUNT(*) FROM aihr_org_snapshot WHERE tenant_id = ? AND employment_status = 'active' - """, TENANT_ID)); + """, tenantId())); } private ModelStats modelStats() { @@ -220,7 +221,7 @@ public class AihrDashboardService { SELECT COUNT(*) FROM aihr_model_config WHERE tenant_id = ? AND category = 'asr' AND enabled = 1 - """, TENANT_ID) > 0); + """, tenantId()) > 0); } private boolean tableExists(String tableName) { @@ -245,6 +246,11 @@ public class AihrDashboardService { } } + private String tenantId() { + String tenantId = LoginHelper.getTenantId(); + return tenantId == null || tenantId.isBlank() ? TENANT_ID : tenantId; + } + private static String statusState(String status, int score) { if (score > 0 && score < 70) { return "danger"; diff --git a/docs/BRD_IMPLEMENTATION_AUDIT.md b/docs/BRD_IMPLEMENTATION_AUDIT.md index d1d982fc..99656995 100644 --- a/docs/BRD_IMPLEMENTATION_AUDIT.md +++ b/docs/BRD_IMPLEMENTATION_AUDIT.md @@ -93,3 +93,4 @@ - 2026-07-14 候选人关联发布边界核对:生产根站点与 `/h5/` 返回 200,`wygj-aihr.service` active,线上后端仍为上一版 jar;远端管理端主 JS 未包含本批 `入职主体关联/candidate-links`,本批源码已提交但尚未发布。后续发布需按现有备份、静态资源同步、后端重启和浏览器回归流程执行。 - 2026-07-14 门禁合同复核:`scripts/tests/demo-check-pilot-gates.test.sh` 通过,确认严格预检覆盖批次日期、唯一在职身份、1–2 个项目、每人至少 10 次训练、80% 完训、20 条校准、AI/人工分档一致率、SOP 可用率、满意度和音频/RAG schema;`scripts/tests/pilot-export-contract.test.mjs` 5/5 通过,AIHR 案例/对练定向测试 31/31 通过,`mobile-uni` 类型检查与 49 个单测通过。当前没有新增可安全实现的门禁缺口,剩余阻塞仍是正式组织映射、正式试点数据、视频样片和方言样本等外部输入。 - 2026-07-14 租户边界复核:AI 面试结果、候选人入职主体关联、候选人补充资料、模型配置和案例记录的查询、写入、组织身份解析均改为使用当前登录租户;无登录上下文时仅保留本地开发默认租户 `000000` 回退。该修复已覆盖案例服务的列表、详情、项目范围、贡献者校验、保存和持久化回读路径,仍需在正式多租户环境做隔离回归。 +- 2026-07-14 仪表盘租户边界复核:管理端首页的面试、训练、知识库、案例、候选资料、组织和模型统计改为按当前登录租户查询;无登录上下文时保留本地开发默认租户回退。尚未把批量知识处理队列和完整 SOP 服务的全部租户调用统一替换,后续继续按数据敏感度分批审查。