diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrModelSeedService.java b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrModelSeedService.java index 2a37d7f8..85b5bf36 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrModelSeedService.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrModelSeedService.java @@ -14,6 +14,7 @@ import org.dromara.aihr.domain.AihrModelDto.ConfigResponse; import org.dromara.aihr.domain.AihrModelDto.ProviderRequest; import org.dromara.aihr.domain.AihrModelDto.ProviderResponse; import org.dromara.aihr.domain.AihrModelDto.ProviderStatusRequest; +import org.dromara.common.satoken.utils.LoginHelper; import org.springframework.beans.factory.annotation.Value; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; @@ -117,7 +118,7 @@ public class AihrModelSeedService { insert into aihr_model_provider (tenant_id, provider_name, provider_code, provider_desc, api_host, api_key, status, sort_order, remark, create_time, update_time) values (?, ?, ?, ?, ?, ?, ?, ?, ?, now(), now()) - """, TENANT_ID, data.providerName(), data.providerCode(), data.providerDesc(), data.apiHost(), emptyToNull(request.apiKey()), + """, tenantId(), data.providerName(), data.providerCode(), data.providerDesc(), data.apiHost(), emptyToNull(request.apiKey()), data.status(), data.sortOrder(), data.remark()); } @@ -131,7 +132,7 @@ public class AihrModelSeedService { status = ?, sort_order = ?, remark = ?, update_time = now() where tenant_id = ? and provider_code = ? """, data.providerName(), data.providerDesc(), data.apiHost(), emptyToNull(request.apiKey()), emptyToNull(request.apiKey()), - data.status(), data.sortOrder(), data.remark(), TENANT_ID, code); + data.status(), data.sortOrder(), data.remark(), tenantId(), code); requireUpdated(updated, "供应商不存在: " + code); } @@ -142,7 +143,7 @@ public class AihrModelSeedService { update aihr_model_provider set status = ?, update_time = now() where tenant_id = ? and provider_code = ? - """, status, TENANT_ID, code); + """, status, tenantId(), code); requireUpdated(updated, "供应商不存在: " + code); } @@ -152,7 +153,7 @@ public class AihrModelSeedService { insert into aihr_model_config (tenant_id, category, model_name, provider_code, model_describe, model_dimension, model_show, api_host, api_key, enabled, remark, create_time, update_time) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, now(), now()) - """, TENANT_ID, data.category(), data.modelName(), data.providerCode(), data.modelDescribe(), data.modelDimension(), + """, tenantId(), data.category(), data.modelName(), data.providerCode(), data.modelDescribe(), data.modelDimension(), data.modelShow(), data.apiHost(), emptyToNull(request.apiKey()), data.enabled(), data.remark()); } @@ -168,7 +169,7 @@ public class AihrModelSeedService { enabled = ?, remark = ?, update_time = now() where tenant_id = ? and id = ? """, data.category(), data.modelName(), data.providerCode(), data.modelDescribe(), data.modelDimension(), data.modelShow(), - data.apiHost(), emptyToNull(request.apiKey()), emptyToNull(request.apiKey()), data.enabled(), data.remark(), TENANT_ID, id); + data.apiHost(), emptyToNull(request.apiKey()), emptyToNull(request.apiKey()), data.enabled(), data.remark(), tenantId(), id); requireUpdated(updated, "模型不存在: " + id); } @@ -181,7 +182,7 @@ public class AihrModelSeedService { update aihr_model_config set enabled = ?, update_time = now() where tenant_id = ? and id = ? - """, enabled, TENANT_ID, id); + """, enabled, tenantId(), id); requireUpdated(updated, "模型不存在: " + id); } @@ -257,7 +258,7 @@ public class AihrModelSeedService { rs.getString("model_name"), rs.getString("resolved_api_host"), rs.getString("resolved_api_key") - ), TENANT_ID, category); + ), tenantId(), category); return rows.stream() .filter(model -> configured(model.baseUrl(), model.modelName(), model.apiKey())) .findFirst(); @@ -315,7 +316,7 @@ public class AihrModelSeedService { rs.getObject("sort_order", Integer.class), "db", configured(rs.getString("api_host"), "model", rs.getString("api_key")) - ), TENANT_ID); + ), tenantId()); } catch (DataAccessException e) { log.debug("aihr model provider db fallback: {}", e.getMessage()); return List.of(); @@ -346,7 +347,7 @@ public class AihrModelSeedService { rs.getInt("enabled") == 1, !isBlank(rs.getString("resolved_api_key")), configured(rs.getString("resolved_api_host"), rs.getString("model_name"), rs.getString("resolved_api_key")) - ), TENANT_ID); + ), tenantId()); } catch (DataAccessException e) { log.debug("aihr model config db fallback: {}", e.getMessage()); return List.of(); @@ -451,8 +452,12 @@ public class AihrModelSeedService { """; } - private static Object[] runtimeArgs(String requestedModel) { - return isBlank(requestedModel) ? new Object[]{TENANT_ID} : new Object[]{TENANT_ID, requestedModel}; + private Object[] runtimeArgs(String requestedModel) { + return isBlank(requestedModel) ? new Object[]{tenantId()} : new Object[]{tenantId(), requestedModel}; + } + + private String tenantId() { + return fallback(LoginHelper.getTenantId(), TENANT_ID); } private static String normalizeBaseUrl(String baseUrl) { diff --git a/docs/BRD_IMPLEMENTATION_AUDIT.md b/docs/BRD_IMPLEMENTATION_AUDIT.md index 79a51929..d1d982fc 100644 --- a/docs/BRD_IMPLEMENTATION_AUDIT.md +++ b/docs/BRD_IMPLEMENTATION_AUDIT.md @@ -92,4 +92,4 @@ - 2026-07-14 生产 schema 修复:使用生产 `/opt/wygj/config/wygj.env` 中的数据库连接配置核对后,按仓库现有 `aihr_practice_mysql8.sql`/运行时建表定义执行 `CREATE TABLE IF NOT EXISTS`,补齐缺失的 `aihr_practice_audio`(9 列)和 `aihr_practice_calibration`(11 列);未写入任何业务行、未新增自定义字段。复核结果为 `org_active=22`、`org_phone_linked=0`、`calibration=0`、`sop_review=13`、`audio=0`,租户接口仍返回 200。该操作只解除 schema 漂移阻塞,不代表正式组织映射或 M5 试点完成。 - 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 租户边界复核:AI 面试结果、候选人入职主体关联、候选人补充资料、模型配置和案例记录的查询、写入、组织身份解析均改为使用当前登录租户;无登录上下文时仅保留本地开发默认租户 `000000` 回退。该修复已覆盖案例服务的列表、详情、项目范围、贡献者校验、保存和持久化回读路径,仍需在正式多租户环境做隔离回归。