package com.xuekairui.quiz.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.xuekairui.quiz.dto.AnswerItem; import com.xuekairui.quiz.entity.QuizQuestion; import com.xuekairui.quiz.entity.QuizUserRecord; import com.xuekairui.quiz.mapper.QuizQuestionMapper; import com.xuekairui.quiz.mapper.QuizUserRecordMapper; import com.xuekairui.quiz.service.DailyPracticeService; import com.xuekairui.quiz.vo.DailyPracticeQuestionsVO; import com.xuekairui.quiz.vo.PracticeResultVO; import com.xuekairui.quiz.vo.PracticeSubmitVO; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Random; import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class DailyPracticeServiceImpl implements DailyPracticeService { private final QuizQuestionMapper questionMapper; private final QuizUserRecordMapper userRecordMapper; @Override public DailyPracticeQuestionsVO getQuestions(Long userId) { LocalDate today = LocalDate.now(); LocalDateTime todayStart = today.atStartOfDay(); // 检查今天是否已完成 long doneCount = userRecordMapper.selectCount( new LambdaQueryWrapper() .eq(QuizUserRecord::getUserId, userId) .eq(QuizUserRecord::getAnswerType, 2) .ge(QuizUserRecord::getCreateTime, todayStart) .eq(QuizUserRecord::getStatus, 1) ); boolean hasDone = doneCount > 0; // 按日期种子随机抽取10道题(同一天同一用户题目固定) long seed = today.toEpochDay() + userId; Random random = new Random(seed); List allQuestions = questionMapper.selectList( new LambdaQueryWrapper().eq(QuizQuestion::getIsReal, 0)); Collections.shuffle(allQuestions, random); List selected = allQuestions.stream().limit(10).collect(Collectors.toList()); List questionList = new ArrayList<>(); for (QuizQuestion q : selected) { questionList.add(DailyPracticeQuestionsVO.DailyQuestionVO.builder() .id(q.getId()) .questionType(q.getQuestionType()) .questionTypeName(getTypeName(q.getQuestionType())) .stem(q.getStem()) .options(q.getOptions()) .build()); } return DailyPracticeQuestionsVO.builder() .date(today.toString()) .questionCount(selected.size()) .hasDone(hasDone) .questions(questionList) .build(); } @Override @Transactional public PracticeSubmitVO submit(Long userId, List answers) { int correctCount = 0; int wrongCount = 0; List results = new ArrayList<>(); List> answerRecords = new ArrayList<>(); for (AnswerItem ans : answers) { Long questionId = ans.getQuestionId(); String userAnswer = ans.getUserAnswer(); Integer timeSpent = ans.getTimeSpent() != null ? ans.getTimeSpent() : 0; QuizQuestion question = questionMapper.selectById(questionId); if (question == null) continue; boolean isCorrect = question.getAnswer().equalsIgnoreCase(userAnswer); if (isCorrect) correctCount++; else wrongCount++; results.add(PracticeResultVO.builder() .questionId(questionId) .isCorrect(isCorrect ? 1 : 0) .correctAnswer(question.getAnswer()) .analysis(question.getAnalysis()) .build()); Map record = new LinkedHashMap<>(); record.put("questionId", questionId); record.put("userAnswer", userAnswer); record.put("isCorrect", isCorrect ? 1 : 0); record.put("timeSpent", timeSpent); answerRecords.add(record); } int total = correctCount + wrongCount; BigDecimal correctRate = total > 0 ? BigDecimal.valueOf(correctCount * 100.0 / total).setScale(0, RoundingMode.HALF_UP) : BigDecimal.ZERO; // 保存做题记录 QuizUserRecord record = QuizUserRecord.builder() .userId(userId) .answerType(2) .totalCount(total) .correctCount(correctCount) .wrongCount(wrongCount) .correctRate(correctRate) .answers(answerRecords) .status(1) .startTime(LocalDateTime.now()) .endTime(LocalDateTime.now()) .build(); userRecordMapper.insert(record); return PracticeSubmitVO.builder() .correctCount(correctCount) .wrongCount(wrongCount) .correctRate(correctRate) .results(results) .build(); } private String getTypeName(Integer type) { if (type == null) return ""; return switch (type) { case 1 -> "最佳选择题"; case 2 -> "多项选择题"; case 3 -> "配伍选择题"; case 4 -> "综合分析选择题"; default -> ""; }; } }