Browse Source

统计/查询高频易错题前10

master
luogw 3 months ago
parent
commit
00648f9ca2
  1. 8
      src/main/java/com/project/exam/domain/service/impl/SubmitPaperDomainServiceImpl.java
  2. 10
      src/main/java/com/project/statistics/application/StatisticsApplicationService.java
  3. 35
      src/main/java/com/project/statistics/application/impl/StatisticsApplicationServiceImpl.java
  4. 19
      src/main/java/com/project/statistics/controller/StatisticsController.java
  5. 91
      src/main/java/com/project/statistics/domain/dto/ErrorProneStatisticsDTO.java
  6. 120
      src/main/java/com/project/statistics/domain/entity/ErrorProneStatisticsEntity.java
  7. 7
      src/main/java/com/project/statistics/domain/service/ErrorProneStatisticsBaseService.java
  8. 17
      src/main/java/com/project/statistics/domain/service/SaveErrorProneStatisticsDomainService.java
  9. 11
      src/main/java/com/project/statistics/domain/service/SearchErrorProneStatisticsDomainService.java
  10. 11
      src/main/java/com/project/statistics/domain/service/impl/ErrorProneStatisticsBaseServiceImpl.java
  11. 212
      src/main/java/com/project/statistics/domain/service/impl/SaveSaveErrorProneStatisticsDomainServiceImpl.java
  12. 31
      src/main/java/com/project/statistics/domain/service/impl/SearchErrorProneStatisticsDomainServiceImpl.java
  13. 10
      src/main/java/com/project/statistics/mapper/ErrorProneStatisticsMapper.java

8
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.NotifyExamRecordDomainService;
import com.project.exam.domain.service.SubmitPaperDomainService; import com.project.exam.domain.service.SubmitPaperDomainService;
import com.project.exam.mapper.ExamRecordMapper; import com.project.exam.mapper.ExamRecordMapper;
import com.project.statistics.application.StatisticsApplicationService;
import com.project.task.domain.dto.TaskDTO; import com.project.task.domain.dto.TaskDTO;
import com.project.task.domain.entity.TaskEntity; import com.project.task.domain.entity.TaskEntity;
import com.project.task.domain.entity.TaskUserEntity; import com.project.task.domain.entity.TaskUserEntity;
@ -44,6 +45,9 @@ public class SubmitPaperDomainServiceImpl implements SubmitPaperDomainService {
@Autowired @Autowired
private NotifyExamRecordDomainService notifyExamRecordDomainService; private NotifyExamRecordDomainService notifyExamRecordDomainService;
@Autowired
private StatisticsApplicationService statisticsApplicationService;
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public ExamRecordDTO submitPaper(Long recordId) throws Exception { public ExamRecordDTO submitPaper(Long recordId) throws Exception {
@ -96,6 +100,10 @@ public class SubmitPaperDomainServiceImpl implements SubmitPaperDomainService {
// 更新 TaskUser 冗余字段 // 更新 TaskUser 冗余字段
updateTaskUserStatus(taskUser , isPassed , recordId); updateTaskUserStatus(taskUser , isPassed , recordId);
// 异步收集易错统计
statisticsApplicationService.collectErrorProneStatistics(
task.getId(), task.getExamMode(), record.getAnswerSnapshot());
// 构建dto // 构建dto
ExamRecordDTO dto = record.toDTO(ExamRecordDTO::new); ExamRecordDTO dto = record.toDTO(ExamRecordDTO::new);
// 后面需要用到这个taskDTO // 后面需要用到这个taskDTO

10
src/main/java/com/project/statistics/application/StatisticsApplicationService.java

@ -1,9 +1,19 @@
package com.project.statistics.application; package com.project.statistics.application;
import com.project.base.domain.result.Result; 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 com.project.statistics.domain.dto.ExamTaskStatisticsDTO;
import java.util.List;
public interface StatisticsApplicationService { public interface StatisticsApplicationService {
Result<ExamTaskStatisticsDTO> examTaskStatistics(Long taskId); Result<ExamTaskStatisticsDTO> examTaskStatistics(Long taskId);
void collectErrorProneStatistics(Long id, Integer examMode, List<ExamRecordEntity.QuestionSnapshot> answerSnapshot);
Result<List<ErrorProneStatisticsDTO>> searchErrorProneTop(Long taskId);
void singleExamStatistics(Long examRecordId) throws Exception;
} }

35
src/main/java/com/project/statistics/application/impl/StatisticsApplicationServiceImpl.java

@ -1,17 +1,32 @@
package com.project.statistics.application.impl; package com.project.statistics.application.impl;
import com.project.base.domain.result.Result; 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.application.StatisticsApplicationService;
import com.project.statistics.domain.dto.ErrorProneStatisticsDTO;
import com.project.statistics.domain.dto.ExamTaskStatisticsDTO; 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.ExamTaskStatisticsDomainService;
import com.project.statistics.domain.service.SearchErrorProneStatisticsDomainService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List;
@Service @Service
public class StatisticsApplicationServiceImpl implements StatisticsApplicationService { public class StatisticsApplicationServiceImpl implements StatisticsApplicationService {
@Autowired @Autowired
private ExamTaskStatisticsDomainService examTaskStatisticsDomainService; 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<ExamTaskStatisticsDTO> examTaskStatistics(Long taskId) { public Result<ExamTaskStatisticsDTO> examTaskStatistics(Long taskId) {
return examTaskStatisticsDomainService.calculateExamTaskStatistics(taskId); return examTaskStatisticsDomainService.calculateExamTaskStatistics(taskId);
} }
/**
* 统计高频易错数据
*/
@Override
public void collectErrorProneStatistics(Long id, Integer examMode, List<ExamRecordEntity.QuestionSnapshot> answerSnapshot) {
saveErrorProneStatisticsDomainService.collectErrorProneStatistics(id, examMode, answerSnapshot);
}
@Override
public Result<List<ErrorProneStatisticsDTO>> 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());
}
} }

19
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.base.domain.result.Result;
import com.project.statistics.application.StatisticsApplicationService; 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.dto.ExamTaskStatisticsDTO;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController @RestController
@RequestMapping("/api/admin/statistics") @RequestMapping("/api/admin/statistics")
public class StatisticsController { public class StatisticsController {
@ -21,5 +24,21 @@ public class StatisticsController {
return statisticsApplicationService.examTaskStatistics(taskId); return statisticsApplicationService.examTaskStatistics(taskId);
} }
/**
* 查询高频易错题前10
*/
@GetMapping("/errorProneTop")
public Result<List<ErrorProneStatisticsDTO>> errorProneTop(Long taskId) {
return statisticsApplicationService.searchErrorProneTop(taskId);
}
/**
* 统计单场考试数据
*/
@GetMapping("/singleExam")
public Result<String> singleExam(Long examRecordId) throws Exception {
statisticsApplicationService.singleExamStatistics(examRecordId);
return Result.success("统计完成");
}
} }

91
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<Long> questionIdList;
/**
* 知识点ID
*/
private Long kpId;
/**
* 内容生成式为知识点内容经典套题为题目内容
*/
private String content;
/**
* 题目类型
*/
private Integer questionType;
/**
* 错误次数
*/
private Integer errorCount;
/**
* 出现次数
*/
private Integer appearCount;
/**
* 占比%错误次数/出现次数*100
*/
private String proportion;
/**
* 选项详情经典套题才有
*/
private List<OptionDetailDTO> 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> T toEntity(Supplier<T> supplier) {
T result = super.toEntity(supplier);
if (result instanceof ErrorProneStatisticsEntity entity) {
// 处理内部列表快照的转换
if (CollUtil.isNotEmpty(this.optionDetailDTOS)) {
List<ErrorProneStatisticsEntity.OptionDetail> optionDetails = this.optionDetailDTOS.stream().map(dto -> {
ErrorProneStatisticsEntity.OptionDetail optionDetail = new ErrorProneStatisticsEntity.OptionDetail();
BeanUtils.copyProperties(dto, optionDetail);
return optionDetail;
}).toList();
entity.setOptionDetails(optionDetails);
}
}
return result;
}
}

