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.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.utils.DateTimeUtil; import com.ycl.jxkg.utils.ExamUtil; 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.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 @RequiredArgsConstructor public class QuestionServiceImpl extends ServiceImpl implements QuestionService { private final QuestionMapper questionMapper; private final SubjectService subjectService; @Override public PageInfo page(QuestionPageRequestVO requestVM) { return PageHelper.startPage(requestVM.getPageIndex(), requestVM.getPageSize(), "create_time desc").doSelectPageInfo(() -> questionMapper.page(requestVM) ); } @Override @Transactional public Question insertFullQuestion(QuestionEditRequestVO model, Integer userId) { Date now = new Date(); //题干、解析、选项等 插入 String questionObject = setQuestionInfoFromVM(model); Question question = new Question(); question.setSubjectId(model.getSubjectId()); question.setCreateTime(now); question.setQuestionType(model.getQuestionType()); question.setStatus(StatusEnum.ENABLE); question.setCorrectFromVM(model.getCorrect(), model.getCorrectArray()); question.setDifficult(model.getDifficult()); question.setContent(questionObject); question.setCreateUser(userId); 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) { Question question = questionMapper.selectById(model.getId()); question.setSubjectId(model.getSubjectId()); question.setDifficult(model.getDifficult()); question.setCorrectFromVM(model.getCorrect(), model.getCorrectArray()); //题干、解析、选项等 更新 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.selectById(questionId); return getQuestionEditRequestVM(question); } @Override public QuestionEditRequestVO getQuestionEditRequestVM(Question question) { //题目映射 QuestionObject questionObject = JsonUtil.toJsonObject(question.getContent(), QuestionObject.class); QuestionEditRequestVO questionEditRequestVO = new QuestionEditRequestVO(); BeanUtils.copyProperties(question, questionEditRequestVO); questionEditRequestVO.setTitle(questionObject.getTitleContent()); //答案 QuestionTypeEnum questionTypeEnum = QuestionTypeEnum.fromCode(question.getQuestionType()); switch (questionTypeEnum) { case SingleChoice: case TrueFalse: case Audio: questionEditRequestVO.setCorrect(question.getCorrect()); break; case MultipleChoice: questionEditRequestVO.setCorrectArray(ExamUtil.contentToArray(question.getCorrect())); break; case GapFilling: List correctContent = questionObject.getQuestionItemObjects().stream().map(d -> d.getContent()).collect(Collectors.toList()); questionEditRequestVO.setCorrectArray(correctContent); break; case ShortAnswer: case Calculate: case Analysis: questionEditRequestVO.setCorrect(questionObject.getCorrect()); break; default: break; } questionEditRequestVO.setAnalyze(questionObject.getAnalyze()); //题目项映射 List editItems = questionObject.getQuestionItemObjects().stream().map(o -> { QuestionEditItemVO questionEditItemVO = new QuestionEditItemVO(); BeanUtils.copyProperties(o, questionEditItemVO); return questionEditItemVO; }).collect(Collectors.toList()); questionEditRequestVO.setItems(editItems); return questionEditRequestVO; } public String setQuestionInfoFromVM(QuestionEditRequestVO model) { List itemObjects = model.getItems().stream().map(i -> { QuestionItemObject item = new QuestionItemObject(); item.setPrefix(i.getPrefix()); item.setContent(i.getContent()); item.setItemUuid(i.getItemUuid()); return item; } ).collect(Collectors.toList()); QuestionObject questionObject = new QuestionObject(); questionObject.setQuestionItemObjects(itemObjects); questionObject.setAnalyze(model.getAnalyze()); questionObject.setTitleContent(model.getTitle()); questionObject.setCorrect(model.getCorrect()); return JsonUtil.toJsonStr(questionObject); } @Override public Integer selectAllCount() { return questionMapper.selectAllCount(); } @Override public List selectMothCount() { Date startTime = DateTimeUtil.getMonthStartDay(); Date endTime = DateTimeUtil.getMonthEndDay(); List mothStartToNowFormat = DateTimeUtil.MothStartToNowFormat(); List mouthCount = questionMapper.selectCountByDate(startTime, endTime); return mothStartToNowFormat.stream().map(md -> { KeyValue keyValue = mouthCount.stream().filter(kv -> kv.getName().equals(md)).findAny().orElse(null); return null == keyValue ? 0 : keyValue.getValue(); }).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 export(QuestionExportVO query) { return questionMapper.export(query); } @Override @Transactional @SneakyThrows public Result importQuestion(MultipartFile file) { List subjects = subjectService.list(); // 题目集合用于批量保存 ArrayList questions = new ArrayList<>(); Consumer> 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 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 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 subjects = subjectService.list(); List 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); } }