package nju.seec.helper.service.impl; 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.quiz.QuizStudentAnswerDTO; 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.CourseService; import nju.seec.helper.service.QuestionService; import nju.seec.helper.service.QuizStudentAnswerService; import nju.seec.helper.vo.QuizStudentAnswerStatisticVO; import nju.seec.helper.vo.question.BaseQuestionVO; 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.AtomicReference; /** * @author cst */ @Service public class QuizStudentAnswerServiceImpl implements QuizStudentAnswerService { private final QuizDAO quizDAO; private final UserDAO userDAO; private final QuizStudentAnswerDAO quizStudentAnswerDAO; private final QuestionService questionService; private final CourseService courseService; public QuizStudentAnswerServiceImpl(QuizDAO quizDAO, UserDAO userDAO, QuizStudentAnswerDAO quizStudentAnswerDAO, QuestionService questionService, CourseService courseService) { this.quizDAO = quizDAO; this.userDAO = userDAO; this.quizStudentAnswerDAO = quizStudentAnswerDAO; this.questionService = questionService; this.courseService = courseService; } @Transactional(rollbackFor = Exception.class) @Override public QuizStudentAnswerVO submitQuizStudentAnswer(LoginUser user, Long quizId, QuizStudentAnswerDTO quizStudentAnswerDTO) { Quiz quiz = quizDAO.findQuizById(quizId); if (!courseService.existsCourseResourcesAuth(user, quiz.getCourse().getId())) { throw HelperException.of(ExceptionType.FORBIDDEN, "您无权提交该测试的作答"); } 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, String.format("已达最大提交次数%d次,无法再提交", quiz.getMaxSubmitNumber())); } // 计算得分 List questionVOList = questionService.getQuestionsByQuiz(quiz); AtomicReference correct = new AtomicReference<>(0); Map answers = quizStudentAnswerDTO.getAnswers(); questionVOList.forEach(baseQuestionVO -> { Object answer; if ((answer = answers.get(baseQuestionVO.getId())) != null && baseQuestionVO.pass(answer)) { correct.getAndSet(correct.get() + 1); } }); BigDecimal score = BigDecimal.valueOf(correct.get() * 100).divide(BigDecimal.valueOf(questionVOList.size()), 2, RoundingMode.HALF_UP); // 计算完毕 quizStudentAnswer.setQuiz(quiz) .setStudent(student) .setAnswers(quizStudentAnswerDTO.getAnswers()) .setSubmitNumber(quizStudentAnswer.getSubmitNumber() + 1) .setAnswers(answers) .setScore(score); return new QuizStudentAnswerVO(quizStudentAnswerDAO.save(quizStudentAnswer), questionVOList); } @Transactional(readOnly = true) @Override public Page getQuizStudentAnswers(LoginUser user, Long quizId, Pageable pageable) { return quizStudentAnswerDAO.findByQuiz(quizDAO.findQuizById(quizId), pageable).map(quizStudentAnswer -> new QuizStudentAnswerVO(quizStudentAnswer, questionService.getQuestionsByQuiz(quizDAO.findQuizById(quizId)))); } @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.getQuestionsByQuiz(quizDAO.findQuizById(quizId)))) .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); } }