fix(aihr): scope pilot SOP metrics

This commit is contained in:
2026-07-14 11:20:12 +08:00
parent 87517e5718
commit 88702867b8
5 changed files with 26 additions and 8 deletions
@@ -1933,6 +1933,7 @@ public class AihrSopSeedService {
SELECT COUNT(*) AS total, COALESCE(SUM(CASE WHEN usable = 1 THEN 1 ELSE 0 END), 0) AS usable SELECT COUNT(*) AS total, COALESCE(SUM(CASE WHEN usable = 1 THEN 1 ELSE 0 END), 0) AS usable
FROM aihr_sop_answer_review FROM aihr_sop_answer_review
WHERE tenant_id = ? AND status = '已评审' WHERE tenant_id = ? AND status = '已评审'
AND (LOWER(TRIM(COALESCE(category, ''))) = 'sop' OR category LIKE '%SOP%')
""", (rs, rowNum) -> new SopReviewStats(rs.getInt("total"), rs.getInt("usable")), tenantId()); """, (rs, rowNum) -> new SopReviewStats(rs.getInt("total"), rs.getInt("usable")), tenantId());
} }
@@ -1946,6 +1947,7 @@ public class AihrSopSeedService {
SELECT COUNT(*) AS total, COALESCE(SUM(CASE WHEN usable = 1 THEN 1 ELSE 0 END), 0) AS usable SELECT COUNT(*) AS total, COALESCE(SUM(CASE WHEN usable = 1 THEN 1 ELSE 0 END), 0) AS usable
FROM aihr_sop_answer_review FROM aihr_sop_answer_review
WHERE tenant_id = ? AND status = '已评审' WHERE tenant_id = ? AND status = '已评审'
AND (LOWER(TRIM(COALESCE(category, ''))) = 'sop' OR category LIKE '%SOP%')
AND reviewed_time >= ? AND reviewed_time < ? AND reviewed_time >= ? AND reviewed_time < ?
""", (rs, rowNum) -> new SopReviewStats(rs.getInt("total"), rs.getInt("usable")), """, (rs, rowNum) -> new SopReviewStats(rs.getInt("total"), rs.getInt("usable")),
tenantId(), Timestamp.valueOf(startTime), Timestamp.valueOf(endTime)); tenantId(), Timestamp.valueOf(startTime), Timestamp.valueOf(endTime));
@@ -53,6 +53,19 @@ public class AihrSopSeedServiceTest {
assertTrue(AihrSopSeedService.hasExplicitSopReviewDecision(new AihrSopDto.SopReviewRequest(false, null, null))); assertTrue(AihrSopSeedService.hasExplicitSopReviewDecision(new AihrSopDto.SopReviewRequest(false, null, null)));
} }
@Test
@Tag("dev")
public void pilotSopStatsScopeToSopCategories() throws Exception {
Path source = Path.of("src/main/java/org/dromara/aihr/service/AihrSopSeedService.java");
if (!Files.exists(source)) {
source = Path.of("ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrSopSeedService.java");
}
String code = Files.readString(source);
assertTrue(code.contains("LOWER(TRIM(COALESCE(category, ''))) = 'sop'"));
assertTrue(code.contains("category LIKE '%SOP%'"));
}
@Test @Test
@Tag("dev") @Tag("dev")
public void evidenceHitsKeepsNamedDocumentOnly() { public void evidenceHitsKeepsNamedDocumentOnly() {
+1
View File
@@ -189,3 +189,4 @@
- 2026-07-14 BRD 4.6 案例发布状态复核:员工端案例列表和详情原先只按租户/项目范围读取,未限制案例状态,理论上可能看到仍处于“已转写/已整理”的管理流程半成品;现对 APP 项目范围读取增加 `status='已入库'`,管理端 HR/管理员仍可查看全部状态以继续处理。新增案例服务回归测试,AIHR 全量测试 `81/81` 通过;视频样片、学习点和主管点评仍需正式业务输入。 - 2026-07-14 BRD 4.6 案例发布状态复核:员工端案例列表和详情原先只按租户/项目范围读取,未限制案例状态,理论上可能看到仍处于“已转写/已整理”的管理流程半成品;现对 APP 项目范围读取增加 `status='已入库'`,管理端 HR/管理员仍可查看全部状态以继续处理。新增案例服务回归测试,AIHR 全量测试 `81/81` 通过;视频样片、学习点和主管点评仍需正式业务输入。
- 2026-07-14 BRD 案例提交能力边界复核:移动端案例页原先对所有登录员工展示“提交素材”表单,但后端仅允许主管/项目负责人提交,普通员工点击后才得到权限错误;现新增只读 `GET /api/knowledge/case/capabilities`,复用服务端唯一贡献者判定,员工端仅在 `canSubmit=true` 时展示提交入口,其他员工显示案例学习说明。后端权限仍保留为最终防线。 - 2026-07-14 BRD 案例提交能力边界复核:移动端案例页原先对所有登录员工展示“提交素材”表单,但后端仅允许主管/项目负责人提交,普通员工点击后才得到权限错误;现新增只读 `GET /api/knowledge/case/capabilities`,复用服务端唯一贡献者判定,员工端仅在 `canSubmit=true` 时展示提交入口,其他员工显示案例学习说明。后端权限仍保留为最终防线。
- 2026-07-14 线上只读发布差异:生产根站和 `/h5/` 返回 `200`,生产仍加载 H5 `assets/index-D4-NrEpb.js`;本地 `b8be1bb6` 构建已生成 `mobile-uni/dist/build/h5/assets/index-u8NWYNWX.js`,案例状态过滤和提交能力入口尚未发布。本轮未执行生产静态资源同步、后端重启或业务数据写入。 - 2026-07-14 线上只读发布差异:生产根站和 `/h5/` 返回 `200`,生产仍加载 H5 `assets/index-D4-NrEpb.js`;本地 `b8be1bb6` 构建已生成 `mobile-uni/dist/build/h5/assets/index-u8NWYNWX.js`,案例状态过滤和提交能力入口尚未发布。本轮未执行生产静态资源同步、后端重启或业务数据写入。
- 2026-07-14 BRD 4.7 SOP 指标口径复核:正式试点的 SOP 可用率与待评审数现只统计评审表中 `category='sop'` 或名称包含 `SOP` 的记录,并继续按租户和试点日期窗口过滤;培训类或其他知识问答不会混入正式 SOP 分母。后端导出、严格预检和单测夹具已统一该条件;岗位与住宅项目的正式适用性仍需组织/HR 规则输入,不能仅靠分类字符串替代。
+3 -3
View File
@@ -245,9 +245,9 @@ check_pilot_samples() {
JOIN latest_calibration latest ON latest.id = c.id JOIN latest_calibration latest ON latest.id = c.id
WHERE c.tenant_id = '$pilot_tenant'")" WHERE c.tenant_id = '$pilot_tenant'")"
read -r calibration_count calibration_matched <<<"$calibration_stats" read -r calibration_count calibration_matched <<<"$calibration_stats"
sop_total="$(pilot_sql_scalar "SELECT COUNT(*) FROM aihr_sop_answer_review WHERE tenant_id = '$pilot_tenant' AND status = '已评审' AND reviewed_time >= '${pilot_start} 00:00:00' AND reviewed_time < DATE_ADD('${pilot_end}', INTERVAL 1 DAY)")" sop_total="$(pilot_sql_scalar "SELECT COUNT(*) FROM aihr_sop_answer_review WHERE tenant_id = '$pilot_tenant' AND status = '已评审' AND (LOWER(TRIM(COALESCE(category, ''))) = 'sop' OR category LIKE '%SOP%') AND reviewed_time >= '${pilot_start} 00:00:00' AND reviewed_time < DATE_ADD('${pilot_end}', INTERVAL 1 DAY)")"
sop_usable="$(pilot_sql_scalar "SELECT COALESCE(SUM(CASE WHEN usable = 1 THEN 1 ELSE 0 END), 0) FROM aihr_sop_answer_review WHERE tenant_id = '$pilot_tenant' AND status = '已评审' AND reviewed_time >= '${pilot_start} 00:00:00' AND reviewed_time < DATE_ADD('${pilot_end}', INTERVAL 1 DAY)")" sop_usable="$(pilot_sql_scalar "SELECT COALESCE(SUM(CASE WHEN usable = 1 THEN 1 ELSE 0 END), 0) FROM aihr_sop_answer_review WHERE tenant_id = '$pilot_tenant' AND status = '已评审' AND (LOWER(TRIM(COALESCE(category, ''))) = 'sop' OR category LIKE '%SOP%') AND reviewed_time >= '${pilot_start} 00:00:00' AND reviewed_time < DATE_ADD('${pilot_end}', INTERVAL 1 DAY)")"
sop_pending="$(pilot_sql_scalar "SELECT COUNT(*) FROM aihr_sop_answer_review WHERE tenant_id = '$pilot_tenant' AND status <> '已评审' AND create_time >= '${pilot_start} 00:00:00' AND create_time < DATE_ADD('${pilot_end}', INTERVAL 1 DAY)")" sop_pending="$(pilot_sql_scalar "SELECT COUNT(*) FROM aihr_sop_answer_review WHERE tenant_id = '$pilot_tenant' AND status <> '已评审' AND (LOWER(TRIM(COALESCE(category, ''))) = 'sop' OR category LIKE '%SOP%') AND create_time >= '${pilot_start} 00:00:00' AND create_time < DATE_ADD('${pilot_end}', INTERVAL 1 DAY)")"
satisfaction_count="$(pilot_sql_scalar " satisfaction_count="$(pilot_sql_scalar "
$org_identity_cte, $org_identity_cte,
formal_sessions AS ( formal_sessions AS (
+7 -5
View File
@@ -72,7 +72,7 @@ CREATE TABLE aihr_practice_calibration (
original_score int, corrected_score int, create_time datetime original_score int, corrected_score int, create_time datetime
); );
CREATE TABLE aihr_sop_answer_review ( CREATE TABLE aihr_sop_answer_review (
tenant_id varchar(20), status varchar(30), usable tinyint, tenant_id varchar(20), category varchar(100), status varchar(30), usable tinyint,
reviewed_time datetime, create_time datetime reviewed_time datetime, create_time datetime
); );
@@ -133,10 +133,12 @@ INSERT INTO aihr_practice_calibration (tenant_id,session_id,original_score,corre
('000000','unsafe-inside',80,40,'2026-07-08 11:00:00'), ('000000','unsafe-inside',80,40,'2026-07-08 11:00:00'),
('000000','e-out',80,40,'2026-07-06 11:00:00'); ('000000','e-out',80,40,'2026-07-06 11:00:00');
INSERT INTO aihr_sop_answer_review VALUES INSERT INTO aihr_sop_answer_review VALUES
('000000','已评审',1,'2026-07-08 12:00:00','2026-07-08 11:00:00'), ('000000','sop','已评审',1,'2026-07-08 12:00:00','2026-07-08 11:00:00'),
('000000','已评审',0,'2026-07-06 12:00:00','2026-07-06 11:00:00'), ('000000','sop','已评审',0,'2026-07-06 12:00:00','2026-07-06 11:00:00'),
('000000','待评审',NULL,NULL,'2026-07-08 13:00:00'), ('000000','sop','待评审',NULL,NULL,'2026-07-08 13:00:00'),
('000000','待评审',NULL,NULL,'2026-07-06 13:00:00'); ('000000','training','已评审',0,'2026-07-08 12:30:00','2026-07-08 11:30:00'),
('000000','training','待评审',NULL,NULL,'2026-07-08 13:00:00'),
('000000','training','待评审',NULL,NULL,'2026-07-06 13:00:00');
SQL SQL
export AIHR_PILOT_DB="$TEST_DB" export AIHR_PILOT_DB="$TEST_DB"