QuestionServiceImpl.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. package nju.seec.helper.service.impl;
  2. import cn.hutool.core.util.IdUtil;
  3. import com.google.common.collect.Lists;
  4. import nju.seec.helper.aspect.auth.LoginUser;
  5. import nju.seec.helper.dao.*;
  6. import nju.seec.helper.dto.question.BaseQuestionDTO;
  7. import nju.seec.helper.dto.question.StudentAnswerDTO;
  8. import nju.seec.helper.entity.QuestionRecord;
  9. import nju.seec.helper.entity.Quiz;
  10. import nju.seec.helper.enums.ExceptionType;
  11. import nju.seec.helper.enums.QuizState;
  12. import nju.seec.helper.enums.UserRole;
  13. import nju.seec.helper.exception.HelperException;
  14. import nju.seec.helper.service.QuestionService;
  15. import nju.seec.helper.sys.bok.api.QuestionApi;
  16. import nju.seec.helper.sys.bok.api.QuestionQueryApi;
  17. import nju.seec.helper.sys.bok.api.RecordApi;
  18. import nju.seec.helper.sys.bok.api.UserInteractiveApi;
  19. import nju.seec.helper.sys.bok.dto.CollectDTO;
  20. import nju.seec.helper.sys.bok.dto.RateDTO;
  21. import nju.seec.helper.sys.bok.dto.RecordDTO;
  22. import nju.seec.helper.sys.bok.vo.InteractiveVO;
  23. import nju.seec.helper.sys.bok.vo.QuestionVO;
  24. import nju.seec.helper.sys.bok.vo.RecordQuestionVO;
  25. import nju.seec.helper.sys.dataanalysis.api.ExerciseApi;
  26. import nju.seec.helper.sys.dataanalysis.model.ExerciseRecord;
  27. import nju.seec.helper.sys.ml.api.RecommendationApi;
  28. import nju.seec.helper.vo.question.BaseQuestionVO;
  29. import org.springframework.beans.factory.annotation.Autowired;
  30. import org.springframework.data.domain.Page;
  31. import org.springframework.data.domain.PageImpl;
  32. import org.springframework.data.domain.Pageable;
  33. import org.springframework.stereotype.Service;
  34. import org.springframework.transaction.annotation.Transactional;
  35. import java.util.Collections;
  36. import java.util.List;
  37. import java.util.Map;
  38. import java.util.Set;
  39. import java.util.stream.Collectors;
  40. /**
  41. * @author xst
  42. * <p>
  43. * updated by cst
  44. */
  45. @Service
  46. public class QuestionServiceImpl implements QuestionService {
  47. private final QuizDAO quizDAO;
  48. private final UserDAO userDAO;
  49. private final QuestionRecordDAO questionRecordDAO;
  50. private final ChooseDAO chooseDAO;
  51. private final CourseDAO courseDAO;
  52. private final QuestionApi questionApi;
  53. private final QuestionQueryApi questionQueryApi;
  54. private final UserInteractiveApi userInteractiveApi;
  55. private final RecordApi recordApi;
  56. private final RecommendationApi recommendationApi;
  57. private final ExerciseApi exerciseApi;
  58. @Autowired
  59. public QuestionServiceImpl(QuizDAO quizDAO
  60. , UserDAO userDAO
  61. , QuestionRecordDAO questionRecordDAO
  62. , ChooseDAO chooseDAO
  63. , CourseDAO courseDAO
  64. , QuestionApi questionApi
  65. , QuestionQueryApi questionQueryApi
  66. , UserInteractiveApi userInteractiveApi
  67. , RecordApi recordApi
  68. , RecommendationApi recommendationApi
  69. , ExerciseApi exerciseApi
  70. ) {
  71. this.quizDAO = quizDAO;
  72. this.userDAO = userDAO;
  73. this.questionRecordDAO = questionRecordDAO;
  74. this.chooseDAO = chooseDAO;
  75. this.courseDAO = courseDAO;
  76. this.questionApi = questionApi;
  77. this.questionQueryApi = questionQueryApi;
  78. this.userInteractiveApi = userInteractiveApi;
  79. this.recordApi = recordApi;
  80. this.recommendationApi = recommendationApi;
  81. this.exerciseApi = exerciseApi;
  82. }
  83. @Override
  84. public Page<BaseQuestionVO> getQuestions(LoginUser user, String stem, String tag, String knowledgeId, Pageable pageable) {
  85. return questionApi.getQuestionList(stem, tag, knowledgeId, pageable).map(bokQuestion -> BaseQuestionVO.convertBokQuestionToVO(bokQuestion, true));
  86. }
  87. @Transactional(readOnly = true)
  88. @Override
  89. public List<BaseQuestionVO> getQuestionsByQuizId(LoginUser user, Long quizId) {
  90. Quiz quiz = quizDAO.findQuizById(quizId);
  91. return questionQueryApi.getQuestionListById(quiz.getQuestions())
  92. .stream()
  93. .map(bokQuestion -> BaseQuestionVO.convertBokQuestionToVO(bokQuestion, quiz.getState() == QuizState.CLOSED || user.getRole() == UserRole.TEACHER))
  94. .collect(Collectors.toList());
  95. }
  96. @Override
  97. public List<BaseQuestionVO> getQuestionsByIds(List<String> questionIds) {
  98. return questionQueryApi.getQuestionListById(questionIds)
  99. .stream()
  100. .map(bokQuestion -> BaseQuestionVO.convertBokQuestionToVO(bokQuestion, true))
  101. .collect(Collectors.toList());
  102. }
  103. @Override
  104. public BaseQuestionVO getOneQuestion(LoginUser user, String questionId) {
  105. return BaseQuestionVO.convertBokQuestionToVO(questionApi.getQuestionsById(questionId), true);
  106. }
  107. @Transactional(rollbackFor = Exception.class)
  108. @Override
  109. public BaseQuestionVO createQuestion(LoginUser user, BaseQuestionDTO baseQuestionDTO) {
  110. String questionId;
  111. do {
  112. // 保证不产生重复QuestionId
  113. questionId = IdUtil.fastSimpleUUID();
  114. } while (questionRecordDAO.existsByQuestionId(questionId));
  115. QuestionVO questionVO = questionApi.createQuestion(questionId, baseQuestionDTO);
  116. questionRecordDAO.save(new QuestionRecord()
  117. .setTeacher(userDAO.findUserById(user.getId()))
  118. .setQuestionId(questionVO.getId()));
  119. return BaseQuestionVO.convertBokQuestionToVO(questionVO, true);
  120. }
  121. @Transactional(readOnly = true)
  122. @Override
  123. public BaseQuestionVO modifyQuestion(LoginUser user, String questionId, BaseQuestionDTO baseQuestionDTO) {
  124. QuestionRecord questionRecord = questionRecordDAO.findByTeacherAndQuestionId(userDAO.findUserById(user.getId()), questionId)
  125. .orElseThrow(() -> HelperException.of(ExceptionType.FORBIDDEN, "您无权修改该问题"));
  126. QuestionVO questionVO = questionApi.updateQuestion(questionId, baseQuestionDTO);
  127. questionRecordDAO.save(questionRecord);
  128. return BaseQuestionVO.convertBokQuestionToVO(questionVO, true);
  129. }
  130. @Transactional(rollbackFor = Exception.class)
  131. @Override
  132. public void deleteQuestion(LoginUser user, String questionId) {
  133. QuestionRecord questionRecord = questionRecordDAO.findByTeacherAndQuestionId(userDAO.findUserById(user.getId()), questionId)
  134. .orElseThrow(() -> HelperException.of(ExceptionType.FORBIDDEN, "您无权删除该问题"));
  135. questionApi.deleteQuestion(questionId);
  136. questionRecordDAO.delete(questionRecord);
  137. }
  138. @Transactional(readOnly = true)
  139. @Override
  140. public Page<BaseQuestionVO> getCreatedQuestions(LoginUser user, Pageable pageable) {
  141. Page<String> questionIdPage = questionRecordDAO.findQuestionIdsByTeacher(userDAO.findUserById(user.getId()), pageable);
  142. return new PageImpl<>(
  143. questionQueryApi.getQuestionListById(questionIdPage.getContent())
  144. .stream()
  145. .map(bokQuestion -> BaseQuestionVO.convertBokQuestionToVO(bokQuestion, true))
  146. .collect(Collectors.toList())
  147. , pageable
  148. , questionIdPage.getTotalElements()
  149. );
  150. }
  151. @Transactional(readOnly = true)
  152. @Override
  153. public Set<String> getIdsOfCreatedQuestions(LoginUser user) {
  154. return questionRecordDAO.findQuestionIdsByTeacher(userDAO.findUserById(user.getId()));
  155. }
  156. @Override
  157. public void collectQuestion(LoginUser user, String questionId, CollectDTO collectDTO) {
  158. userInteractiveApi.collectQuestion(String.valueOf(user.getPid()), questionId, collectDTO);
  159. }
  160. @Override
  161. public void rateQuestion(LoginUser user, String questionId, RateDTO rateDTO) {
  162. userInteractiveApi.rateQuestion(String.valueOf(user.getPid()), questionId, rateDTO);
  163. }
  164. @Transactional(readOnly = true)
  165. @Override
  166. public Page<BaseQuestionVO> getCollectedAndRatedQuestions(LoginUser user, Boolean collect, Boolean rate, Pageable pageable) {
  167. return convert(user, userInteractiveApi.getCollectAndRateQuestions(String.valueOf(user.getPid()), collect, rate, pageable));
  168. }
  169. @Transactional(readOnly = true)
  170. @Override
  171. public Page<BaseQuestionVO> getCompletedQuestions(LoginUser user, Pageable pageable) {
  172. RecordQuestionVO recordQuestionVO = recordApi.getUserRecordQuestions(String.valueOf(user.getPid()), pageable);
  173. return convert(user, new PageImpl<>(recordQuestionVO.getQuestions(), pageable, recordQuestionVO.getPage().getTotalElements()));
  174. }
  175. @Override
  176. public List<InteractiveVO> getInteractiveList(LoginUser user, String questionId) {
  177. return userInteractiveApi.getInteractive(String.valueOf(user.getPid()), questionId);
  178. }
  179. @Override
  180. public List<BaseQuestionVO> getRecommendationQuestions(LoginUser user, List<String> knowledgeId, Integer questionNum) {
  181. return questionQueryApi.getQuestionListById(recommendationApi.getRecommendResult(String.valueOf(user.getPid()), knowledgeId, questionNum))
  182. .stream()
  183. .map(questionVO -> BaseQuestionVO.convertBokQuestionToVO(questionVO, true))
  184. .collect(Collectors.toList());
  185. }
  186. @Transactional(readOnly = true)
  187. @Override
  188. public List<BaseQuestionVO> getRecommendationQuestionsByCourse(LoginUser user, Long courseId, Integer questionNum) {
  189. return this.getRecommendationQuestions(user, courseDAO.findCourseById(courseId).getKnowledgeId(), questionNum);
  190. }
  191. @Override
  192. public void record(LoginUser user, StudentAnswerDTO studentAnswerDTO) {
  193. if (studentAnswerDTO.getRecords() == null || studentAnswerDTO.getRecords().isEmpty()) {
  194. return;
  195. }
  196. Map<String, StudentAnswerDTO.AnswerRecordDTO> recordMap = studentAnswerDTO.getRecords()
  197. .entrySet()
  198. .stream()
  199. .filter(entry -> entry.getValue().getStartAt().isBefore(entry.getValue().getEndAt()))
  200. .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
  201. if (recordMap.isEmpty()) {
  202. return;
  203. }
  204. List<BaseQuestionVO> baseQuestionVOList = questionQueryApi.getQuestionListById(Lists.newArrayList(recordMap.keySet()))
  205. .stream()
  206. .map(questionVO -> BaseQuestionVO.convertBokQuestionToVO(questionVO, true))
  207. .collect(Collectors.toList());
  208. // 创建两个列表
  209. int size = recordMap.size();
  210. List<ExerciseRecord> exerciseRecords = Lists.newArrayListWithExpectedSize(size);
  211. List<RecordDTO> records = Lists.newArrayListWithExpectedSize(size);
  212. // 填充列表
  213. String userId = String.valueOf(user.getPid());
  214. baseQuestionVOList.forEach(baseQuestionVO -> {
  215. String questionId = baseQuestionVO.getId();
  216. StudentAnswerDTO.AnswerRecordDTO answerRecord = recordMap.get(questionId);
  217. Object answer = answerRecord.getAnswer();
  218. Boolean pass = baseQuestionVO.pass(answer);
  219. exerciseRecords.add(exerciseApi.createExerciseRecordDTO(userId, questionId, answerRecord.getStartAt(), answerRecord.getEndAt(), pass));
  220. records.add(recordApi.createRecordDTO(userId, questionId, answer, pass, answerRecord.getStartAt(), answerRecord.getEndAt()));
  221. });
  222. exerciseApi.reportExercise(exerciseRecords);
  223. recordApi.reportUserRecord(records);
  224. }
  225. private static final Set<QuizState> HIDE_QUESTION_ANSWER_STATES = Collections.singleton(QuizState.ONGOING);
  226. private Page<BaseQuestionVO> convert(LoginUser user, Page<QuestionVO> questionVOList) {
  227. List<String> hideQuestionIds = quizDAO.findByCourseIdInAndStateIn(chooseDAO.findCourseIdsByStudentId(user.getId()), HIDE_QUESTION_ANSWER_STATES)
  228. .stream()
  229. .flatMap(quiz -> quiz.getQuestions().stream())
  230. .collect(Collectors.toList());
  231. return questionVOList.map(questionVO -> BaseQuestionVO.convertBokQuestionToVO(questionVO, !hideQuestionIds.contains(questionVO.getId())));
  232. }
  233. }