|
|
@@ -0,0 +1,347 @@
|
|
|
+package nju.seec.helper.service.impl;
|
|
|
+
|
|
|
+import nju.seec.helper.dao.*;
|
|
|
+import nju.seec.helper.dto.QuestionStudentAnswerDTO;
|
|
|
+import nju.seec.helper.entity.*;
|
|
|
+import nju.seec.helper.service.QuizService;
|
|
|
+import nju.seec.helper.util.BokUtil;
|
|
|
+import nju.seec.helper.util.enums.ExceptionType;
|
|
|
+import nju.seec.helper.util.enums.QuizState;
|
|
|
+import nju.seec.helper.util.enums.SlideState;
|
|
|
+import nju.seec.helper.util.enums.UserType;
|
|
|
+import nju.seec.helper.util.exception.HelperException;
|
|
|
+import nju.seec.helper.vo.quiz.BaseQuestionVO;
|
|
|
+import nju.seec.helper.vo.quiz.QuizResultVO;
|
|
|
+import nju.seec.helper.vo.quiz.QuizVO;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.data.domain.Page;
|
|
|
+import org.springframework.data.domain.Pageable;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+import org.springframework.util.Assert;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@Service
|
|
|
+public class QuizServiceImpl implements QuizService {
|
|
|
+ private final SlideDAO slideDAO;
|
|
|
+ private final QuizDAO quizDAO;
|
|
|
+ private final QuizStudentAnswerDAO quizStudentAnswerDAO;
|
|
|
+ private final ChooseDAO chooseDAO;
|
|
|
+ private final CourseDAO courseDAO;
|
|
|
+ private final UserDAO userDAO;
|
|
|
+ private final BokUtil bokUtil;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ public QuizServiceImpl(SlideDAO slideDAO, QuizDAO quizDAO, QuizStudentAnswerDAO quizStudentAnswerDAO, ChooseDAO chooseDAO, CourseDAO courseDAO, UserDAO userDAO, BokUtil bokUtil) {
|
|
|
+ this.slideDAO = slideDAO;
|
|
|
+ this.quizDAO = quizDAO;
|
|
|
+ this.quizStudentAnswerDAO = quizStudentAnswerDAO;
|
|
|
+ this.chooseDAO = chooseDAO;
|
|
|
+ this.courseDAO = courseDAO;
|
|
|
+ this.userDAO = userDAO;
|
|
|
+ this.bokUtil = bokUtil;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Quiz createQuiz(String name, Long uid, SlideState quizTime,
|
|
|
+ Long slideId, List<String> questions){
|
|
|
+ User teacher =new User();
|
|
|
+ teacher.setId(uid);
|
|
|
+ Slide slide = slideDAO.findSlideById(slideId);
|
|
|
+ Course course = new Course();
|
|
|
+ course.setId(slide.getCourseId());
|
|
|
+ Quiz quiz = new Quiz();
|
|
|
+
|
|
|
+ quiz.setCourse(course);
|
|
|
+ quiz.setName(name);
|
|
|
+ quiz.setQuestions(questions);
|
|
|
+ quiz.setQuizTime(quizTime);
|
|
|
+ quiz.setSlide(slide);
|
|
|
+ quiz.setTeacher(teacher);
|
|
|
+
|
|
|
+ checkQuizState(quiz,slide);
|
|
|
+
|
|
|
+ quiz=quizDAO.saveAndFlush(quiz);
|
|
|
+ return quiz;
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public String deleteQuiz(Long quizId) {
|
|
|
+ Quiz quiz =quizDAO.findQuizById(quizId);
|
|
|
+ if(quiz.getState()!=QuizState.NOT_STARTED){throw HelperException.of(ExceptionType.FORBIDDEN,"不能删除已经开始的测试!");}
|
|
|
+ quizDAO.delete(quiz);
|
|
|
+ return "delete success";
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Quiz modifyQuiz(Long quizId, String name, List<String> questions, SlideState quizTime, String slideId) {
|
|
|
+
|
|
|
+ Quiz quiz =quizDAO.findQuizById(quizId);
|
|
|
+ if(quiz.getState()!=QuizState.NOT_STARTED){throw HelperException.of(ExceptionType.FORBIDDEN,"不能修改已经开始的测试!");}
|
|
|
+ if(name!=null) {
|
|
|
+ quiz.setName(name);
|
|
|
+ }
|
|
|
+ if(questions!=null) {
|
|
|
+ quiz.setQuestions(questions);
|
|
|
+ }
|
|
|
+ if(quizTime!=null) {
|
|
|
+ quiz.setQuizTime(quizTime);
|
|
|
+ checkQuizState(quiz,quiz.getSlide());
|
|
|
+ }
|
|
|
+ return quizDAO.saveAndFlush(quiz);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Page<Quiz> getAllBasicQuizByUser(Pageable pageable, QuizState state, Long uid) {
|
|
|
+ User user=userDAO.findUserById(uid);
|
|
|
+ //todo: 这里写的太狗屎了,可以用重写sql或者用实例查询
|
|
|
+ if(user.getType().equals(UserType.STUDENT)){
|
|
|
+ final Set<Long> courseIdsByStudentId = chooseDAO.findCourseIdsByStudentId(uid);
|
|
|
+ final Set<Course> collect = courseIdsByStudentId.stream().map(i -> {
|
|
|
+ Course c = new Course();
|
|
|
+ c.setId(i);
|
|
|
+ return c;
|
|
|
+ }).collect(Collectors.toSet());
|
|
|
+ if(state!=null){
|
|
|
+ return quizDAO.findAllByCourseInAndState(collect,state,pageable);
|
|
|
+ }else{
|
|
|
+ return quizDAO.findAllByCourseIn(collect,pageable);
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ if(state!=null){
|
|
|
+ return quizDAO.findByTeacherAndState(user,state,pageable);
|
|
|
+ }else{
|
|
|
+ return quizDAO.findByTeacher(user,pageable);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<QuizResultVO> getQuizResult(Long quizId) {
|
|
|
+ Assert.notNull(quizId,"错误的测试!");
|
|
|
+ final Quiz quiz = quizDAO.findQuizById(quizId);
|
|
|
+ if(quiz.getState()!=QuizState.CLOSED){throw new RuntimeException("测试未关闭,无法得到测试结果");}
|
|
|
+ List<QuizResultVO> retList=new ArrayList<>();
|
|
|
+ final List<StudentScore> studentScoreList = quiz.getStudentScore();
|
|
|
+ Map<Long,List<QuizStudentAnswer>> idQuizStudentAnswerMap=new HashMap<>();
|
|
|
+ for(QuizStudentAnswer qsa:quizStudentAnswerDAO.findAllByQuiz(quiz)){
|
|
|
+ idQuizStudentAnswerMap.computeIfAbsent(qsa.getStudent().getId(), k -> new ArrayList<>());
|
|
|
+ idQuizStudentAnswerMap.get(qsa.getStudent().getId()).add(qsa);
|
|
|
+ }
|
|
|
+ for(StudentScore studentScore:studentScoreList){
|
|
|
+ final User student = studentScore.getStudent();
|
|
|
+ final List<QuizStudentAnswer> list = idQuizStudentAnswerMap.get(student.getId());
|
|
|
+ retList.add(new QuizResultVO(studentScore,student,list));
|
|
|
+ }
|
|
|
+ return retList;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void modifySlideState(Slide slide) {
|
|
|
+ final List<Quiz> quizzes = quizDAO.findAllBySlide(slide);
|
|
|
+ quizzes.forEach(quiz->checkQuizState(quiz,slide));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Integer upStudentAnswer(Long quizId, Long uid, List<QuestionStudentAnswerDTO> answers) {
|
|
|
+ Assert.notNull(quizId,"错误的测试!");
|
|
|
+ final Quiz quiz = quizDAO.findQuizById(quizId);
|
|
|
+ if(quiz.getState()!=QuizState.ONGOING){throw HelperException.of(ExceptionType.FORBIDDEN,"不能提交尚未开始的作业!");}
|
|
|
+ User student =new User();student.setId(uid);
|
|
|
+ Set<QuizStudentAnswer> quizAnswers = quizStudentAnswerDAO.findByStudentAndQuiz(student,quiz);
|
|
|
+ Set<String> questionIdSet = new HashSet<>(quiz.getQuestions());
|
|
|
+ Map<String,QuizStudentAnswer> qsaMap=new HashMap<>(questionIdSet.size());
|
|
|
+ for(QuizStudentAnswer qsa: quizAnswers){
|
|
|
+ qsaMap.put(qsa.getQuestionId(),qsa);
|
|
|
+ }
|
|
|
+ //确定被更新或者新建的学生答案提交
|
|
|
+ List<QuizStudentAnswer> quizStudentAnswers=new ArrayList<>();
|
|
|
+ for(QuestionStudentAnswerDTO studentAnswer:answers){
|
|
|
+ String id = studentAnswer.getQuestionId();
|
|
|
+ String answer = studentAnswer.getStudentAnswer().toString();
|
|
|
+ if(!questionIdSet.contains(id)){break;}
|
|
|
+ if(qsaMap.get(id)!=null){
|
|
|
+ if(qsaMap.get(id).getStudentAnswer().equals(answer)){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ qsaMap.get(id).setStudentAnswer(answer);
|
|
|
+ System.out.println(answer);
|
|
|
+ quizStudentAnswers.add(qsaMap.get(id));
|
|
|
+ }else {
|
|
|
+ QuizStudentAnswer qsa=QuizStudentAnswer.builder()
|
|
|
+ .questionId(id).quiz(quiz).student(student).studentAnswer(answer)
|
|
|
+ .build();
|
|
|
+ quizStudentAnswers.add(qsa);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ Integer savedNum=quizStudentAnswers.size();
|
|
|
+ quizStudentAnswerDAO.saveAll(quizStudentAnswers);
|
|
|
+ return savedNum;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Page<Quiz> getAllBasicQuizBySlide(Long slideId, Pageable pageable, QuizState state, Long uid) {
|
|
|
+ Assert.notNull(slideId,"错误的幻灯片!");
|
|
|
+ Slide slide=new Slide();
|
|
|
+ slide.setId(slideId);
|
|
|
+ if(state!=null) {
|
|
|
+ return quizDAO.findAllBySlideAndState(slide, state, pageable);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return quizDAO.findAllBySlide(slide, pageable);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public QuizState checkQuizState(Quiz quiz, Slide slide) {
|
|
|
+ int quizTime = quiz.getQuizTime().getNum();
|
|
|
+ int slideTime = slide.getState().getNum();
|
|
|
+ if (quiz.getId() == null){
|
|
|
+ //未持久化的quiz
|
|
|
+ quiz.setState(slideTime < quizTime ? QuizState.NOT_STARTED : QuizState.ONGOING);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ //持久化后,不仅仅需要推进状态,还需要判分,保存等步骤
|
|
|
+ if (slideTime < quizTime) {
|
|
|
+ if(quiz.getState().equals(QuizState.NOT_STARTED)){return QuizState.NOT_STARTED;}
|
|
|
+ //未开始
|
|
|
+ quiz.setState(QuizState.NOT_STARTED);
|
|
|
+ } else if (slideTime == quizTime) {
|
|
|
+ if(quiz.getState().equals(QuizState.ONGOING)){return QuizState.ONGOING;}
|
|
|
+ quiz.setState(QuizState.ONGOING);
|
|
|
+ } else {
|
|
|
+ if(quiz.getState().equals(QuizState.CLOSED)){return QuizState.CLOSED;}
|
|
|
+ quiz.setState(QuizState.CLOSED);
|
|
|
+ Set<QuizStudentAnswer> quizAnswers = quizStudentAnswerDAO.findAllByQuiz(quiz);
|
|
|
+ final Set<Long> studentIds = chooseDAO.findStudentIdsByCourseId(slide.getCourseId());
|
|
|
+ Student2QuestionId2Answer triadMap = new Student2QuestionId2Answer(studentIds, quiz.getQuestions().size());
|
|
|
+ //将已经作答的学生答案加入
|
|
|
+ for (QuizStudentAnswer answers : quizAnswers) {
|
|
|
+ triadMap.addAnswer(answers);
|
|
|
+ }
|
|
|
+ //生成未作答的学生答案
|
|
|
+ triadMap.fullAnswer(quiz);
|
|
|
+ //检查答案,赋分
|
|
|
+ triadMap.checkAnswerAndFullPass(bokUtil.bokFindByIdIn(quiz.getQuestions()), quiz);
|
|
|
+ //保存现场
|
|
|
+ quizStudentAnswerDAO.saveAll(triadMap.getAll());
|
|
|
+ }
|
|
|
+
|
|
|
+ quizDAO.save(quiz);
|
|
|
+ }
|
|
|
+ return quiz.getState();
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public QuizState checkQuizState(Long quizId, Long slideId){
|
|
|
+ Quiz quiz=quizDAO.findQuizById(quizId);
|
|
|
+ Slide slide=slideDAO.findSlideById(slideId);
|
|
|
+ return checkQuizState(quiz,slide);
|
|
|
+ }
|
|
|
+ private class Student2QuestionId2Answer {
|
|
|
+ Map<Long,Map<String,QuizStudentAnswer>> student2QuestionId2Answer;
|
|
|
+ Student2QuestionId2Answer(Set<Long> studentIds, Integer quizQuestionSize) {
|
|
|
+ student2QuestionId2Answer =new LinkedHashMap<>(studentIds.size());
|
|
|
+ for(Long studentId:studentIds){
|
|
|
+ Map<String,QuizStudentAnswer> questionId2Answer= new LinkedHashMap<>(quizQuestionSize);
|
|
|
+ student2QuestionId2Answer.put(studentId,questionId2Answer);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ void addAnswer(QuizStudentAnswer answers){
|
|
|
+ Map<String, QuizStudentAnswer> stringQuizStudentAnswerMap = student2QuestionId2Answer.get(answers.getStudent().getId());
|
|
|
+ if(stringQuizStudentAnswerMap==null){
|
|
|
+ return ;
|
|
|
+ }
|
|
|
+ stringQuizStudentAnswerMap.put(answers.getQuestionId(),answers);
|
|
|
+ }
|
|
|
+ void fullAnswer(Quiz quiz){
|
|
|
+ List<String> questions=quiz.getQuestions();
|
|
|
+ student2QuestionId2Answer.forEach((studentId, map)->{
|
|
|
+ if(questions.size()!=map.size()){
|
|
|
+ for(String questionId:questions){
|
|
|
+ if(map.get(questionId)==null){
|
|
|
+ User student =new User();student.setId(studentId);
|
|
|
+ QuizStudentAnswer qsa=QuizStudentAnswer.builder()
|
|
|
+ .questionId(questionId).quiz(quiz).student(student)
|
|
|
+ .build();
|
|
|
+ map.put(questionId,qsa);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ void checkAnswerAndFullPass(List<BaseQuestionVO> questionVos, Quiz quiz){
|
|
|
+ if(quiz.getStudentScore()==null){quiz.setStudentScore(new ArrayList<>(student2QuestionId2Answer.size()));}
|
|
|
+ student2QuestionId2Answer.forEach((studentId, map)->{
|
|
|
+ int passCount=0;
|
|
|
+ for(BaseQuestionVO vo:questionVos){
|
|
|
+ final String studentAnswer = map.get(vo.getQuestionId()).getStudentAnswer();
|
|
|
+ boolean pass=vo.checkAnswer(studentAnswer);
|
|
|
+ if(pass){passCount++;}
|
|
|
+ map.get(vo.getQuestionId()).setPass(pass);
|
|
|
+ }
|
|
|
+ Double score = (100.0*passCount)/questionVos.size();
|
|
|
+ User student =new User();student.setId(studentId);
|
|
|
+ StudentScore studentScore=new StudentScore();
|
|
|
+ studentScore.setQuizId(quiz.getId());
|
|
|
+ studentScore.setScore(Long.valueOf(Math.round(score)).intValue());
|
|
|
+ studentScore.setStudent(student);
|
|
|
+ quiz.getStudentScore().add(studentScore);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ List<QuizStudentAnswer> getAll(){
|
|
|
+ List<QuizStudentAnswer> list=new ArrayList<>();
|
|
|
+ for(Long sid: student2QuestionId2Answer.keySet()){
|
|
|
+ list.addAll(student2QuestionId2Answer.get(sid).values());
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public QuizVO combineQuiz(Long quizId){
|
|
|
+ Assert.notNull(quizId,"错误的测试!");
|
|
|
+ final Quiz quizById = quizDAO.findQuizById(quizId);
|
|
|
+ final List<BaseQuestionVO> questionVoS = bokUtil.bokFindByIdIn(quizById.getQuestions());
|
|
|
+ return new QuizVO(quizById,questionVoS);
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public QuizVO combineQuizWithAnswer(Long quizId, Long uid,UserType userType){
|
|
|
+ Assert.notNull(quizId,"错误的测试!");
|
|
|
+ final Quiz quizById = quizDAO.findQuizById(quizId);
|
|
|
+ User student =new User();
|
|
|
+ student.setId(uid);
|
|
|
+
|
|
|
+ if(userType==null||userType.equals(UserType.TEACHER)){
|
|
|
+ //向老师展示
|
|
|
+ List<BaseQuestionVO> questionVoS = bokUtil.bokFindByIdIn(quizById.getQuestions());
|
|
|
+ return new QuizVO(quizById,questionVoS);
|
|
|
+ }
|
|
|
+ if(quizById.getState().equals(QuizState.NOT_STARTED)){
|
|
|
+ //未开始看不到题目
|
|
|
+ return new QuizVO(quizById);
|
|
|
+ }
|
|
|
+
|
|
|
+ List<BaseQuestionVO> questionVos = bokUtil.bokFindByIdIn(quizById.getQuestions());
|
|
|
+ final Set<QuizStudentAnswer> quizAnswers = quizStudentAnswerDAO.findByStudentAndQuiz(student,quizById);
|
|
|
+ Map<String,QuizStudentAnswer> qsaMap=new HashMap<>(quizAnswers.size());
|
|
|
+ for(QuizStudentAnswer qsa: quizAnswers){
|
|
|
+ qsaMap.put(qsa.getQuestionId(),qsa);
|
|
|
+ }
|
|
|
+ for(BaseQuestionVO vo:questionVos){
|
|
|
+ if(qsaMap.get(vo.getQuestionId())!=null){
|
|
|
+ vo.exAddAnswer(qsaMap.get(vo.getQuestionId()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return new QuizVO(quizById,questionVos);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|