龚焕茏
2024-05-07 49429bad1036c81c056faeadfa009c53ba777fad
src/main/java/com/mindskip/xzs/controller/admin/QuestionController.java
@@ -1,12 +1,24 @@
package com.mindskip.xzs.controller.admin;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.metadata.data.HyperlinkData;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.fastjson.JSON;
import com.mindskip.xzs.base.BaseApiController;
import com.mindskip.xzs.base.RestResponse;
import com.mindskip.xzs.base.SystemCode;
import com.mindskip.xzs.context.WebContext;
import com.mindskip.xzs.domain.Question;
import com.mindskip.xzs.domain.QuestionSubject;
import com.mindskip.xzs.domain.Subject;
import com.mindskip.xzs.domain.TextContent;
import com.mindskip.xzs.domain.enums.QuestionSourceEnum;
import com.mindskip.xzs.domain.enums.QuestionStatusEnum;
import com.mindskip.xzs.domain.enums.QuestionTypeEnum;
import com.mindskip.xzs.domain.question.QuestionItemObject;
import com.mindskip.xzs.domain.question.QuestionObject;
import com.mindskip.xzs.excel.*;
import com.mindskip.xzs.repository.DepartmentMapper;
import com.mindskip.xzs.repository.SubjectMapper;
import com.mindskip.xzs.service.*;
@@ -16,15 +28,25 @@
import com.mindskip.xzs.viewmodel.admin.education.SubjectPageRequestVM;
import com.mindskip.xzs.viewmodel.admin.question.*;
import com.github.pagehelper.PageInfo;
import com.mindskip.xzs.vo.QuestionExportVO;
import com.mindskip.xzs.vo.QuestionImportVO;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@RestController("AdminQuestionController")
@@ -40,6 +62,8 @@
    private final QuestionSubjectService questionSubjectService;
    private static final String SPLIT = "、";
    @Autowired
    public QuestionController(QuestionService questionService, TextContentService textContentService, SubjectMapper subjectMapper, DepartmentMapper departmentMapper, QuestionSubjectService questionSubjectService) {
        this.questionService = questionService;
@@ -50,7 +74,7 @@
    }
    @RequestMapping(value = "/page", method = RequestMethod.POST)
    public RestResponse<PageInfo<QuestionResponseVM>> pageList(@RequestBody QuestionPageRequestVM model) {
    public RestResponse<PageInfo<QuestionResponseVM>> pageList(@RequestBody @Valid QuestionPageRequestVM model) {
        PageInfo<Question> pageInfo = questionService.page(model);
        PageInfo<QuestionResponseVM> page = PageInfoHelper.copyMap(pageInfo, q -> {
            QuestionResponseVM vm = modelMapper.map(q, QuestionResponseVM.class);
@@ -88,9 +112,8 @@
    }
    @RequestMapping(value = "/select/{id}", method = RequestMethod.POST)
    public RestResponse<QuestionEditRequestVM> select(@PathVariable Integer id) {
        QuestionEditRequestVM newVM = questionService.getQuestionEditRequestVM(id);
        return RestResponse.ok(newVM);
    public RestResponse<ExamQuestionVO> select(@PathVariable Integer id) {
        return RestResponse.ok(questionService.getQuestionEditRequestVM(id));
    }
@@ -120,13 +143,238 @@
        return RestResponse.ok();
    }
    /**
     * 下载题目导入模板
     *
     * @param response
     * @throws IOException
     */
    @GetMapping("/download/question/import/temp")
    public void getImportTemp(HttpServletResponse response) throws IOException {
        String fileName = URLEncoder.encode("题目导入模板", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        // 构建模板样例数据
        List<QuestionImportVO> data = new ArrayList<>(4);
        QuestionImportVO questionImportVO = new QuestionImportVO();
        questionImportVO.setQuestionType("单选题");
        questionImportVO.setDifficult(2);
        questionImportVO.setCorrect("B");
        questionImportVO.setScore(2);
        questionImportVO.setSubjectName("测试课目");
        questionImportVO.setAnalyze("B是对的");
        questionImportVO.setTitle("这是一道测试题目,使用该模板请删除或替换这道题");
        questionImportVO.setOptionName("A");
        questionImportVO.setOptionValue("选我");
        data.add(questionImportVO);
        QuestionImportVO questionImportVO1 = new QuestionImportVO();
        questionImportVO1.setOptionName("B");
        questionImportVO1.setOptionValue("选B");
        data.add(questionImportVO1);
        QuestionImportVO questionImportVO2 = new QuestionImportVO();
        questionImportVO2.setOptionName("C");
        questionImportVO2.setOptionValue("选C");
        data.add(questionImportVO2);
        QuestionImportVO questionImportVO3 = new QuestionImportVO();
        questionImportVO3.setOptionName("D");
        questionImportVO3.setOptionValue("选D");
        data.add(questionImportVO3);
        // 查出所有的课目(excel下拉数据)
        List<Subject> subjects = subjectMapper.allSubject();
        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);
    }
    @GetMapping("/question/export")
    public void importQuestion(QuestionExportVO query, HttpServletResponse response) throws IOException {
        query.formartTime();
        // 查询导出数据
        List<QuestionImportVO> exportData = questionService.export(query);
        // 构建数据
        List<QuestionImportVO> exportList = new ArrayList<>(exportData.size() * 4);
        // 行合并规则
        List<RowItem> mergeRowList = new ArrayList<>(exportData.size());
        int j = 2;
        for (QuestionImportVO data : exportData) {
            QuestionObject questionContent = JSON.parseObject(data.getQuestionContent(), QuestionObject.class);
            RowItem rowItem = new RowItem();
            rowItem.setStart(j);
            int end = j + questionContent.getQuestionItemObjects().size() - 1;
            rowItem.setEnd(end);
            mergeRowList.add(rowItem);
            j = end + 1;
            int i = 0;
            for (QuestionItemObject option : questionContent.getQuestionItemObjects()) {
                if (i == 0) {
                    QuestionImportVO master = new QuestionImportVO();
                    BeanUtils.copyProperties(data, master);
                    if (org.springframework.util.StringUtils.hasText(data.getQuestionType())) {
                        master.setQuestionType(QuestionTypeEnum.fromCode(Integer.valueOf(data.getQuestionType())).getName());
                    }
                    master.setOptionName(option.getPrefix());
                    master.setOptionValue(option.getContent());
                    master.setTitle(questionContent.getTitleContent());
                    master.setAnalyze(questionContent.getAnalyze());
                    master.setSubjectName(data.getSubjectList().stream().collect(Collectors.joining("、")));
                    master.setCorrect(data.getCorrect().replaceAll(",", "、"));
                    BigDecimal score = BigDecimal.valueOf(master.getScore());
                    master.setScore(score.divide(BigDecimal.TEN).intValue());
                    exportList.add(master);
                } else {
                    QuestionImportVO optionItem = new QuestionImportVO();
                    optionItem.setOptionName(option.getPrefix());
                    optionItem.setOptionValue(option.getContent());
                    exportList.add(optionItem);
                }
                i++;
            }
        }
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("题目导出数据", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        // 查出所有的课目(excel下拉数据)
        List<Subject> subjects = subjectMapper.allSubject();
        List<String> subjectNameList = subjects.stream().map(Subject::getName).collect(Collectors.toList());
        EasyExcel.write(response.getOutputStream(), QuestionImportVO.class)
                .sheet("题目导出数据")
                .registerWriteHandler(new SelectExcel(subjectNameList))
                .registerWriteHandler(new DynamicMergeCellStrategy(mergeRowList, Arrays.asList(0, 1, 2, 5, 6, 7, 8)))
                .doWrite(exportList);
    }
    /**
     * 题目导入
     *
     * easyexcel导入一对多,比如一个题目,四个选项。那么读取到的数据就有四条,第一条数据是齐全的。后面三条只有选项有值
     * @param file
     * @throws IOException
     */
    @PostMapping("/question/import")
    @Transactional(rollbackFor = Exception.class)
    public RestResponse importQuestion(@RequestPart("file") MultipartFile file) throws IOException {
        Consumer<List<QuestionImportVO>> consumer = (data) -> {
            // 题目的课目信息
            List<QuestionSubject> questionSubjectsList = new ArrayList<>(48);
            for (int i = 0; i < data.size(); i++) {
                // 题目实体
                Question question = new Question();
                // 读取的题目
                QuestionImportVO excelQuestion = data.get(i);
                // 如果是第一条完整数据,那么继续往后读取选项内容
                if (excelQuestion.master()) {
                    // 该题的选项
                    List<QuestionItemObject> options = new ArrayList<>(4);
                    // 选项内容
                    QuestionItemObject option = new QuestionItemObject();
                    option.setPrefix(excelQuestion.getOptionName());
                    option.setContent(excelQuestion.getOptionValue());
                    options.add(option);
                    int next = 1;
                    // 继续往后读选项
                    while (Boolean.TRUE) {
                        // 判断是否是最后一条
                        if (next + i == data.size()) {
                            break;
                        }
                        QuestionImportVO nextQuestion = data.get(next + i);
                        if (nextQuestion.master()) {
                            break;
                        }
                        QuestionItemObject nextOption = new QuestionItemObject();
                        nextOption.setPrefix(nextQuestion.getOptionName());
                        nextOption.setContent(nextQuestion.getOptionValue());
                        options.add(nextOption);
                        next++;
                    }
                    i += next;
                    // 保存题目内容
                    QuestionObject questionObject = new QuestionObject();
                    questionObject.setQuestionItemObjects(options);
                    questionObject.setAnalyze(excelQuestion.getAnalyze());
                    questionObject.setTitleContent(excelQuestion.getTitle());
                    questionObject.setCorrect(excelQuestion.getCorrect());
                    TextContent textContent = new TextContent();
                    textContent.setContent(JSON.toJSONString(questionObject));
                    textContent.setCreateTime(new Date());
                    textContentService.insert(textContent);
                    // 保存题目信息
                    // 设置题型
                    question.setQuestionType(QuestionTypeEnum.get(excelQuestion.getQuestionType()));
                    // 答案(多选需要用,分割保存字符串到数据库)
                    String[] corrects = excelQuestion.getCorrect().split(SPLIT);
                    if (corrects.length > 1) {
                        question.setCorrect(Arrays.asList(corrects).stream().collect(Collectors.joining(",")));
                    } else {
                        question.setCorrect(excelQuestion.getCorrect());
                    }
                    // 难度
                    question.setDifficult(excelQuestion.getDifficult());
                    // 分数
                    question.setScore(ExamUtil.scoreFromVM(String.valueOf(excelQuestion.getScore())));
                    // 创建人
                    question.setCreateUser(1);
                    question.setStatus(QuestionStatusEnum.OK.getCode());
                    question.setCreateTime(new Date());
                    question.setDeleted(Boolean.FALSE);
                    question.setInfoTextContentId(textContent.getId());
                    questionService.insert(question);
                    // 查出所有的课目
                    List<Subject> subjects = subjectMapper.allSubject();
                    List<String> subjectNames = Arrays.asList(excelQuestion.getSubjectName().split(SPLIT));
                    List<Subject> targetSubject = subjects.stream()
                            .filter(subject -> subjectNames.contains(subject.getName()))
                            .collect(Collectors.toList());
                    if (CollectionUtils.isEmpty(targetSubject)) {
                        // todo 记录这个错误
                        continue;
                    }
                    // 构建课目-题目信息
                    questionSubjectsList = targetSubject.stream().map(subject -> {
                        QuestionSubject questionSubject = new QuestionSubject();
                        questionSubject.setQuestionId(question.getId());
                        questionSubject.setSubjectId(subject.getId());
                        questionSubject.setDeleted(0);
                        return questionSubject;
                    }).collect(Collectors.toList());
                }
                System.out.println(question);
            }
            // 批量保存题目-课目信息
            if (! CollectionUtils.isEmpty(questionSubjectsList)) {
                questionSubjectService.saves(questionSubjectsList);
            }
        };
        EasyExcel.read(file.getInputStream(), QuestionImportVO.class, new CurrencyDataListener(consumer)).sheet("模板").doRead();
        return RestResponse.ok();
    }
    @PostMapping("/import")
    public void importUser(@RequestPart("file") MultipartFile file) throws Exception {
    public RestResponse importUser(@RequestPart("file") MultipartFile file) throws Exception {
        List<QuestionEditVO> questionEditVOS = ExcelUtils.readMultipartFile(file, QuestionEditVO.class)
                .stream().map(e -> {
                    e.setQuestionType(QuestionTypeEnum.get(e.getType()));
                    e.setSubjectId(subjectMapper.getName(e.getSubjectName()).getId());
                    e.setGradeLevel(departmentMapper.getName(e.getDepartment()).getId());
//                    e.setSubjectId(subjectMapper.getName(e.getSbNames()).getId());
//                    e.setGradeLevel(departmentMapper.getName(e.getDepartment()).getId());
                    return e;
                }).collect(Collectors.toList());
@@ -145,25 +393,38 @@
            questionEditItemVM.setPrefix("B");
            questionEditItemVM.setContent(vm.getB());
            questionEditItemVMS.add(questionEditItemVM);
            questionEditItemVM = new QuestionEditItemVM();
            questionEditItemVM.setPrefix("C");
            questionEditItemVM.setContent(vm.getC());
            questionEditItemVMS.add(questionEditItemVM);
            questionEditItemVM = new QuestionEditItemVM();
            questionEditItemVM.setPrefix("D");
            questionEditItemVM.setContent(vm.getD());
            questionEditItemVMS.add(questionEditItemVM);
            if(!"".equals(vm.getC()) && vm.getC()!=null){
                questionEditItemVM = new QuestionEditItemVM();
                questionEditItemVM.setPrefix("C");
                questionEditItemVM.setContent(vm.getC());
                questionEditItemVMS.add(questionEditItemVM);
            }
            if(!"".equals(vm.getD()) && vm.getD()!=null){
                questionEditItemVM = new QuestionEditItemVM();
                questionEditItemVM.setPrefix("D");
                questionEditItemVM.setContent(vm.getD());
                questionEditItemVMS.add(questionEditItemVM);
            }
            vm.setItems(questionEditItemVMS);
            List<String> str = Arrays.asList(vm.getCorrect().split(","));
            List<Subject> subjectList = subjectMapper.getNames(vm.getSbNames().split(","));
            Integer[] arr =subjectList.stream()
                    .map(Subject::getId).toArray(Integer[]::new);
            vm.setSubjectIds(arr);
            //多选
            if (str.size() > 1) {
                vm.setCorrectArray(str);
                vm.setCorrect(null);
            }
            vm.setScore(QuestionSourceEnum.fromType(vm.getQuestionType()).toString());
            vm.setDifficult(4);
            questionService.insertFullQuestion(vm, getCurrentUser().getId());
            questionEditItemVMS.clear();
        }
        return RestResponse.ok();
    }
}