|
|
|
@ -2,6 +2,7 @@ package com.project.statistics.domain.service.impl; |
|
|
|
|
|
|
|
import cn.hutool.core.collection.CollUtil; |
|
|
|
import cn.hutool.core.collection.CollectionUtil; |
|
|
|
import cn.hutool.core.util.ObjectUtil; |
|
|
|
import cn.hutool.core.util.StrUtil; |
|
|
|
import com.project.exam.domain.entity.ExamRecordEntity; |
|
|
|
import com.project.question.domain.entity.QuestionEntity; |
|
|
|
@ -11,6 +12,7 @@ import com.project.question.domain.service.TaskKnowledgePointBaseService; |
|
|
|
import com.project.statistics.domain.entity.ErrorProneStatisticsEntity; |
|
|
|
import com.project.statistics.domain.service.ErrorProneStatisticsBaseService; |
|
|
|
import com.project.statistics.domain.service.SaveErrorProneStatisticsDomainService; |
|
|
|
import com.project.task.domain.dto.TaskDTO; |
|
|
|
import com.project.task.domain.entity.TaskEntity; |
|
|
|
import com.project.task.domain.enums.ExamModeEnum; |
|
|
|
import com.project.task.domain.enums.QuestionTypeEnum; |
|
|
|
@ -26,6 +28,7 @@ import java.util.List; |
|
|
|
import java.util.Map; |
|
|
|
import java.util.Objects; |
|
|
|
import java.util.concurrent.TimeUnit; |
|
|
|
import java.util.function.Predicate; |
|
|
|
import java.util.stream.Collectors; |
|
|
|
|
|
|
|
@Service |
|
|
|
@ -41,9 +44,6 @@ public class SaveSaveErrorProneStatisticsDomainServiceImpl implements SaveErrorP |
|
|
|
@Autowired |
|
|
|
private TaskKnowledgePointBaseService taskKnowledgePointBaseService; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private TaskBaseService taskBaseService; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private StringRedisTemplate redisTemplate; |
|
|
|
|
|
|
|
@ -53,28 +53,44 @@ public class SaveSaveErrorProneStatisticsDomainServiceImpl implements SaveErrorP |
|
|
|
// 每次抢锁失败后,休眠50ms再重试
|
|
|
|
private static final long LOCK_RETRY_INTERVAL_MS = 50; |
|
|
|
|
|
|
|
/** |
|
|
|
* 收集客观题易错统计(试卷提交时调用,此时简答题尚未评分) |
|
|
|
*/ |
|
|
|
@Override |
|
|
|
@Async |
|
|
|
public void collectErrorProneStatistics(Long taskId, Integer examMode, List<ExamRecordEntity.QuestionSnapshot> snapshots) { |
|
|
|
if (taskId == null || CollUtil.isEmpty(snapshots)) { |
|
|
|
public void collectErrorProneStatistics(TaskDTO taskDTO, List<ExamRecordEntity.QuestionSnapshot> snapshots) { |
|
|
|
collectByFilter(taskDTO, snapshots, this::isNotShortAnswer); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 收集简答题易错统计(简答题评分完成后调用) |
|
|
|
*/ |
|
|
|
@Override |
|
|
|
@Async |
|
|
|
public void collectShortAnswerErrorProneStatistics(TaskDTO taskDTO, List<ExamRecordEntity.QuestionSnapshot> snapshots) { |
|
|
|
collectByFilter(taskDTO, snapshots, this::isShortAnswer); |
|
|
|
} |
|
|
|
|
|
|
|
private void collectByFilter(TaskDTO taskDTO, List<ExamRecordEntity.QuestionSnapshot> snapshots, Predicate<ExamRecordEntity.QuestionSnapshot> filter) { |
|
|
|
if (ObjectUtil.isNull(taskDTO) || CollUtil.isEmpty(snapshots)) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
TaskEntity task = taskBaseService.getById(taskId); |
|
|
|
if (Objects.isNull(task)){ |
|
|
|
throw new IllegalArgumentException("考试任务不存在,taskId: " + taskId); |
|
|
|
List<ExamRecordEntity.QuestionSnapshot> filtered = snapshots.stream().filter(filter).collect(Collectors.toList()); |
|
|
|
if (CollUtil.isEmpty(filtered)) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
Double shortAnswerScore = task.getShortAnswerScore(); |
|
|
|
Double shortAnswerScore = taskDTO.getShortAnswerScore(); |
|
|
|
|
|
|
|
if (ExamModeEnum.GENERATIVE.getValue().equals(examMode)) { |
|
|
|
collectGenerativeStatistics(taskId, shortAnswerScore, snapshots); |
|
|
|
} else if (ExamModeEnum.CLASSIC.getValue().equals(examMode)) { |
|
|
|
collectClassicStatistics(taskId, shortAnswerScore, snapshots); |
|
|
|
if (ExamModeEnum.GENERATIVE.getValue().equals(taskDTO.getExamMode())) { |
|
|
|
collectGenerativeStatistics(taskDTO.getId(), shortAnswerScore, filtered); |
|
|
|
} else if (ExamModeEnum.CLASSIC.getValue().equals(taskDTO.getExamMode())) { |
|
|
|
collectClassicStatistics(taskDTO.getId(), shortAnswerScore, filtered); |
|
|
|
} |
|
|
|
} catch (Exception e) { |
|
|
|
log.error("[易错统计] 收集失败, taskId={}", taskId, e); |
|
|
|
log.error("[易错统计] 收集失败, taskId={}", taskDTO.getId(), e); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -180,7 +196,7 @@ public class SaveSaveErrorProneStatisticsDomainServiceImpl implements SaveErrorP |
|
|
|
entity.setAppearCount(0); |
|
|
|
//构建题目详细信息
|
|
|
|
List<ErrorProneStatisticsEntity.OptionDetail> optionDetails; |
|
|
|
if (isShortAnswer(snapshot.getType())) { |
|
|
|
if (isShortAnswer(snapshot)) { |
|
|
|
optionDetails = buildOptionDetail(question.getQuestionDetail()); |
|
|
|
} else { |
|
|
|
optionDetails = buildOptionDetail(snapshot); |
|
|
|
@ -275,7 +291,7 @@ public class SaveSaveErrorProneStatisticsDomainServiceImpl implements SaveErrorP |
|
|
|
*/ |
|
|
|
private void updateOptionDetail(ErrorProneStatisticsEntity entity, ExamRecordEntity.QuestionSnapshot snapshot) { |
|
|
|
String normalizedUserAnswer; |
|
|
|
if(isShortAnswer(snapshot.getType())){ |
|
|
|
if (isShortAnswer(snapshot)) { |
|
|
|
List<Integer> hitPoints = snapshot.getHitPoints(); |
|
|
|
normalizedUserAnswer = CollectionUtil.isEmpty(hitPoints) ? "" : hitPoints.stream().map(String::valueOf).collect(Collectors.joining(",")); |
|
|
|
}else{ |
|
|
|
@ -310,15 +326,22 @@ public class SaveSaveErrorProneStatisticsDomainServiceImpl implements SaveErrorP |
|
|
|
/** |
|
|
|
* 是否为简答题 |
|
|
|
*/ |
|
|
|
private boolean isShortAnswer(Integer type) { |
|
|
|
return Objects.equals(type, QuestionTypeEnum.SHORT_ANSWER.getValue()); |
|
|
|
private boolean isShortAnswer(ExamRecordEntity.QuestionSnapshot snapshot) { |
|
|
|
return Objects.equals(snapshot.getType(), QuestionTypeEnum.SHORT_ANSWER.getValue()); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 是否为非简答题 |
|
|
|
*/ |
|
|
|
private boolean isNotShortAnswer(ExamRecordEntity.QuestionSnapshot snapshot) { |
|
|
|
return !isShortAnswer(snapshot); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 判断是否为错题:客观题按 isRight,简答题按 aiScore 是否得满 |
|
|
|
*/ |
|
|
|
private boolean isErrorQuestion(ExamRecordEntity.QuestionSnapshot snapshot, Double shortAnswerScore) { |
|
|
|
if (isShortAnswer(snapshot.getType())) { |
|
|
|
if (isShortAnswer(snapshot)) { |
|
|
|
Double aiScore = snapshot.getAiScore(); |
|
|
|
return aiScore == null || aiScore < shortAnswerScore; |
|
|
|
} |
|
|
|
|