From c76c500dc7496222f519680db3884d63b1621440 Mon Sep 17 00:00:00 2001 From: let5sne Date: Tue, 14 Jul 2026 15:19:07 +0800 Subject: [PATCH] fix(aihr): align fallback scoring with BRD dimensions --- .../aihr/service/AihrPracticeSeedService.java | 44 ++++++++++--------- .../service/AihrPracticeSeedServiceTest.java | 15 +++++++ docs/BRD_IMPLEMENTATION_AUDIT.md | 1 + frontend/src/views/train/practice.vue | 18 ++++---- scripts/demo-check.sh | 2 + 5 files changed, 52 insertions(+), 28 deletions(-) diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java index 243231d1..45838ae4 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java @@ -717,18 +717,19 @@ public class AihrPracticeSeedService { } private PracticeResult seedPracticeResult(ActiveSession activeSession, ScenarioSeed scenario) { - int compliance = scoreValue(scenario.scores(), "合规", scenario.total()); - int communication = scoreValue(scenario.scores(), "沟通", scenario.total()); - int emotion = scoreValue(scenario.scores(), "情绪", scenario.total()); - int marketing = scoreValue(scenario.scores(), "营销", scenario.total()); - Integer response = responseTimelinessScore(activeSession); + int taskCompletion = scoreValue(scenario.scores(), "任务完成度", scenario.total()); + int standardization = scoreValue(scenario.scores(), "话术规范性", taskCompletion); + int emotion = scoreValue(scenario.scores(), "情绪管理能力", scenario.total()); + int marketing = scoreValue(scenario.scores(), "增值转化潜力", scenario.total()); + Integer response = scoreValue(scenario.scores(), "响应时效"); + response = response == null ? responseTimelinessScore(activeSession) : response; int total = response == null ? scenario.total() - : weightedPracticeScore(compliance, average(compliance, communication), emotion, response, marketing); + : weightedPracticeScore(taskCompletion, standardization, emotion, response, marketing); return new PracticeResult( total, - brdDimensions(compliance, average(compliance, communication), emotion, response, marketing), - scenario.rewrite(), scenario.summary(), compliance, communication, compliance, response, + brdDimensions(taskCompletion, standardization, emotion, response, marketing), + scenario.rewrite(), scenario.summary(), standardization, standardization, taskCompletion, response, averageResponseLatencyMs(activeSession) ); } @@ -3957,10 +3958,11 @@ public class AihrPracticeSeedService { private List defaultScores(String scenarioCode) { boolean feeScenario = !isBlank(scenarioCode) && scenarioCode.contains("fee"); return List.of( - new DimensionResponse("合规", feeScenario ? 82 : 84, "SOP关键点覆盖"), - new DimensionResponse("沟通", 84, "承诺与表达清晰度"), - new DimensionResponse("情绪", 82, "安抚与承接能力"), - new DimensionResponse("营销", feeScenario ? 80 : 76, "政策解释与办理引导") + new DimensionResponse("任务完成度", feeScenario ? 82 : 84, "SOP关键点覆盖;训练回退代理"), + new DimensionResponse("话术规范性", 84, "承诺与表达清晰度;训练回退代理"), + new DimensionResponse("情绪管理能力", 82, "安抚与承接能力;训练回退代理"), + new DimensionResponse("响应时效", "待采集", "无真实回合耗时证据时不回填"), + new DimensionResponse("增值转化潜力", feeScenario ? 80 : 76, "政策解释与办理引导;训练回退代理") ); } @@ -3998,10 +4000,11 @@ public class AihrPracticeSeedService { ) ), List.of( - new DimensionResponse("合规", 84, "有升级路径"), - new DimensionResponse("沟通", 88, "承诺清楚"), - new DimensionResponse("情绪", 82, "先承接诉求"), - new DimensionResponse("错题", "1条", "补费用争议") + new DimensionResponse("任务完成度", 84, "有升级路径;训练回退代理"), + new DimensionResponse("话术规范性", 86, "承诺清楚;训练回退代理"), + new DimensionResponse("情绪管理能力", 82, "先承接诉求"), + new DimensionResponse("响应时效", "待采集", "无真实回合耗时证据时不回填"), + new DimensionResponse("增值转化潜力", 76, "训练回退代理") ), 86, "建议表达为:“我先确认责任人和到场时间,10 分钟内回复您;如果今天无法完成,我同步主管给您替代方案和下一次反馈时间。”", @@ -4032,10 +4035,11 @@ public class AihrPracticeSeedService { ) ), List.of( - new DimensionResponse("合规", 80, "复核明确"), - new DimensionResponse("沟通", 83, "拆分得当"), - new DimensionResponse("情绪", 78, "安抚一般"), - new DimensionResponse("错题", "2条", "补开场安抚") + new DimensionResponse("任务完成度", 80, "复核明确;训练回退代理"), + new DimensionResponse("话术规范性", 82, "拆分得当;训练回退代理"), + new DimensionResponse("情绪管理能力", 78, "安抚一般"), + new DimensionResponse("响应时效", "待采集", "无真实回合耗时证据时不回填"), + new DimensionResponse("增值转化潜力", 80, "训练回退代理") ), 81, "建议先承接情绪:“您觉得服务不到位,我先把问题负责跟到底。”再说明缴费和整改并行,最后给出主管复核与反馈时间。", diff --git a/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrPracticeSeedServiceTest.java b/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrPracticeSeedServiceTest.java index 2846c8da..e2b87470 100644 --- a/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrPracticeSeedServiceTest.java +++ b/backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/service/AihrPracticeSeedServiceTest.java @@ -2,6 +2,7 @@ package org.dromara.aihr.service; import com.fasterxml.jackson.databind.ObjectMapper; import org.dromara.aihr.domain.AihrPracticeDto.CompetencyResponse; +import org.dromara.aihr.domain.AihrPracticeDto.DimensionResponse; import org.dromara.aihr.domain.AihrPracticeDto.FinishRequest; import org.dromara.aihr.domain.AihrPracticeDto.PracticeAssignmentRequest; import org.dromara.aihr.domain.AihrPracticeDto.ReviewAdviceRequest; @@ -131,6 +132,20 @@ public class AihrPracticeSeedServiceTest { assertTrue(result.isEmpty()); } + @Test + @SuppressWarnings("unchecked") + public void seedFallbackScoresUseBrdFiveDimensions() throws Exception { + AihrPracticeSeedService service = new AihrPracticeSeedService(new ObjectMapper(), null, null, null); + Method method = AihrPracticeSeedService.class.getDeclaredMethod("defaultScores", String.class); + method.setAccessible(true); + + List scores = (List) method.invoke(service, "fee-collection"); + + assertEquals(List.of("任务完成度", "话术规范性", "情绪管理能力", "响应时效", "增值转化潜力"), + scores.stream().map(DimensionResponse::label).toList()); + assertEquals("待采集", scores.get(3).value()); + } + @Test public void supervisorAssignmentSourceIsServerOwned() throws Exception { String source = Files.readString(Path.of("src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java")); diff --git a/docs/BRD_IMPLEMENTATION_AUDIT.md b/docs/BRD_IMPLEMENTATION_AUDIT.md index 7ab0fab9..04f1c180 100644 --- a/docs/BRD_IMPLEMENTATION_AUDIT.md +++ b/docs/BRD_IMPLEMENTATION_AUDIT.md @@ -293,4 +293,5 @@ - 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`),本地最新提交 `e0da5f0a` 尚未发布;本轮未执行生产同步、后端重启或业务数据写入。 - 2026-07-14 BRD 4.4 入职日期数据链路补齐:组织快照初始化 DDL、外部组织同步和旧库懒迁移现在统一保存 `hire_date`,每日三题在存在该字段但记录缺日期时仍只允许本地 `dev/local` 的显式训练次数兼容回退,生产不会用训练次数推断新员工;新增 MySQL 8 版本迁移与严格预检字段/身份门禁。未写入试点业务数据,正式环境仍需外部组织同步实际提供入职日期并执行迁移。 - 2026-07-14 BRD 4.5.1 五维评分规则数据对齐:对练 `/finish`、复盘、校准和画像代码已补齐任务完成度、话术规范性、情绪管理能力、响应时效、增值转化潜力五项;本轮同步 reset SQL、运行时 seed fallback 和现有生活顾问 Rubric 迁移为 40%/25%/20%/10%/5%,严格预检新增五维 Rubric 数量与权重和检查。任务完成度当前以 SOP 执行/问题推进代理,响应时效当前以陪练回合响应耗时代理;工单闭环率、首解率、正式首响/处理周期仍待业务系统与 HR 确认,未把代理指标宣称为正式绩效口径。迁移只改评分规则结构,不写训练、校准或 SOP 业务样本。 +- 2026-07-14 BRD 4.5.1 回退路径一致性修复:数据库异常或演示回退时,后端 seed 和管理端本地场景此前仍可能返回旧四维/错题卡;现统一返回 BRD 五维,缺少真实回合耗时的响应时效明确为“待采集”,不使用旧错题字段冒充评估维度。新增运行时回归测试与 `demo-check` marker,未修改业务数据。 - 2026-07-14 BRD 最新线上只读复核:生产根站与 `/h5/` 返回 `200`,线上仍加载管理端 `assets/index-CJZ3Ax3Z.js` 与 H5 `assets/index-D4-NrEpb.js`;当前本地提交 `94d483d3` 构建资源分别为 `assets/index-Cv2wI9UI.js`(SHA-256 `cd6e3eab4a684141ccd64617dcde4d99030c9c13f7da618c11e1709c04f244a0`)和 `assets/index-Dq7sfWZP.js`(SHA-256 `f8499e5f261cc06d02de275e285e4a7c946dd6ef54fd29b3a1c0bc7a9a689c3d`)。本轮只读核验,未执行生产静态资源同步、后端重启或业务数据写入;五维修复仍未被证明在线上生效。 diff --git a/frontend/src/views/train/practice.vue b/frontend/src/views/train/practice.vue index 1a2567b6..4e7c8a79 100644 --- a/frontend/src/views/train/practice.vue +++ b/frontend/src/views/train/practice.vue @@ -414,10 +414,11 @@ const fallbackScenarios: ScenarioSeed[] = [ } ], scores: [ - { label: '合规', value: 84, note: '有升级路径' }, - { label: '沟通', value: 88, note: '承诺清楚' }, - { label: '情绪', value: 82, note: '先承接诉求' }, - { label: '错题', value: '1条', note: '补费用争议' } + { label: '任务完成度', value: 84, note: '有升级路径;训练回退代理' }, + { label: '话术规范性', value: 86, note: '承诺清楚;训练回退代理' }, + { label: '情绪管理能力', value: 82, note: '先承接诉求' }, + { label: '响应时效', value: '待采集', note: '无真实回合耗时证据时不回填' }, + { label: '增值转化潜力', value: 76, note: '训练回退代理' } ], total: 86, rewrite: '建议表达为:“我先确认责任人和到场时间,10 分钟内回复您;如果今天无法完成,我同步主管给您替代方案和下一次反馈时间。”', @@ -446,10 +447,11 @@ const fallbackScenarios: ScenarioSeed[] = [ } ], scores: [ - { label: '合规', value: 80, note: '复核明确' }, - { label: '沟通', value: 83, note: '拆分得当' }, - { label: '情绪', value: 78, note: '安抚一般' }, - { label: '错题', value: '2条', note: '补开场安抚' } + { label: '任务完成度', value: 80, note: '复核明确;训练回退代理' }, + { label: '话术规范性', value: 82, note: '拆分得当;训练回退代理' }, + { label: '情绪管理能力', value: 78, note: '安抚一般' }, + { label: '响应时效', value: '待采集', note: '无真实回合耗时证据时不回填' }, + { label: '增值转化潜力', value: 80, note: '训练回退代理' } ], total: 81, rewrite: '建议先承接情绪:“您觉得服务不到位,我先把问题负责跟到底。”再说明缴费和整改并行,最后给出主管复核与反馈时间。', diff --git a/scripts/demo-check.sh b/scripts/demo-check.sh index d6d82a55..53125d87 100755 --- a/scripts/demo-check.sh +++ b/scripts/demo-check.sh @@ -497,6 +497,8 @@ contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/control contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "mobileCompletedCount" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "任务完成度" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "响应时效" +contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "new DimensionResponse(\"响应时效\", \"待采集\"" +contains frontend/src/views/train/practice.vue "label: '任务完成度'" contains backend/script/sql/aihr_practice_mysql8.sql "task_completion" contains backend/script/sql/update/aihr_20260714_practice_five_dimensions_mysql8.sql "aihr_brd_rubric_codes" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/domain/AihrPracticeDto.java "MistakeAggregateResponse"