fix(aihr): preserve dynamic tenant context

This commit is contained in:
2026-07-14 21:15:37 +08:00
parent 6dfbb1458d
commit bf4c069dd7
9 changed files with 52 additions and 11 deletions
@@ -1,7 +1,7 @@
package org.dromara.aihr.service;
import lombok.RequiredArgsConstructor;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.service.ISysOssService;
@@ -192,7 +192,7 @@ public class AihrCandidateMaterialService {
}
private String tenantId() {
String tenantId = LoginHelper.getTenantId();
String tenantId = TenantHelper.getTenantId();
return clean(tenantId, TENANT_ID);
}
@@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.aihr.domain.AihrCaseDto.CurateRequest;
import org.dromara.aihr.domain.AihrCaseDto.CurateResponse;
import org.dromara.aihr.domain.AihrCaseDto.DetailResponse;
@@ -300,7 +301,7 @@ public class AihrCaseService {
}
private String tenantId() {
return firstNonBlank(LoginHelper.getTenantId(), "000000");
return firstNonBlank(TenantHelper.getTenantId(), "000000");
}
private Optional<CaseSummary> organizeWithModel(CaseState state) {
@@ -9,7 +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.dromara.common.tenant.helper.TenantHelper;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.beans.factory.annotation.Value;
@@ -253,7 +253,7 @@ public class AihrDashboardService {
}
private String tenantId() {
String tenantId = LoginHelper.getTenantId();
String tenantId = TenantHelper.getTenantId();
return tenantId == null || tenantId.isBlank() ? TENANT_ID : tenantId;
}
@@ -5,7 +5,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.aihr.domain.AihrInterviewDto.AnswerRequest;
import org.dromara.aihr.domain.AihrInterviewDto.AnswerResponse;
import org.dromara.aihr.domain.AihrInterviewDto.CandidateLinkRequest;
@@ -310,7 +310,7 @@ public class AihrInterviewService {
}
private String tenantId() {
return firstNonBlank(LoginHelper.getTenantId(), "000000");
return firstNonBlank(TenantHelper.getTenantId(), "000000");
}
private void saveResult(String sessionId, InterviewSession session, ScoreResult score) {
@@ -9,7 +9,7 @@ import org.dromara.aihr.domain.AihrOrgSyncDto.OrgProjectOption;
import org.dromara.aihr.domain.AihrOrgSyncDto.OrgSnapshotResponse;
import org.dromara.aihr.domain.AihrOrgSyncDto.SyncRequest;
import org.dromara.aihr.domain.AihrOrgSyncDto.SyncResponse;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -763,7 +763,7 @@ public class AihrOrgSyncService {
}
private String tenantId() {
String tenantId = LoginHelper.getTenantId();
String tenantId = TenantHelper.getTenantId();
return clean(tenantId).isBlank() ? TENANT_ID : tenantId.trim();
}
}
@@ -47,7 +47,7 @@ import org.dromara.aihr.domain.AihrPracticeDto.TeamMemberResponse;
import org.dromara.aihr.service.AihrPracticeLlmService.PracticeTurn;
import org.dromara.aihr.service.AihrPracticeLlmService.DailyDrillAssessment;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataAccessException;
@@ -3957,7 +3957,7 @@ public class AihrPracticeSeedService {
}
private String tenantId() {
return firstNonBlank(LoginHelper.getTenantId(), TENANT_ID);
return firstNonBlank(TenantHelper.getTenantId(), TENANT_ID);
}
private String firstNonBlank(String first, String second) {
@@ -0,0 +1,36 @@
package org.dromara.aihr.service;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
@Tag("dev")
class AihrTenantContextContractTest {
@Test
void businessServicesUseDynamicTenantContext() throws Exception {
Path moduleRoot = Path.of("src/main/java/org/dromara/aihr/service");
if (!Files.exists(moduleRoot)) {
moduleRoot = Path.of("ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service");
}
for (String service : List.of(
"AihrCandidateMaterialService.java",
"AihrCaseService.java",
"AihrDashboardService.java",
"AihrInterviewService.java",
"AihrOrgSyncService.java",
"AihrPracticeSeedService.java"
)) {
String source = Files.readString(moduleRoot.resolve(service));
assertTrue(source.contains("TenantHelper.getTenantId()"), service);
assertFalse(source.contains("LoginHelper.getTenantId()"), service);
}
}
}
+1
View File
@@ -2,6 +2,7 @@
更新时间:2026-07-14
- 2026-07-14 BRD G3 多租户动态上下文修复:候选资料、案例、仪表盘、面试、组织同步和陪练服务此前从 `LoginHelper` 读取租户,后台 `TenantHelper.dynamic(...)` 场景可能回退到 `000000`;现统一改用 `TenantHelper.getTenantId()`,保留案例服务的 `LoginHelper` 仅用于当前操作人身份,并新增源码契约测试与 `demo-check` marker。未修改业务数据;正式多租户环境仍需跨租户 HTTP 回归。
- 2026-07-14 Figma/BRD 对账口径修正:`FIGMA_IMPLEMENTATION_MATRIX.md` 的 M2 总结此前仍把问答反馈写成视觉缺口;当前员工端问答反馈、状态提示和后端记录已在位,剩余仅为 Figma 画板中的收藏持久化契约与完整视觉状态复核,不把开放问题榜纳入本期。
- 2026-07-14 最新线上只读资源复核:生产根站、`/h5/` 和 `/prod-api/auth/tenant/list` 均返回 `200`;线上管理端仍加载 `assets/index-CJZ3Ax3Z.js`(SHA-256 `8b9278a26ccb760abce489b12a20b221748c64d4c4153613d2511777bb9677bc`),H5 仍加载 `assets/index-D4-NrEpb.js`(SHA-256 `ab15bfd17cabe58e2f34b0ac61ee198a837128ed85dc6bb0ddf77bc3e22dcd9c`);当前提交 `0de9704e` 重建后的本地资源为管理端 `assets/index-B9T505HT.js`(SHA-256 `66a827a7b3e5d794ae9da54c6e2276080995614fa52f54d49f746087663f8c94`)和 H5 `assets/index-CDn6TrX8.js`(SHA-256 `eecb4820f3887aceb952efe3e6f2210bab325be8b03f2813e6ec304c68b26f08`),两端仍未发布。本轮仅做 GET/hash 核验,未执行生产静态同步、后端重启或业务数据写入。
- 2026-07-14 BRD 5.4/G3 组织同步写入保护:`POST /api/aihr/org/sync` 现在要求请求显式传 `dryRun=true` 或 `dryRun=false`,省略请求体或传 `null` 会在外部拉取前直接拒绝,避免空请求因 `replaceExisting=true` 默认值意外写入组织快照;补充服务单测、`demo-check` marker 和 API 对接说明,未修改线上组织数据。
+3
View File
@@ -444,6 +444,9 @@ contains frontend/src/views/index.vue "不等于端到端验收"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrDashboardService.java "不等于端到端验收"
contains frontend/src/views/index.vue "正式试点身份待核对"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrDashboardService.java "正式试点身份待核对"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "TenantHelper.getTenantId()"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrOrgSyncService.java "TenantHelper.getTenantId()"
contains backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrTenantContextContractTest.java "businessServicesUseDynamicTenantContext"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrDashboardService.java "String traineeExpression = storeDisplayFields"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "String nameExpression = !storeDisplayFields"
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "PILOT_SESSION_ROWS_SQL.formatted(storeDisplayFields"