package nju.seec.helper.service.impl; import cn.hutool.core.util.StrUtil; import com.google.common.collect.Maps; import nju.seec.helper.aspect.auth.LoginUser; import nju.seec.helper.dao.QuizDAO; import nju.seec.helper.dao.QuizStudentAnswerDAO; import nju.seec.helper.dao.UserDAO; import nju.seec.helper.dto.question.StudentAnswerDTO; import nju.seec.helper.entity.Quiz; import nju.seec.helper.entity.QuizStudentAnswer; import nju.seec.helper.entity.User; import nju.seec.helper.enums.ExceptionType; import nju.seec.helper.exception.HelperException; import nju.seec.helper.service.QuestionService; import nju.seec.helper.service.QuizStudentAnswerService; import nju.seec.helper.vo.question.BaseQuestionVO; import nju.seec.helper.vo.quiz.QuizStudentAnswerStatisticVO; import nju.seec.helper.vo.quiz.QuizStudentAnswerVO; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; /** * @author cst */ @Service public class QuizStudentAnswerServiceImpl implements QuizStudentAnswerService { private final QuizDAO quizDAO; private final UserDAO userDAO; private final QuizStudentAnswerDAO quizStudentAnswerDAO; private final QuestionService questionService; public QuizStudentAnswerServiceImpl(QuizDAO quizDAO, UserDAO userDAO, QuizStudentAnswerDAO quizStudentAnswerDAO, QuestionService questionService) { this.quizDAO = quizDAO; this.userDAO = userDAO; this.quizStudentAnswerDAO = quizStudentAnswerDAO; this.questionService = questionService; } @Transactional(rollbackFor = Exception.class) @Override public QuizStudentAnswerVO submitQuizStudentAnswer(LoginUser user, Long quizId, StudentAnswerDTO studentAnswerDTO) { Quiz quiz = quizDAO.findQuizById(quizId); switch (quiz.getState()) { case NOT_STARTED: throw HelperException.of(ExceptionType.FORBIDDEN, "测试未开始,无法提交"); case CLOSED: throw HelperException.of(ExceptionType.FORBIDDEN, "测试已关闭,无法提交"); default: break; } User student = userDAO.findUserById(user.getId()); QuizStudentAnswer quizStudentAnswer = quizStudentAnswerDAO.findByQuizAndStudent(quiz, student).orElse(new QuizStudentAnswer()); if (quizStudentAnswer.getSubmitNumber() >= quiz.getMaxSubmitNumber()) { throw HelperException.of(ExceptionType.FORBIDDEN, StrUtil.format("已达最大提交次数{}次,无法再提交", quiz.getMaxSubmitNumber())); } // 计算得分 List questionVOList = questionService.getQuestionsByIds(quiz.getQuestions()); AtomicInteger correct = new AtomicInteger(); Map records = studentAnswerDTO.getRecords(); questionVOList.forEach(baseQuestionVO -> { String questionId = baseQuestionVO.getId(); Object answer; if (records.get(questionId) != null) { answer = records.get(questionId).getAnswer(); } else { answer = quizStudentAnswer.getAnswers().get(questionId); } if (baseQuestionVO.pass(answer)) { correct.getAndIncrement(); } quizStudentAnswer.getAnswers().put(questionId, answer); }); BigDecimal score = BigDecimal.valueOf(correct.get() * 100).divide(BigDecimal.valueOf(questionVOList.size()), 2, RoundingMode.HALF_UP); // 计算完毕 quizStudentAnswer.setQuiz(quiz) .setStudent(student) .setSubmitNumber(quizStudentAnswer.getSubmitNumber() + 1) .setScore(score); questionService.record(user, studentAnswerDTO); return new QuizStudentAnswerVO(quizStudentAnswerDAO.save(quizStudentAnswer), questionVOList); } @Transactional(readOnly = true) @Override public Page getQuizStudentAnswers(LoginUser user, Long quizId, String key, Pageable pageable) { return quizStudentAnswerDAO.findByQuizIdAndKey(quizId, key, pageable).map(quizStudentAnswer -> new QuizStudentAnswerVO(quizStudentAnswer, questionService.getQuestionsByIds(quizDAO.findQuizById(quizId).getQuestions()))); } @Transactional(readOnly = true) @Override public QuizStudentAnswerVO getQuizStudentAnswer(LoginUser user, Long quizId) { return quizStudentAnswerDAO .findByQuizAndStudent(quizDAO.findQuizById(quizId), userDAO.findUserById(user.getId())) .map(quizStudentAnswer -> new QuizStudentAnswerVO(quizStudentAnswer, questionService.getQuestionsByIds(quizDAO.findQuizById(quizId).getQuestions()))) .orElse(null); } @Transactional(readOnly = true) @Override public QuizStudentAnswerStatisticVO getQuizStudentAnswerStatistic(LoginUser user, Long quizId) { List quizStudentAnswers = quizStudentAnswerDAO.findByQuiz(quizDAO.findQuizById(quizId)); Map scores = Maps.newHashMapWithExpectedSize(quizStudentAnswers.size()); Map submitNums = Maps.newHashMapWithExpectedSize(quizStudentAnswers.size()); quizStudentAnswers.forEach( quizStudentAnswer -> { scores.merge(quizStudentAnswer.getScore(), 1, Integer::sum); submitNums.merge(quizStudentAnswer.getSubmitNumber(), 1, Integer::sum); } ); return QuizStudentAnswerStatisticVO.of(quizId, scores, submitNums); } }