DailyPracticeServiceImpl.java 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. package com.xuekairui.quiz.service.impl;
  2. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  3. import com.xuekairui.quiz.dto.AnswerItem;
  4. import com.xuekairui.quiz.entity.QuizQuestion;
  5. import com.xuekairui.quiz.entity.QuizUserRecord;
  6. import com.xuekairui.quiz.mapper.QuizQuestionMapper;
  7. import com.xuekairui.quiz.mapper.QuizUserRecordMapper;
  8. import com.xuekairui.quiz.service.DailyPracticeService;
  9. import com.xuekairui.quiz.vo.DailyPracticeQuestionsVO;
  10. import com.xuekairui.quiz.vo.PracticeResultVO;
  11. import com.xuekairui.quiz.vo.PracticeSubmitVO;
  12. import lombok.RequiredArgsConstructor;
  13. import org.springframework.stereotype.Service;
  14. import org.springframework.transaction.annotation.Transactional;
  15. import java.math.BigDecimal;
  16. import java.math.RoundingMode;
  17. import java.time.LocalDate;
  18. import java.time.LocalDateTime;
  19. import java.util.ArrayList;
  20. import java.util.Collections;
  21. import java.util.LinkedHashMap;
  22. import java.util.List;
  23. import java.util.Map;
  24. import java.util.Random;
  25. import java.util.stream.Collectors;
  26. @Service
  27. @RequiredArgsConstructor
  28. public class DailyPracticeServiceImpl implements DailyPracticeService {
  29. private final QuizQuestionMapper questionMapper;
  30. private final QuizUserRecordMapper userRecordMapper;
  31. @Override
  32. public DailyPracticeQuestionsVO getQuestions(Long userId) {
  33. LocalDate today = LocalDate.now();
  34. LocalDateTime todayStart = today.atStartOfDay();
  35. // 检查今天是否已完成
  36. long doneCount = userRecordMapper.selectCount(
  37. new LambdaQueryWrapper<QuizUserRecord>()
  38. .eq(QuizUserRecord::getUserId, userId)
  39. .eq(QuizUserRecord::getAnswerType, 2)
  40. .ge(QuizUserRecord::getCreateTime, todayStart)
  41. .eq(QuizUserRecord::getStatus, 1)
  42. );
  43. boolean hasDone = doneCount > 0;
  44. // 按日期种子随机抽取10道题(同一天同一用户题目固定)
  45. long seed = today.toEpochDay() + userId;
  46. Random random = new Random(seed);
  47. List<QuizQuestion> allQuestions = questionMapper.selectList(
  48. new LambdaQueryWrapper<QuizQuestion>().eq(QuizQuestion::getIsReal, 0));
  49. Collections.shuffle(allQuestions, random);
  50. List<QuizQuestion> selected = allQuestions.stream().limit(10).collect(Collectors.toList());
  51. List<DailyPracticeQuestionsVO.DailyQuestionVO> questionList = new ArrayList<>();
  52. for (QuizQuestion q : selected) {
  53. questionList.add(DailyPracticeQuestionsVO.DailyQuestionVO.builder()
  54. .id(q.getId())
  55. .questionType(q.getQuestionType())
  56. .questionTypeName(getTypeName(q.getQuestionType()))
  57. .stem(q.getStem())
  58. .options(q.getOptions())
  59. .build());
  60. }
  61. return DailyPracticeQuestionsVO.builder()
  62. .date(today.toString())
  63. .questionCount(selected.size())
  64. .hasDone(hasDone)
  65. .questions(questionList)
  66. .build();
  67. }
  68. @Override
  69. @Transactional
  70. public PracticeSubmitVO submit(Long userId, List<AnswerItem> answers) {
  71. int correctCount = 0;
  72. int wrongCount = 0;
  73. List<PracticeResultVO> results = new ArrayList<>();
  74. List<Map<String, Object>> answerRecords = new ArrayList<>();
  75. for (AnswerItem ans : answers) {
  76. Long questionId = ans.getQuestionId();
  77. String userAnswer = ans.getUserAnswer();
  78. Integer timeSpent = ans.getTimeSpent() != null ? ans.getTimeSpent() : 0;
  79. QuizQuestion question = questionMapper.selectById(questionId);
  80. if (question == null) continue;
  81. boolean isCorrect = question.getAnswer().equalsIgnoreCase(userAnswer);
  82. if (isCorrect) correctCount++;
  83. else wrongCount++;
  84. results.add(PracticeResultVO.builder()
  85. .questionId(questionId)
  86. .isCorrect(isCorrect ? 1 : 0)
  87. .correctAnswer(question.getAnswer())
  88. .analysis(question.getAnalysis())
  89. .build());
  90. Map<String, Object> record = new LinkedHashMap<>();
  91. record.put("questionId", questionId);
  92. record.put("userAnswer", userAnswer);
  93. record.put("isCorrect", isCorrect ? 1 : 0);
  94. record.put("timeSpent", timeSpent);
  95. answerRecords.add(record);
  96. }
  97. int total = correctCount + wrongCount;
  98. BigDecimal correctRate = total > 0 ? BigDecimal.valueOf(correctCount * 100.0 / total).setScale(0, RoundingMode.HALF_UP) : BigDecimal.ZERO;
  99. // 保存做题记录
  100. QuizUserRecord record = QuizUserRecord.builder()
  101. .userId(userId)
  102. .answerType(2)
  103. .totalCount(total)
  104. .correctCount(correctCount)
  105. .wrongCount(wrongCount)
  106. .correctRate(correctRate)
  107. .answers(answerRecords)
  108. .status(1)
  109. .startTime(LocalDateTime.now())
  110. .endTime(LocalDateTime.now())
  111. .build();
  112. userRecordMapper.insert(record);
  113. return PracticeSubmitVO.builder()
  114. .correctCount(correctCount)
  115. .wrongCount(wrongCount)
  116. .correctRate(correctRate)
  117. .results(results)
  118. .build();
  119. }
  120. private String getTypeName(Integer type) {
  121. if (type == null) return "";
  122. return switch (type) {
  123. case 1 -> "最佳选择题";
  124. case 2 -> "多项选择题";
  125. case 3 -> "配伍选择题";
  126. case 4 -> "综合分析选择题";
  127. default -> "";
  128. };
  129. }
  130. }