fix(aihr): align growth path progress with criteria

This commit is contained in:
2026-07-09 16:01:14 +08:00
parent f1fe0bdfaa
commit bba1e00425
2 changed files with 41 additions and 3 deletions
@@ -856,12 +856,22 @@ public class AihrPracticeSeedService {
); );
} }
return List.of( return List.of(
new GrowthStageResponse("初级", Math.min(100, Math.max(30, completed * 10)), completed >= 3 ? "已达成" : "进行中", "完成3次基础场景并保持80分以上"), new GrowthStageResponse("初级", stageProgress(completed, 3, score, 80), stageStatus(completed, 3, score, 80, "进行中"), "完成3次基础场景并保持80分以上"),
new GrowthStageResponse("中级", Math.min(100, Math.max(0, completed * 6 + Math.max(0, score - 75))), completed >= 10 && score >= 85 ? "已达成" : "待积累", "完成10次训练且测评分达到85"), new GrowthStageResponse("中级", stageProgress(completed, 10, score, 85), stageStatus(completed, 10, score, 85, "待积累"), "完成10次训练且测评分达到85"),
new GrowthStageResponse("高级", Math.min(100, Math.max(0, completed * 4 + Math.max(0, score - 80))), completed >= 20 && score >= 90 ? "已达成" : "待积累", "完成20次训练、主管复盘稳定通过") new GrowthStageResponse("高级", stageProgress(completed, 20, score, 90), stageStatus(completed, 20, score, 90, "待积累"), "完成20次训练、主管复盘稳定通过")
); );
} }
private int stageProgress(int completed, int requiredCompleted, int score, int requiredScore) {
int completedProgress = Math.min(100, Math.round(completed * 100F / requiredCompleted));
int scoreProgress = Math.min(100, Math.round(score * 100F / requiredScore));
return Math.min(completedProgress, scoreProgress);
}
private String stageStatus(int completed, int requiredCompleted, int score, int requiredScore, String fallback) {
return completed >= requiredCompleted && score >= requiredScore ? "已达成" : fallback;
}
public List<PracticeAlertResponse> alerts() { public List<PracticeAlertResponse> alerts() {
ensurePracticeTable(); ensurePracticeTable();
int pending = countPendingReview(""); int pending = countPendingReview("");
@@ -136,6 +136,34 @@ public class AihrPracticeSeedServiceTest {
assertTrue(profile.growthPath().stream().allMatch(item -> Integer.valueOf(0).equals(item.progress()))); assertTrue(profile.growthPath().stream().allMatch(item -> Integer.valueOf(0).equals(item.progress())));
} }
@Test
public void competencyGrowthProgressStopsAtWeakRequirement() {
JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class);
when(jdbcTemplate.queryForObject(ArgumentMatchers.anyString(), eq(Integer.class), ArgumentMatchers.any(), ArgumentMatchers.any()))
.thenReturn(1);
when(jdbcTemplate.query(contains("COUNT(*) completed"), any(RowMapper.class), eq("000000"), eq("13900001001"), eq("13900001001")))
.thenAnswer(invocation -> mapOne(invocation, Map.of(
"completed", "33",
"score", "81",
"pending_review", "2",
"compliance", "82",
"communication", "80",
"emotion", "78",
"incentive_points", "20"
)));
AihrPracticeSeedService service = new AihrPracticeSeedService(new ObjectMapper(), jdbcTemplate, null, null);
CompetencyResponse profile = service.competency("13900001001");
assertEquals("初级", profile.aiLevel());
assertEquals(100, profile.growthPath().get(0).progress());
assertEquals("已达成", profile.growthPath().get(0).status());
assertEquals(95, profile.growthPath().get(1).progress());
assertEquals("待积累", profile.growthPath().get(1).status());
assertEquals(90, profile.growthPath().get(2).progress());
assertEquals("待积累", profile.growthPath().get(2).status());
}
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
private static <T> List<T> mapOne(InvocationOnMock invocation, Map<String, String> values) throws SQLException { private static <T> List<T> mapOne(InvocationOnMock invocation, Map<String, String> values) throws SQLException {
RowMapper mapper = invocation.getArgument(1); RowMapper mapper = invocation.getArgument(1);