120
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<Long> 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<OptionDetail> optionDetails;
@Data
public static class OptionDetail {
private String option; // 选项
private String optionContent; // 选项内容
private Integer choosenCount; // 选择次数
private Boolean right;//正确选项
}
@Override
public <T> T toDTO(Supplier<T> 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<ErrorProneStatisticsDTO.OptionDetailDTO> 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));
}
}

7
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<ErrorProneStatisticsEntity> {
}

17
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<ExamRecordEntity.QuestionSnapshot> snapshots);
}

11
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<List<ErrorProneStatisticsDTO>> searchTopByTaskId(Long taskId);
}

11
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<ErrorProneStatisticsMapper, ErrorProneStatisticsEntity> implements ErrorProneStatisticsBaseService {
}

212
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<ExamRecordEntity.QuestionSnapshot> 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<ExamRecordEntity.QuestionSnapshot> 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<TaskKnowledgePointEntity> 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<Long> 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<ExamRecordEntity.QuestionSnapshot> 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<ErrorProneStatisticsEntity.OptionDetail> buildOptionDetail(ExamRecordEntity.QuestionSnapshot snapshot) {
List<ErrorProneStatisticsEntity.OptionDetail> list = new ArrayList<>();
Map<String, String> options = snapshot.getOptions();
if (options == null) {
return list;
}
String normalizedRightAnswer = normalizeAnswer(snapshot.getRightAnswer());
for (Map.Entry<String, String> 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<ErrorProneStatisticsEntity.OptionDetail> 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());
}
}

31
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<List<ErrorProneStatisticsDTO>> searchTopByTaskId(Long taskId) {
List<ErrorProneStatisticsEntity> entityList = errorProneStatisticsBaseService.lambdaQuery()
.eq(ErrorProneStatisticsEntity::getTaskId, taskId)
.orderByDesc(ErrorProneStatisticsEntity::getErrorCount)
.last("LIMIT 10")
.list();
List<ErrorProneStatisticsDTO> dtoList = entityList.stream().map(entity -> entity.toDTO(ErrorProneStatisticsDTO::new)).collect(Collectors.toList());
return Result.success(dtoList);
}
}

10
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<ErrorProneStatisticsEntity> {
}
Loading…
Cancel
Save