| | |
| | | package com.ycl.jxkg.service.impl; |
| | | |
| | | import com.alibaba.excel.EasyExcel; |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.github.pagehelper.PageHelper; |
| | | import com.github.pagehelper.PageInfo; |
| | | import com.ycl.jxkg.base.Result; |
| | | import com.ycl.jxkg.domain.entity.Question; |
| | | import com.ycl.jxkg.domain.entity.Subject; |
| | | import com.ycl.jxkg.domain.other.KeyValue; |
| | | import com.ycl.jxkg.domain.Question; |
| | | import com.ycl.jxkg.domain.TextContent; |
| | | import com.ycl.jxkg.domain.enums.QuestionStatusEnum; |
| | | import com.ycl.jxkg.domain.enums.QuestionTypeEnum; |
| | | import com.ycl.jxkg.domain.question.QuestionItemObject; |
| | | import com.ycl.jxkg.domain.question.QuestionObject; |
| | | import com.ycl.jxkg.domain.vo.admin.exam.ExamPaperImportVO; |
| | | import com.ycl.jxkg.domain.vo.admin.exam.QuestionExportVO; |
| | | import com.ycl.jxkg.domain.vo.admin.exam.QuestionImportVO; |
| | | import com.ycl.jxkg.domain.vo.admin.question.QuestionEditItemVO; |
| | | import com.ycl.jxkg.domain.vo.admin.question.QuestionEditRequestVO; |
| | | import com.ycl.jxkg.domain.vo.admin.question.QuestionPageRequestVO; |
| | | import com.ycl.jxkg.domain.vo.admin.question.QuestionResponseVO; |
| | | import com.ycl.jxkg.enums.QuestionTypeEnum; |
| | | import com.ycl.jxkg.enums.general.StatusEnum; |
| | | import com.ycl.jxkg.excel.CurrencyDataListener; |
| | | import com.ycl.jxkg.excel.FixedMergeCellStrategy; |
| | | import com.ycl.jxkg.excel.SelectExcel; |
| | | import com.ycl.jxkg.mapper.QuestionMapper; |
| | | import com.ycl.jxkg.service.QuestionService; |
| | | import com.ycl.jxkg.service.SubjectService; |
| | | import com.ycl.jxkg.service.TextContentService; |
| | | import com.ycl.jxkg.utils.DateTimeUtil; |
| | | import com.ycl.jxkg.utils.JsonUtil; |
| | | import com.ycl.jxkg.utils.ExamUtil; |
| | | import com.ycl.jxkg.vo.admin.question.QuestionEditItemVO; |
| | | import com.ycl.jxkg.vo.admin.question.QuestionEditRequestVO; |
| | | import com.ycl.jxkg.vo.admin.question.QuestionPageRequestVO; |
| | | import com.github.pagehelper.PageHelper; |
| | | import com.github.pagehelper.PageInfo; |
| | | import com.ycl.jxkg.utils.HtmlUtil; |
| | | import com.ycl.jxkg.utils.JsonUtil; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.SneakyThrows; |
| | | import org.springframework.beans.BeanUtils; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.net.URLEncoder; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import java.util.function.Consumer; |
| | | import java.util.stream.Collectors; |
| | | |
| | | @Service |
| | | public class QuestionServiceImpl extends BaseServiceImpl<Question> implements QuestionService { |
| | | @RequiredArgsConstructor |
| | | public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, Question> implements QuestionService { |
| | | |
| | | private final QuestionMapper questionMapper; |
| | | private final TextContentService textContentService; |
| | | private final SubjectService subjectService; |
| | | |
| | | @Autowired |
| | | public QuestionServiceImpl(QuestionMapper questionMapper, TextContentService textContentService, SubjectService subjectService) { |
| | | super(questionMapper); |
| | | this.textContentService = textContentService; |
| | | this.questionMapper = questionMapper; |
| | | this.subjectService = subjectService; |
| | | } |
| | | |
| | | @Override |
| | | public PageInfo<Question> page(QuestionPageRequestVO requestVM) { |
| | | return PageHelper.startPage(requestVM.getPageIndex(), requestVM.getPageSize(), "id desc").doSelectPageInfo(() -> |
| | | public PageInfo<QuestionResponseVO> page(QuestionPageRequestVO requestVM) { |
| | | return PageHelper.startPage(requestVM.getPageIndex(), requestVM.getPageSize(), "create_time desc").doSelectPageInfo(() -> |
| | | questionMapper.page(requestVM) |
| | | ); |
| | | } |
| | |
| | | @Transactional |
| | | public Question insertFullQuestion(QuestionEditRequestVO model, Integer userId) { |
| | | Date now = new Date(); |
| | | Integer gradeLevel = subjectService.levelBySubjectId(model.getSubjectId()); |
| | | |
| | | //题干、解析、选项等 插入 |
| | | TextContent infoTextContent = new TextContent(); |
| | | infoTextContent.setCreateTime(now); |
| | | setQuestionInfoFromVM(infoTextContent, model); |
| | | textContentService.insertByFilter(infoTextContent); |
| | | String questionObject = setQuestionInfoFromVM(model); |
| | | |
| | | Question question = new Question(); |
| | | question.setSubjectId(model.getSubjectId()); |
| | | question.setGradeLevel(gradeLevel); |
| | | question.setCreateTime(now); |
| | | question.setQuestionType(model.getQuestionType()); |
| | | question.setStatus(QuestionStatusEnum.OK.getCode()); |
| | | question.setStatus(StatusEnum.ENABLE); |
| | | question.setCorrectFromVM(model.getCorrect(), model.getCorrectArray()); |
| | | question.setScore(ExamUtil.scoreFromVM(model.getScore())); |
| | | question.setDifficult(model.getDifficult()); |
| | | question.setInfoTextContentId(infoTextContent.getId()); |
| | | question.setContent(questionObject); |
| | | question.setCreateUser(userId); |
| | | question.setDeleted(false); |
| | | questionMapper.insertSelective(question); |
| | | question.setTitle(HtmlUtil.clear(model.getTitle())); |
| | | question.setAudioFile(model.getAudioFile()); |
| | | question.setOriginalFile(model.getOriginalFile()); |
| | | questionMapper.insert(question); |
| | | return question; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional |
| | | public Question updateFullQuestion(QuestionEditRequestVO model) { |
| | | Integer gradeLevel = subjectService.levelBySubjectId(model.getSubjectId()); |
| | | Question question = questionMapper.selectByPrimaryKey(model.getId()); |
| | | Question question = questionMapper.selectById(model.getId()); |
| | | question.setSubjectId(model.getSubjectId()); |
| | | question.setGradeLevel(gradeLevel); |
| | | question.setScore(ExamUtil.scoreFromVM(model.getScore())); |
| | | question.setDifficult(model.getDifficult()); |
| | | question.setCorrectFromVM(model.getCorrect(), model.getCorrectArray()); |
| | | questionMapper.updateByPrimaryKeySelective(question); |
| | | |
| | | //题干、解析、选项等 更新 |
| | | TextContent infoTextContent = textContentService.selectById(question.getInfoTextContentId()); |
| | | setQuestionInfoFromVM(infoTextContent, model); |
| | | textContentService.updateByIdFilter(infoTextContent); |
| | | |
| | | String questionObject = setQuestionInfoFromVM(model); |
| | | question.setContent(questionObject); |
| | | question.setTitle(HtmlUtil.clear(model.getTitle())); |
| | | question.setAudioFile(model.getAudioFile()); |
| | | question.setOriginalFile(model.getOriginalFile()); |
| | | questionMapper.updateById(question); |
| | | return question; |
| | | } |
| | | |
| | | @Override |
| | | public QuestionEditRequestVO getQuestionEditRequestVM(Integer questionId) { |
| | | //题目映射 |
| | | Question question = questionMapper.selectByPrimaryKey(questionId); |
| | | Question question = questionMapper.selectById(questionId); |
| | | return getQuestionEditRequestVM(question); |
| | | } |
| | | |
| | | @Override |
| | | public QuestionEditRequestVO getQuestionEditRequestVM(Question question) { |
| | | //题目映射 |
| | | TextContent questionInfoTextContent = textContentService.selectById(question.getInfoTextContentId()); |
| | | QuestionObject questionObject = JsonUtil.toJsonObject(questionInfoTextContent.getContent(), QuestionObject.class); |
| | | QuestionObject questionObject = JsonUtil.toJsonObject(question.getContent(), QuestionObject.class); |
| | | QuestionEditRequestVO questionEditRequestVO = new QuestionEditRequestVO(); |
| | | BeanUtils.copyProperties(question, questionEditRequestVO); |
| | | questionEditRequestVO.setTitle(questionObject.getTitleContent()); |
| | |
| | | switch (questionTypeEnum) { |
| | | case SingleChoice: |
| | | case TrueFalse: |
| | | case Audio: |
| | | questionEditRequestVO.setCorrect(question.getCorrect()); |
| | | break; |
| | | case MultipleChoice: |
| | |
| | | questionEditRequestVO.setCorrectArray(correctContent); |
| | | break; |
| | | case ShortAnswer: |
| | | case Calculate: |
| | | case Analysis: |
| | | questionEditRequestVO.setCorrect(questionObject.getCorrect()); |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | questionEditRequestVO.setScore(ExamUtil.scoreToVM(question.getScore())); |
| | | questionEditRequestVO.setAnalyze(questionObject.getAnalyze()); |
| | | |
| | | |
| | |
| | | List<QuestionEditItemVO> editItems = questionObject.getQuestionItemObjects().stream().map(o -> { |
| | | QuestionEditItemVO questionEditItemVO = new QuestionEditItemVO(); |
| | | BeanUtils.copyProperties(o, questionEditItemVO); |
| | | if (o.getScore() != null) { |
| | | questionEditItemVO.setScore(ExamUtil.scoreToVM(o.getScore())); |
| | | } |
| | | return questionEditItemVO; |
| | | }).collect(Collectors.toList()); |
| | | questionEditRequestVO.setItems(editItems); |
| | | return questionEditRequestVO; |
| | | } |
| | | |
| | | public void setQuestionInfoFromVM(TextContent infoTextContent, QuestionEditRequestVO model) { |
| | | public String setQuestionInfoFromVM(QuestionEditRequestVO model) { |
| | | List<QuestionItemObject> itemObjects = model.getItems().stream().map(i -> |
| | | { |
| | | QuestionItemObject item = new QuestionItemObject(); |
| | | item.setPrefix(i.getPrefix()); |
| | | item.setContent(i.getContent()); |
| | | item.setItemUuid(i.getItemUuid()); |
| | | item.setScore(ExamUtil.scoreFromVM(i.getScore())); |
| | | return item; |
| | | } |
| | | ).collect(Collectors.toList()); |
| | |
| | | questionObject.setAnalyze(model.getAnalyze()); |
| | | questionObject.setTitleContent(model.getTitle()); |
| | | questionObject.setCorrect(model.getCorrect()); |
| | | infoTextContent.setContent(JsonUtil.toJsonStr(questionObject)); |
| | | return JsonUtil.toJsonStr(questionObject); |
| | | } |
| | | |
| | | @Override |
| | |
| | | }).collect(Collectors.toList()); |
| | | } |
| | | |
| | | @Override |
| | | public Boolean updateStatus(QuestionResponseVO question) { |
| | | return new LambdaUpdateChainWrapper<>(questionMapper) |
| | | .set(Question::getStatus, question.getStatus()) |
| | | .eq(Question::getId, question.getId()) |
| | | .update(); |
| | | } |
| | | |
| | | @Override |
| | | public List<ExamPaperImportVO> export(QuestionExportVO query) { |
| | | return questionMapper.export(query); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional |
| | | @SneakyThrows |
| | | public Result<Boolean> importQuestion(MultipartFile file) { |
| | | List<Subject> subjects = subjectService.list(); |
| | | // 题目集合用于批量保存 |
| | | ArrayList<Question> questions = new ArrayList<>(); |
| | | Consumer<List<QuestionImportVO>> consumer = (data) -> { |
| | | // 循环每一行 |
| | | for (int i = 0; i < data.size(); i++) { |
| | | // 读取的题目 |
| | | QuestionImportVO excelQuestion = data.get(i); |
| | | String questionType = excelQuestion.getQuestionType(); |
| | | // 判断是否完整题目 |
| | | if (excelQuestion.intact()) { |
| | | // 循环题目 |
| | | while (Boolean.TRUE) { |
| | | // 更新读取的题目 |
| | | excelQuestion = data.get(i); |
| | | Question question = new Question(); |
| | | // 该题的选项 |
| | | List<QuestionItemObject> options = new ArrayList<>(8); |
| | | // 选项内容 |
| | | QuestionItemObject option = new QuestionItemObject(); |
| | | option.setPrefix(excelQuestion.getOptionName()); |
| | | option.setContent(excelQuestion.getOptionValue()); |
| | | options.add(option); |
| | | // 循环选项 |
| | | while (Boolean.TRUE) { |
| | | // 判断是否是最后一条 |
| | | if (i + 1 == data.size()) { |
| | | break; |
| | | } |
| | | QuestionImportVO nextQuestion = data.get(1 + i); |
| | | if (nextQuestion.intact()) { |
| | | break; |
| | | } |
| | | QuestionItemObject nextOption = new QuestionItemObject(); |
| | | nextOption.setPrefix(nextQuestion.getOptionName()); |
| | | nextOption.setContent(nextQuestion.getOptionValue()); |
| | | options.add(nextOption); |
| | | i++; |
| | | } |
| | | // 保存题目内容 |
| | | QuestionObject questionObject = new QuestionObject(); |
| | | questionObject.setQuestionItemObjects(options); |
| | | questionObject.setAnalyze(excelQuestion.getAnalyze()); |
| | | questionObject.setTitleContent(excelQuestion.getTitle()); |
| | | questionObject.setCorrect(excelQuestion.getCorrect()); |
| | | question.setTitle(excelQuestion.getTitle()); |
| | | question.setContent(JSON.toJSONString(questionObject)); |
| | | question.setQuestionType(QuestionTypeEnum.get(excelQuestion.getQuestionType())); |
| | | // 答案(多选需要用、分割保存字符串到数据库) |
| | | String[] corrects = excelQuestion.getCorrect().split("、"); |
| | | if (corrects.length > 1) { |
| | | question.setCorrect(String.join(",", corrects)); |
| | | } else { |
| | | question.setCorrect(excelQuestion.getCorrect()); |
| | | } |
| | | // 难度 |
| | | question.setDifficult(excelQuestion.getDifficult()); |
| | | // 创建人 |
| | | question.setCreateUser(2); |
| | | question.setStatus(StatusEnum.ENABLE); |
| | | question.setCreateTime(new Date()); |
| | | question.setDeleted(0); |
| | | question.setQuestionType(QuestionTypeEnum.get(questionType)); |
| | | // 根据科目名称获取id |
| | | QuestionImportVO finalExcelQuestion = excelQuestion; |
| | | question.setSubjectId(subjects.stream().filter(subject -> subject.getName().equals(finalExcelQuestion.getSubject())).findFirst().get().getId()); |
| | | questions.add(question); |
| | | if (i + 1 == data.size() || data.get(i + 1).intact()) { |
| | | break; |
| | | } |
| | | i++; |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | EasyExcel.read(file.getInputStream(), QuestionImportVO.class, new CurrencyDataListener(consumer)).sheet("模板").doRead(); |
| | | // 保存题目 |
| | | return Result.ok(saveBatch(questions)); |
| | | } |
| | | |
| | | @Override |
| | | @SneakyThrows |
| | | public void importTemplate(HttpServletResponse response) { |
| | | String fileName = URLEncoder.encode("试卷导入模板", "UTF-8").replaceAll("\\+", "%20"); |
| | | response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); |
| | | |
| | | // 构建模板样例数据 |
| | | List<QuestionImportVO> data = new ArrayList<>(8); |
| | | QuestionImportVO questionImportVO = new QuestionImportVO(); |
| | | questionImportVO.setQuestionType("单选题"); |
| | | questionImportVO.setSubject("语文"); |
| | | questionImportVO.setDifficult(2); |
| | | questionImportVO.setCorrect("A"); |
| | | questionImportVO.setScore(2); |
| | | questionImportVO.setAnalyze("A是对的"); |
| | | questionImportVO.setTitle("这是一道测试题目,使用该模板请删除或替换这道题"); |
| | | questionImportVO.setOptionName("A"); |
| | | questionImportVO.setOptionValue("选我"); |
| | | data.add(questionImportVO); |
| | | |
| | | QuestionImportVO questionImport1 = new QuestionImportVO(); |
| | | questionImport1.setOptionName("B"); |
| | | questionImport1.setOptionValue("选B"); |
| | | data.add(questionImport1); |
| | | |
| | | QuestionImportVO questionImport2 = new QuestionImportVO(); |
| | | questionImport2.setOptionName("C"); |
| | | questionImport2.setOptionValue("选C"); |
| | | data.add(questionImport2); |
| | | |
| | | QuestionImportVO questionImport3 = new QuestionImportVO(); |
| | | questionImport3.setOptionName("D"); |
| | | questionImport3.setOptionValue("选D"); |
| | | data.add(questionImport3); |
| | | |
| | | // 查出所有的课目(excel下拉数据) |
| | | List<Subject> subjects = subjectService.list(); |
| | | List<String> subjectNameList = subjects.stream().map(Subject::getName).collect(Collectors.toList()); |
| | | EasyExcel.write(response.getOutputStream(), QuestionImportVO.class) |
| | | .sheet("模板") |
| | | .registerWriteHandler(new SelectExcel(subjectNameList)) |
| | | .registerWriteHandler(new FixedMergeCellStrategy(2, 4, Arrays.asList(0, 1, 2, 5, 6, 7, 8))) |
| | | .doWrite(data); |
| | | } |
| | | |
| | | } |