feat(aihr): add supervisor mistake aggregation
This commit is contained in:
+13
-1
@@ -162,6 +162,17 @@ public final class AihrPracticeDto {
|
||||
) {
|
||||
}
|
||||
|
||||
public record MistakeAggregateResponse(
|
||||
String scenarioId,
|
||||
String scenarioName,
|
||||
String cause,
|
||||
Integer count,
|
||||
Integer affectedPeople,
|
||||
Integer averageScore,
|
||||
String latestTime
|
||||
) {
|
||||
}
|
||||
|
||||
public record DialogueResponse(String role, String label, String text, String audioUrl, Long audioOssId, Integer emotion, Integer trust, Boolean redFlag, String coachHint) {
|
||||
public DialogueResponse(String role, String label, String text) {
|
||||
this(role, label, text, "", null, null, null, null, "");
|
||||
@@ -260,7 +271,8 @@ public final class AihrPracticeDto {
|
||||
public record PracticeTeamResponse(
|
||||
List<TeamMemberResponse> members,
|
||||
List<RecordResponse> records,
|
||||
List<PracticeAssignmentResponse> assignments
|
||||
List<PracticeAssignmentResponse> assignments,
|
||||
List<MistakeAggregateResponse> mistakes
|
||||
) {
|
||||
}
|
||||
|
||||
|
||||
+55
-2
@@ -26,6 +26,7 @@ import org.dromara.aihr.domain.AihrPracticeDto.PromptTemplateResponse;
|
||||
import org.dromara.aihr.domain.AihrPracticeDto.PromotionEvidenceResponse;
|
||||
import org.dromara.aihr.domain.AihrPracticeDto.RecordResponse;
|
||||
import org.dromara.aihr.domain.AihrPracticeDto.MistakeResponse;
|
||||
import org.dromara.aihr.domain.AihrPracticeDto.MistakeAggregateResponse;
|
||||
import org.dromara.aihr.domain.AihrPracticeDto.ReviewAdviceRequest;
|
||||
import org.dromara.aihr.domain.AihrPracticeDto.ReviewDetailResponse;
|
||||
import org.dromara.aihr.domain.AihrPracticeDto.RubricDimensionResponse;
|
||||
@@ -799,12 +800,13 @@ public class AihrPracticeSeedService {
|
||||
TeamScope scope = teamScope(supervisorExtPartyId);
|
||||
int safeLimit = normalizeTeamLimit(limit);
|
||||
if (scope.scoped() && scope.extPartyIds().isEmpty()) {
|
||||
return new PracticeTeamResponse(List.of(), List.of(), List.of());
|
||||
return new PracticeTeamResponse(List.of(), List.of(), List.of(), List.of());
|
||||
}
|
||||
return new PracticeTeamResponse(
|
||||
practiceTeamMembers(scope),
|
||||
practiceTeamRecords(scope, safeLimit),
|
||||
practiceTeamAssignments(scope, safeLimit)
|
||||
practiceTeamAssignments(scope, safeLimit),
|
||||
practiceTeamMistakes(scope, safeLimit)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -920,6 +922,57 @@ public class AihrPracticeSeedService {
|
||||
return jdbcTemplate.query(sql, this::mapAssignment, args.toArray());
|
||||
}
|
||||
|
||||
private List<MistakeAggregateResponse> practiceTeamMistakes(TeamScope scope, int limit) {
|
||||
ensurePracticeTable();
|
||||
List<Object> args = new ArrayList<>();
|
||||
args.add(TENANT_ID);
|
||||
StringBuilder where = new StringBuilder("WHERE tenant_id = ? AND mode = 'mobile' AND finished_time IS NOT NULL");
|
||||
if (scope.scoped()) {
|
||||
where.append(" AND ext_party_id IN (").append(inClause(scope.extPartyIds().size())).append(")");
|
||||
args.addAll(scope.extPartyIds());
|
||||
}
|
||||
args.add(limit);
|
||||
String sql = """
|
||||
SELECT scenario_id,
|
||||
scenario_name,
|
||||
cause,
|
||||
COUNT(*) AS mistake_count,
|
||||
COUNT(DISTINCT NULLIF(ext_party_id, '')) AS affected_people,
|
||||
ROUND(AVG(COALESCE(total_score, 0))) AS average_score,
|
||||
MAX(finished_time) AS latest_time
|
||||
FROM (
|
||||
SELECT scenario_id,
|
||||
COALESCE(NULLIF(scenario_name, ''), '场景训练') AS scenario_name,
|
||||
ext_party_id,
|
||||
total_score,
|
||||
finished_time,
|
||||
CASE
|
||||
WHEN dialogue_json LIKE '%%"redFlag":true%%' THEN '红线话术'
|
||||
WHEN COALESCE(dim_emotion, 100) < 60 THEN '情绪承接'
|
||||
WHEN COALESCE(dim_compliance, 100) < 60 THEN '流程合规'
|
||||
ELSE '综合得分不足'
|
||||
END AS cause
|
||||
FROM aihr_practice_session
|
||||
%s
|
||||
AND (total_score < 80 OR dialogue_json LIKE '%%"redFlag":true%%')
|
||||
) mistake_rows
|
||||
GROUP BY scenario_id, scenario_name, cause
|
||||
ORDER BY mistake_count DESC, latest_time DESC, scenario_name, cause
|
||||
LIMIT ?
|
||||
""".formatted(where);
|
||||
return jdbcTemplate.query(sql, (rs, rowNum) -> new MistakeAggregateResponse(
|
||||
rs.getString("scenario_id"),
|
||||
firstNonBlank(rs.getString("scenario_name"), "场景训练"),
|
||||
firstNonBlank(rs.getString("cause"), "综合得分不足"),
|
||||
rs.getInt("mistake_count"),
|
||||
rs.getInt("affected_people"),
|
||||
rs.getInt("average_score"),
|
||||
rs.getTimestamp("latest_time") == null
|
||||
? ""
|
||||
: rs.getTimestamp("latest_time").toLocalDateTime().format(TIME_FORMATTER)
|
||||
), args.toArray());
|
||||
}
|
||||
|
||||
public List<RecordResponse> pendingReviewRecords(int limit) {
|
||||
return pendingReviewRecords("", "", "", limit);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user