diff --git a/src/main/java/com/project/exam/domain/service/impl/SubmitPaperDomainServiceImpl.java b/src/main/java/com/project/exam/domain/service/impl/SubmitPaperDomainServiceImpl.java index 7fdb365..291db37 100644 --- a/src/main/java/com/project/exam/domain/service/impl/SubmitPaperDomainServiceImpl.java +++ b/src/main/java/com/project/exam/domain/service/impl/SubmitPaperDomainServiceImpl.java @@ -8,6 +8,7 @@ import com.project.exam.domain.service.BuildExamRecordDomainService; import com.project.exam.domain.service.NotifyExamRecordDomainService; import com.project.exam.domain.service.SubmitPaperDomainService; import com.project.exam.mapper.ExamRecordMapper; +import com.project.statistics.application.StatisticsApplicationService; import com.project.task.domain.dto.TaskDTO; import com.project.task.domain.entity.TaskEntity; import com.project.task.domain.entity.TaskUserEntity; @@ -44,6 +45,9 @@ public class SubmitPaperDomainServiceImpl implements SubmitPaperDomainService { @Autowired private NotifyExamRecordDomainService notifyExamRecordDomainService; + @Autowired + private StatisticsApplicationService statisticsApplicationService; + @Override @Transactional(rollbackFor = Exception.class) public ExamRecordDTO submitPaper(Long recordId) throws Exception { @@ -96,6 +100,10 @@ public class SubmitPaperDomainServiceImpl implements SubmitPaperDomainService { // 更新 TaskUser 冗余字段 updateTaskUserStatus(taskUser , isPassed , recordId); + // 异步收集易错统计 + statisticsApplicationService.collectErrorProneStatistics( + task.getId(), task.getExamMode(), record.getAnswerSnapshot()); + // 构建dto ExamRecordDTO dto = record.toDTO(ExamRecordDTO::new); // 后面需要用到这个taskDTO diff --git a/src/main/java/com/project/statistics/application/StatisticsApplicationService.java b/src/main/java/com/project/statistics/application/StatisticsApplicationService.java index 7b9d774..d0e2f35 100644 --- a/src/main/java/com/project/statistics/application/StatisticsApplicationService.java +++ b/src/main/java/com/project/statistics/application/StatisticsApplicationService.java @@ -1,9 +1,19 @@ package com.project.statistics.application; import com.project.base.domain.result.Result; +import com.project.exam.domain.entity.ExamRecordEntity; +import com.project.statistics.domain.dto.ErrorProneStatisticsDTO; import com.project.statistics.domain.dto.ExamTaskStatisticsDTO; +import java.util.List; + public interface StatisticsApplicationService { Result examTaskStatistics(Long taskId); + + void collectErrorProneStatistics(Long id, Integer examMode, List answerSnapshot); + + Result> searchErrorProneTop(Long taskId); + + void singleExamStatistics(Long examRecordId) throws Exception; } diff --git a/src/main/java/com/project/statistics/application/impl/StatisticsApplicationServiceImpl.java b/src/main/java/com/project/statistics/application/impl/StatisticsApplicationServiceImpl.java index f7d6841..e9f8fd4 100644 --- a/src/main/java/com/project/statistics/application/impl/StatisticsApplicationServiceImpl.java +++ b/src/main/java/com/project/statistics/application/impl/StatisticsApplicationServiceImpl.java @@ -1,17 +1,32 @@ package com.project.statistics.application.impl; import com.project.base.domain.result.Result; +import com.project.exam.application.ExamRecordApplicationService; +import com.project.exam.domain.dto.ExamRecordDTO; +import com.project.exam.domain.entity.ExamRecordEntity; +import com.project.exam.domain.service.GetDetailExamRecordDomainService; import com.project.statistics.application.StatisticsApplicationService; +import com.project.statistics.domain.dto.ErrorProneStatisticsDTO; import com.project.statistics.domain.dto.ExamTaskStatisticsDTO; +import com.project.statistics.domain.service.SaveErrorProneStatisticsDomainService; import com.project.statistics.domain.service.ExamTaskStatisticsDomainService; +import com.project.statistics.domain.service.SearchErrorProneStatisticsDomainService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.List; + @Service public class StatisticsApplicationServiceImpl implements StatisticsApplicationService { @Autowired private ExamTaskStatisticsDomainService examTaskStatisticsDomainService; + @Autowired + private SaveErrorProneStatisticsDomainService saveErrorProneStatisticsDomainService; + @Autowired + private SearchErrorProneStatisticsDomainService searchErrorProneStatisticsDomainService; + @Autowired + private GetDetailExamRecordDomainService getDetailExamRecordDomainService; /** * 统计考试任务数据 @@ -20,4 +35,24 @@ public class StatisticsApplicationServiceImpl implements StatisticsApplicationSe public Result examTaskStatistics(Long taskId) { return examTaskStatisticsDomainService.calculateExamTaskStatistics(taskId); } + + /** + * 统计高频易错数据 + */ + @Override + public void collectErrorProneStatistics(Long id, Integer examMode, List answerSnapshot) { + saveErrorProneStatisticsDomainService.collectErrorProneStatistics(id, examMode, answerSnapshot); + } + + @Override + public Result> searchErrorProneTop(Long taskId) { + return searchErrorProneStatisticsDomainService.searchTopByTaskId(taskId); + } + + @Override + public void singleExamStatistics(Long examRecordId) throws Exception { + ExamRecordDTO detail = getDetailExamRecordDomainService.getDetail(examRecordId).getData(); + ExamRecordEntity entity = detail.toEntity(ExamRecordEntity::new); + saveErrorProneStatisticsDomainService.collectErrorProneStatistics(detail.getTaskId(), 1, entity.getAnswerSnapshot()); + } } diff --git a/src/main/java/com/project/statistics/controller/StatisticsController.java b/src/main/java/com/project/statistics/controller/StatisticsController.java index 5e0d405..95595ed 100644 --- a/src/main/java/com/project/statistics/controller/StatisticsController.java +++ b/src/main/java/com/project/statistics/controller/StatisticsController.java @@ -2,10 +2,13 @@ package com.project.statistics.controller; import com.project.base.domain.result.Result; import com.project.statistics.application.StatisticsApplicationService; +import com.project.statistics.domain.dto.ErrorProneStatisticsDTO; import com.project.statistics.domain.dto.ExamTaskStatisticsDTO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import java.util.List; + @RestController @RequestMapping("/api/admin/statistics") public class StatisticsController { @@ -21,5 +24,21 @@ public class StatisticsController { return statisticsApplicationService.examTaskStatistics(taskId); } + /** + * 查询高频易错题前10 + */ + @GetMapping("/errorProneTop") + public Result> errorProneTop(Long taskId) { + return statisticsApplicationService.searchErrorProneTop(taskId); + } + + /** + * 统计单场考试数据 + */ + @GetMapping("/singleExam") + public Result singleExam(Long examRecordId) throws Exception { + statisticsApplicationService.singleExamStatistics(examRecordId); + return Result.success("统计完成"); + } } diff --git a/src/main/java/com/project/statistics/domain/dto/ErrorProneStatisticsDTO.java b/src/main/java/com/project/statistics/domain/dto/ErrorProneStatisticsDTO.java new file mode 100644 index 0000000..c47325c --- /dev/null +++ b/src/main/java/com/project/statistics/domain/dto/ErrorProneStatisticsDTO.java @@ -0,0 +1,91 @@ +package com.project.statistics.domain.dto; + +import cn.hutool.core.collection.CollUtil; +import com.project.base.domain.dto.BaseDTO; +import com.project.statistics.domain.entity.ErrorProneStatisticsEntity; +import lombok.Data; +import org.springframework.beans.BeanUtils; + +import java.util.List; +import java.util.function.Supplier; + +@Data +public class ErrorProneStatisticsDTO extends BaseDTO { + private Long id; + + /** + * 考试模式:0-生成式,1-经典套题 + */ + private Integer examMode; + + /** + * 考试ID + */ + private Long taskId; + + /** + * 关联题目ID列表 + */ + private List questionIdList; + + /** + * 知识点ID + */ + private Long kpId; + + /** + * 内容:生成式为知识点内容,经典套题为题目内容 + */ + private String content; + + /** + * 题目类型 + */ + private Integer questionType; + + /** + * 错误次数 + */ + private Integer errorCount; + + /** + * 出现次数 + */ + private Integer appearCount; + + /** + * 占比(%):错误次数/出现次数*100 + */ + private String proportion; + + /** + * 选项详情(经典套题才有) + */ + private List optionDetailDTOS; + + @Data + public static class OptionDetailDTO { + private String option; // 选项 + private String optionContent; // 选项内容 + private Integer choosenCount; // 选择次数 + private Boolean right;//正确选项 + private String proportion; // 占比(%):选择次数/出现次数*100 + } + + @Override + public T toEntity(Supplier supplier) { + T result = super.toEntity(supplier); + if (result instanceof ErrorProneStatisticsEntity entity) { + // 处理内部列表快照的转换 + if (CollUtil.isNotEmpty(this.optionDetailDTOS)) { + List optionDetails = this.optionDetailDTOS.stream().map(dto -> { + ErrorProneStatisticsEntity.OptionDetail optionDetail = new ErrorProneStatisticsEntity.OptionDetail(); + BeanUtils.copyProperties(dto, optionDetail); + return optionDetail; + }).toList(); + entity.setOptionDetails(optionDetails); + } + } + return result; + } +} diff --git a/src/main/java/com/project/statistics/domain/entity/ErrorProneStatisticsEntity.java b/src/main/java/com/project/statistics/domain/entity/ErrorProneStatisticsEntity.java new file mode 100644 index 0000000..baee1a7 --- /dev/null +++ b/src/main/java/com/project/statistics/domain/entity/ErrorProneStatisticsEntity.java @@ -0,0 +1,120 @@ +package com.project.statistics.domain.entity; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import com.project.base.domain.entity.BaseEntity; +import com.project.statistics.domain.dto.ErrorProneStatisticsDTO; +import jakarta.persistence.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.hibernate.annotations.Comment; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; +import org.springframework.beans.BeanUtils; + +import java.util.List; +import java.util.function.Supplier; + + +@Data +@Table(name = "evaluator_error_prone_statistics") +@Entity +@TableName(value = "evaluator_error_prone_statistics", autoResultMap = true) +@EqualsAndHashCode(callSuper = true) +public class ErrorProneStatisticsEntity extends BaseEntity { + @TableId(type = IdType.ASSIGN_ID) + @Id + private Long id; + + @Column(name = "exam_mode") + @Comment("考试模式:0-生成式,1-经典套题") + @TableField("exam_mode") + private Integer examMode = 0; + + @Column(name = "task_id") + @TableField("task_id") + @Comment("考试任务ID") + private Long taskId; + + /** + * 关联题目idList + * 存储为 JSON 数组: [1, 10, 101] + * 生成式:多个题目ID,经典套题:只有一个题目ID + */ + @TableField(value = "question_id_list" , typeHandler = JacksonTypeHandler.class) + @Column(name = "question_id_list", columnDefinition = "json comment '关联题目列表'") + @JdbcTypeCode(SqlTypes.JSON) + private List questionIdList; + + @Column(name = "kp_id") + @TableField("kp_id") + @Comment("知识点ID") + private Long kpId; + + @Column(name = "content", columnDefinition = "TEXT comment '内容:生成式为知识点内容,经典套题为题目内容'") + private String content; + + @Column(name = "question_type") + @Comment("题目类型") + @TableField("question_type") + private Integer questionType; + + @Column(name = "error_count") + @Comment("错误次数") + @TableField("error_count") + private Integer errorCount; // 错误次数 + + @Column(name = "appear_count") + @Comment("出现次数") + @TableField("appear_count") + private Integer appearCount; // 出现次数 + + @TableField(value = "option_detail" , typeHandler = JacksonTypeHandler.class) + @JdbcTypeCode(SqlTypes.JSON) + @Column(name = "option_detail", columnDefinition = "json comment '选项内容'") + private List optionDetails; + + @Data + public static class OptionDetail { + private String option; // 选项 + private String optionContent; // 选项内容 + private Integer choosenCount; // 选择次数 + private Boolean right;//正确选项 + } + + @Override + public T toDTO(Supplier supplier) { + T result = super.toDTO(supplier); + if (result instanceof ErrorProneStatisticsDTO dto) { + // 计算主实体占比:错误次数/出现次数*100,保留整数 + int appear = this.appearCount == null ? 0 : this.appearCount; + int error = this.errorCount == null ? 0 : this.errorCount; + dto.setProportion(calculateProportion(error, appear)); + + // 处理内部快照列表从 Entity 到 DTO 的转换 + if (CollUtil.isNotEmpty(this.optionDetails)) { + List dtoList = this.optionDetails.stream().map(optionDetail -> { + ErrorProneStatisticsDTO.OptionDetailDTO optionDetailDTO = new ErrorProneStatisticsDTO.OptionDetailDTO(); + BeanUtils.copyProperties(optionDetail, optionDetailDTO); + // 计算选项占比:选择次数/出现次数*100,保留整数 + int chosen = optionDetail.getChoosenCount() == null ? 0 : optionDetail.getChoosenCount(); + optionDetailDTO.setProportion(calculateProportion(chosen, appear)); + return optionDetailDTO; + }).toList(); + dto.setOptionDetailDTOS(dtoList); + } + } + return result; + } + + private String calculateProportion(int numerator, int denominator) { + if (denominator == 0) { + return "0"; + } + return String.valueOf(Math.round(numerator * 100.0 / denominator)); + } +} diff --git a/src/main/java/com/project/statistics/domain/service/ErrorProneStatisticsBaseService.java b/src/main/java/com/project/statistics/domain/service/ErrorProneStatisticsBaseService.java new file mode 100644 index 0000000..4538027 --- /dev/null +++ b/src/main/java/com/project/statistics/domain/service/ErrorProneStatisticsBaseService.java @@ -0,0 +1,7 @@ +package com.project.statistics.domain.service; + +import com.project.base.domain.service.IBaseService; +import com.project.statistics.domain.entity.ErrorProneStatisticsEntity; + +public interface ErrorProneStatisticsBaseService extends IBaseService { +} diff --git a/src/main/java/com/project/statistics/domain/service/SaveErrorProneStatisticsDomainService.java b/src/main/java/com/project/statistics/domain/service/SaveErrorProneStatisticsDomainService.java new file mode 100644 index 0000000..a74155b --- /dev/null +++ b/src/main/java/com/project/statistics/domain/service/SaveErrorProneStatisticsDomainService.java @@ -0,0 +1,17 @@ +package com.project.statistics.domain.service; + +import com.project.exam.domain.entity.ExamRecordEntity; + +import java.util.List; + +public interface SaveErrorProneStatisticsDomainService { + + /** + * 异步收集易错统计 + * + * @param taskId 考试任务ID + * @param examMode 考试模式 + * @param snapshots 答题快照 + */ + void collectErrorProneStatistics(Long taskId, Integer examMode, List snapshots); +} diff --git a/src/main/java/com/project/statistics/domain/service/SearchErrorProneStatisticsDomainService.java b/src/main/java/com/project/statistics/domain/service/SearchErrorProneStatisticsDomainService.java new file mode 100644 index 0000000..0523d0b --- /dev/null +++ b/src/main/java/com/project/statistics/domain/service/SearchErrorProneStatisticsDomainService.java @@ -0,0 +1,11 @@ +package com.project.statistics.domain.service; + +import com.project.base.domain.result.Result; +import com.project.statistics.domain.dto.ErrorProneStatisticsDTO; + +import java.util.List; + +public interface SearchErrorProneStatisticsDomainService { + + Result> searchTopByTaskId(Long taskId); +} diff --git a/src/main/java/com/project/statistics/domain/service/impl/ErrorProneStatisticsBaseServiceImpl.java b/src/main/java/com/project/statistics/domain/service/impl/ErrorProneStatisticsBaseServiceImpl.java new file mode 100644 index 0000000..59803d6 --- /dev/null +++ b/src/main/java/com/project/statistics/domain/service/impl/ErrorProneStatisticsBaseServiceImpl.java @@ -0,0 +1,11 @@ +package com.project.statistics.domain.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.project.statistics.domain.entity.ErrorProneStatisticsEntity; +import com.project.statistics.domain.service.ErrorProneStatisticsBaseService; +import com.project.statistics.mapper.ErrorProneStatisticsMapper; +import org.springframework.stereotype.Service; + +@Service +public class ErrorProneStatisticsBaseServiceImpl extends ServiceImpl implements ErrorProneStatisticsBaseService { +} diff --git a/src/main/java/com/project/statistics/domain/service/impl/SaveSaveErrorProneStatisticsDomainServiceImpl.java b/src/main/java/com/project/statistics/domain/service/impl/SaveSaveErrorProneStatisticsDomainServiceImpl.java new file mode 100644 index 0000000..fc2d611 --- /dev/null +++ b/src/main/java/com/project/statistics/domain/service/impl/SaveSaveErrorProneStatisticsDomainServiceImpl.java @@ -0,0 +1,212 @@ +package com.project.statistics.domain.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.project.exam.domain.entity.ExamRecordEntity; +import com.project.question.domain.entity.QuestionEntity; +import com.project.question.domain.entity.TaskKnowledgePointEntity; +import com.project.question.domain.service.QuestionBaseService; +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.enums.ExamModeEnum; +import com.project.task.domain.enums.QuestionTypeEnum; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +@Service +@Slf4j +public class SaveSaveErrorProneStatisticsDomainServiceImpl implements SaveErrorProneStatisticsDomainService { + + @Autowired + private ErrorProneStatisticsBaseService errorProneStatisticsBaseService; + + @Autowired + private QuestionBaseService questionBaseService; + + @Autowired + private TaskKnowledgePointBaseService taskKnowledgePointBaseService; + + @Override + @Async + public void collectErrorProneStatistics(Long taskId, Integer examMode, List snapshots) { + if (taskId == null || CollUtil.isEmpty(snapshots)) { + return; + } + + try { + if (ExamModeEnum.GENERATIVE.getValue().equals(examMode)) { + collectGenerativeStatistics(taskId, snapshots); + } else if (ExamModeEnum.CLASSIC.getValue().equals(examMode)) { + collectClassicStatistics(taskId, snapshots); + } + } catch (Exception e) { + log.error("[易错统计] 收集失败, taskId={}", taskId, e); + } + } + + /** + * 生成式套题:以知识点为单位统计 + */ + private void collectGenerativeStatistics(Long taskId, List snapshots) { + for (ExamRecordEntity.QuestionSnapshot snapshot : snapshots) { + // 跳过简答题 + if (isShortAnswer(snapshot.getType())) { + continue; + } + Long questionId = snapshot.getQuestionId(); + if (questionId == null) { + continue; + } + QuestionEntity question = questionBaseService.getById(questionId); + if (question == null || CollUtil.isEmpty(question.getKpIdList())) { + continue; + } + + List kpList = taskKnowledgePointBaseService.listByIds(question.getKpIdList()); + for (TaskKnowledgePointEntity kp : kpList) { + if (kp == null || StrUtil.isBlank(kp.getContent())) { + continue; + } + + ErrorProneStatisticsEntity entity = errorProneStatisticsBaseService.lambdaQuery() + .eq(ErrorProneStatisticsEntity::getTaskId, taskId) + .eq(ErrorProneStatisticsEntity::getKpId, kp.getId()) + .one(); + + if (entity == null) { + entity = new ErrorProneStatisticsEntity(); + entity.setTaskId(taskId); + entity.setExamMode(ExamModeEnum.GENERATIVE.getValue()); + entity.setContent(kp.getContent()); + entity.setKpId(kp.getId()); + entity.setErrorCount(0); + entity.setAppearCount(0); + } + + List questionIdList = CollectionUtil.isEmpty(entity.getQuestionIdList()) ? new ArrayList<>() : entity.getQuestionIdList(); + questionIdList.add(questionId); + entity.setQuestionIdList(questionIdList); + entity.setAppearCount(entity.getAppearCount() + 1); + if (Boolean.FALSE.equals(snapshot.getIsRight())) { + entity.setErrorCount(entity.getErrorCount() + 1); + } + + errorProneStatisticsBaseService.saveOrUpdate(entity); + } + } + } + + /** + * 经典套题:以题目为单位统计,并统计选项选择情况 + */ + private void collectClassicStatistics(Long taskId, List snapshots) { + for (ExamRecordEntity.QuestionSnapshot snapshot : snapshots) { + // 跳过简答题 + if (isShortAnswer(snapshot.getType())) { + continue; + } + + String content = snapshot.getQuestionContent(); + if (StrUtil.isBlank(content)) { + continue; + } + + ErrorProneStatisticsEntity entity = errorProneStatisticsBaseService.lambdaQuery() + .eq(ErrorProneStatisticsEntity::getTaskId, taskId) + .eq(ErrorProneStatisticsEntity::getExamMode, snapshot.getQuestionId()) + .one(); + + if (entity == null) { + entity = new ErrorProneStatisticsEntity(); + entity.setTaskId(taskId); + entity.setQuestionIdList(List.of(snapshot.getQuestionId())); + entity.setExamMode(ExamModeEnum.CLASSIC.getValue()); + entity.setContent(content); + entity.setQuestionType(snapshot.getType()); + entity.setErrorCount(0); + entity.setAppearCount(0); + entity.setOptionDetails(buildOptionDetail(snapshot)); + } + + entity.setAppearCount(entity.getAppearCount() + 1); + if (Boolean.FALSE.equals(snapshot.getIsRight())) { + entity.setErrorCount(entity.getErrorCount() + 1); + } + + updateOptionDetail(entity, snapshot.getUserAnswer()); + + errorProneStatisticsBaseService.saveOrUpdate(entity); + } + } + + /** + * 构建选项详情 + */ + private List buildOptionDetail(ExamRecordEntity.QuestionSnapshot snapshot) { + List list = new ArrayList<>(); + Map options = snapshot.getOptions(); + if (options == null) { + return list; + } + + String normalizedRightAnswer = normalizeAnswer(snapshot.getRightAnswer()); + + for (Map.Entry entry : options.entrySet()) { + ErrorProneStatisticsEntity.OptionDetail od = new ErrorProneStatisticsEntity.OptionDetail(); + od.setOption(entry.getKey()); + od.setOptionContent(entry.getValue()); + od.setChoosenCount(0); + od.setRight(normalizedRightAnswer.contains(entry.getKey().toUpperCase())); + list.add(od); + } + return list; + } + + /** + * 更新选项被选择次数 + */ + private void updateOptionDetail(ErrorProneStatisticsEntity entity, String userAnswer) { + String normalizedUserAnswer = normalizeAnswer(userAnswer); + if (StrUtil.isBlank(normalizedUserAnswer)) { + return; + } + + List optionDetailList = entity.getOptionDetails(); + if (CollUtil.isEmpty(optionDetailList)) { + return; + } + + for (ErrorProneStatisticsEntity.OptionDetail od : optionDetailList) { + if (normalizedUserAnswer.contains(od.getOption().toUpperCase())) { + od.setChoosenCount((od.getChoosenCount() == null ? 0 : od.getChoosenCount()) + 1); + } + } + } + + /** + * 标准化答案:去除非字母数字字符并转大写 + */ + private String normalizeAnswer(String answer) { + if (StrUtil.isBlank(answer)) { + return ""; + } + return answer.replaceAll("[^a-zA-Z0-9]", "").toUpperCase(); + } + + /** + * 是否为简答题 + */ + private boolean isShortAnswer(Integer type) { + return Objects.equals(type, QuestionTypeEnum.SHORT_ANSWER.getValue()); + } +} diff --git a/src/main/java/com/project/statistics/domain/service/impl/SearchErrorProneStatisticsDomainServiceImpl.java b/src/main/java/com/project/statistics/domain/service/impl/SearchErrorProneStatisticsDomainServiceImpl.java new file mode 100644 index 0000000..072d3c4 --- /dev/null +++ b/src/main/java/com/project/statistics/domain/service/impl/SearchErrorProneStatisticsDomainServiceImpl.java @@ -0,0 +1,31 @@ +package com.project.statistics.domain.service.impl; + +import com.project.base.domain.result.Result; +import com.project.statistics.domain.dto.ErrorProneStatisticsDTO; +import com.project.statistics.domain.entity.ErrorProneStatisticsEntity; +import com.project.statistics.domain.service.ErrorProneStatisticsBaseService; +import com.project.statistics.domain.service.SearchErrorProneStatisticsDomainService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class SearchErrorProneStatisticsDomainServiceImpl implements SearchErrorProneStatisticsDomainService { + + @Autowired + private ErrorProneStatisticsBaseService errorProneStatisticsBaseService; + + @Override + public Result> searchTopByTaskId(Long taskId) { + List entityList = errorProneStatisticsBaseService.lambdaQuery() + .eq(ErrorProneStatisticsEntity::getTaskId, taskId) + .orderByDesc(ErrorProneStatisticsEntity::getErrorCount) + .last("LIMIT 10") + .list(); + + List dtoList = entityList.stream().map(entity -> entity.toDTO(ErrorProneStatisticsDTO::new)).collect(Collectors.toList()); + return Result.success(dtoList); + } +} diff --git a/src/main/java/com/project/statistics/mapper/ErrorProneStatisticsMapper.java b/src/main/java/com/project/statistics/mapper/ErrorProneStatisticsMapper.java new file mode 100644 index 0000000..a0fdad6 --- /dev/null +++ b/src/main/java/com/project/statistics/mapper/ErrorProneStatisticsMapper.java @@ -0,0 +1,10 @@ +package com.project.statistics.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.project.statistics.domain.entity.ErrorProneStatisticsEntity; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface ErrorProneStatisticsMapper extends BaseMapper { + +}