Kaynağa Gözat

错误音频标签校验,保存小题,导出数据包

xiatian 4 ay önce
ebeveyn
işleme
e24fe26cf1

+ 1331 - 1282
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/impl/ExportPaperServiceImpl.java

@@ -1,1283 +1,1332 @@
-package cn.com.qmth.examcloud.core.questions.service.impl;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.servlet.http.HttpServletResponse;
-
-import cn.com.qmth.examcloud.support.fss.FssFactory;
-import cn.com.qmth.examcloud.support.fss.FssHelper;
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.mongodb.core.MongoTemplate;
-import org.springframework.data.mongodb.core.query.Criteria;
-import org.springframework.data.mongodb.core.query.Query;
-import org.springframework.stereotype.Service;
-
-import com.google.common.collect.Lists;
-import com.google.gson.Gson;
-
-import cn.com.qmth.examcloud.api.commons.enums.AdminOperateType;
-import cn.com.qmth.examcloud.api.commons.security.bean.User;
-import cn.com.qmth.examcloud.commons.exception.StatusException;
-import cn.com.qmth.examcloud.core.questions.base.CommonUtils;
-import cn.com.qmth.examcloud.core.questions.base.FileDisposeUtil;
-import cn.com.qmth.examcloud.core.questions.base.IdUtils;
-import cn.com.qmth.examcloud.core.questions.base.Model;
-import cn.com.qmth.examcloud.core.questions.base.converter.utils.FileUtil;
-import cn.com.qmth.examcloud.core.questions.base.enums.ExamFileType;
-import cn.com.qmth.examcloud.core.questions.base.enums.PaperSeqMode;
-import cn.com.qmth.examcloud.core.questions.base.question.enums.QuesStructType;
-import cn.com.qmth.examcloud.core.questions.dao.CoursePropertyRepo;
-import cn.com.qmth.examcloud.core.questions.dao.PaperDetailUnitRepo;
-import cn.com.qmth.examcloud.core.questions.dao.PaperRepo;
-import cn.com.qmth.examcloud.core.questions.dao.QuestionAudioRepo;
-import cn.com.qmth.examcloud.core.questions.dao.entity.Course;
-import cn.com.qmth.examcloud.core.questions.dao.entity.CourseProperty;
-import cn.com.qmth.examcloud.core.questions.dao.entity.Paper;
-import cn.com.qmth.examcloud.core.questions.dao.entity.PaperDetail;
-import cn.com.qmth.examcloud.core.questions.dao.entity.PaperDetailUnit;
-import cn.com.qmth.examcloud.core.questions.dao.entity.Property;
-import cn.com.qmth.examcloud.core.questions.dao.entity.QuesOption;
-import cn.com.qmth.examcloud.core.questions.dao.entity.QuesProperty;
-import cn.com.qmth.examcloud.core.questions.dao.entity.Question;
-import cn.com.qmth.examcloud.core.questions.dao.entity.QuestionAudio;
-import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.Block;
-import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.ComputerTestOption;
-import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.ComputerTestPaper;
-import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.ComputerTestPaperDetail;
-import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.ComputerTestQuestion;
-import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.Section;
-import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.Sections;
-import cn.com.qmth.examcloud.core.questions.service.ExportPaperService;
-import cn.com.qmth.examcloud.core.questions.service.ExportThemisPaperService;
-import cn.com.qmth.examcloud.core.questions.service.PaperDetailService;
-import cn.com.qmth.examcloud.core.questions.service.PaperService;
-import cn.com.qmth.examcloud.core.questions.service.PropertyService;
-import cn.com.qmth.examcloud.core.questions.service.bean.dto.DownloadPaperDto;
-import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperExp;
-import cn.com.qmth.examcloud.core.questions.service.bean.dto.QuestionDistributeDto;
-import cn.com.qmth.examcloud.core.questions.service.converter.PrintExamPaperService;
-import cn.com.qmth.examcloud.core.questions.service.export.ExportPaperAbstractService;
-import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisPaperAndAnswer;
-import cn.com.qmth.examcloud.core.questions.service.util.ExportPaperUtil;
-import cn.com.qmth.examcloud.core.questions.service.util.PaperUtil;
-import cn.com.qmth.examcloud.reports.commons.bean.AdminOperateReport;
-import cn.com.qmth.examcloud.reports.commons.util.ReportsUtil;
-
-@Service("exportPaperService")
-public class ExportPaperServiceImpl implements ExportPaperService {
-
-    private static final Logger LOG = LoggerFactory.getLogger(ExportPaperServiceImpl.class);
-
-    public static final String TEMP_FILE_EXP = "docxExport/";
-
-    public static final String TEMP_FILE_NAME = "_考试说明.docx";
-
-    public static final String DOCX_SUFFIX = ".docx";
-
-    public static final String ZIP_SUFFIX = ".zip";
-
-    @Autowired
-    private PaperRepo paperRepo;
-
-    @Autowired
-    private PaperService paperService;
-
-    @Autowired
-    private PaperDetailService paperDetailService;
-
-    @Autowired
-    private MongoTemplate mongoTemplate;
-
-    @Autowired
-    private CoursePropertyRepo coursePropertyRepo;
-
-    @Autowired
-    private PropertyService propertyService;
-
-    @Autowired
-    private QuestionAudioRepo questionAudioRepo;
-
-    @Autowired
-    private PrintExamPaperService printExamPaperService;
-
-    @Autowired
-    private PaperDetailUnitRepo paperDetailUnitRepo;
-    
-    @Autowired
-    private ExportThemisPaperService exportThemisPaperService;
-
-//    @Autowired
-//    protected QuesPkgPathRepo quesPkgPathRepo;
-
-//    @Autowired
-//    private SysProperty sysProperty;
-    @Override
-    public void exportPaperFile(String paperId, String exportContentList,
-            HttpServletResponse response, PaperSeqMode seqMode, String examType, String psw, User user) {
-        ExportPaperAbstractService exportPaperAbstractService = PaperUtil.getByRootOrgId(user.getRootOrgId().toString());
-        // 根据试卷id查询试卷
-        Paper paper = Model.of(paperRepo.findById(paperId));
-
-        String zipFileName =IdUtils.uuid();
-        long startTime;
-        try {
-            File directory = new File(TEMP_FILE_EXP + File.separator + zipFileName);
-            if (!directory.exists()) {
-                directory.mkdirs();
-            }
-            if (exportContentList.indexOf(ExamFileType.PRINT_EXAM_PACKAGE.name()) > -1) {
-                printExamPaperService.downloadPaper(Lists.newArrayList(paper), directory.getAbsolutePath(), psw);
-            }
-            if (exportContentList.indexOf(ExamFileType.COMPUTERTEST_PACKAGE.name()) > -1) {
-                downJson(paper, zipFileName);
-            }
-            if (exportContentList.indexOf(ExamFileType.THEMIS_PACKAGE.name()) > -1) {
-            	List<Paper> papers=new ArrayList<>();
-            	papers.add(paper);
-                downThemisPackage(papers, zipFileName);
-            }
-            try {
-            	DownloadPaperDto dto=new DownloadPaperDto(user.getRootOrgId(), paperId, zipFileName, examType,seqMode);
-                if (exportContentList.indexOf(ExamFileType.PAPER.name()) > -1) {
-                    exportPaperAbstractService.downloadPaper(dto);
-                }
-
-                if (exportContentList.indexOf(ExamFileType.ANSWER.name()) > -1) {
-                    exportPaperAbstractService.downloadPaperAnswer(dto);
-                }
-            } catch (StatusException e) {
-                LOG.error(e.getMessage(), e);
-                throw e;
-            } catch (Exception e) {
-                LOG.error(e.getMessage(), e);
-                throw new StatusException("100001", e.getMessage());
-            }
-            // 下载考试说明 2018-2-27 weiwehai
-            /*
-             * if(examType.equals("offLine") &&
-             * StringUtils.isNotBlank(paper.getExamRemark())){
-             * downExamRemark(paper,zipFileName); }
-             */
-            LOG.debug("开始压缩成zip...");
-            startTime = System.currentTimeMillis();
-            FileDisposeUtil.fileToZip(TEMP_FILE_EXP + File.separator + zipFileName, TEMP_FILE_EXP, zipFileName);
-            FileDisposeUtil.downloadFile(paper.getName() + "_" + paper.getCourse().getCode() + ".zip",
-                    TEMP_FILE_EXP + File.separator + zipFileName + ".zip", response);
-            long endTime = System.currentTimeMillis();
-            LOG.debug("下载zip耗时:" + (endTime - startTime) + "ms");
-        } finally {
-            long endTime = System.currentTimeMillis();
-			FileUtil.deleteFolder(TEMP_FILE_EXP+ File.separator + zipFileName);
-			FileUtil.deleteFolder(TEMP_FILE_EXP+ File.separator + zipFileName+ ".zip");
-//            deteleFolder(TEMP_FILE_EXP, zipFileName);
-            long deleteTime = System.currentTimeMillis();
-            LOG.debug("删除文件耗时:" + (deleteTime - endTime) + "ms");
-        }
-        StringBuilder paperInfo=new StringBuilder();
-		paperInfo.append("课程:"+paper.getCourse().getName()+"("+paper.getCourse().getCode()+")");
-		paperInfo.append(" 试卷名称:"+paper.getName());
-		paperInfo.append(getContentName(exportContentList));
-		
-		ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(), AdminOperateType.TYPE36.getDesc(),paperInfo.toString()));
-    }
-
-    private String getContentName(String exportContentList) {
-    	StringBuilder sb=new StringBuilder();
-    	sb.append(" 下载内容:");
-    	for(String content:exportContentList.split(",")) {
-    		sb.append(ExamFileType.valueOf(content).getName()+",");
-    	}
-    	sb.deleteCharAt(sb.length()-1);
-    	return sb.toString();
-    }
-    /**
-     * 下载考试说明
-     *
-     * @param zipFileName
-     * @throws Exception
-     */
-//    @SuppressWarnings("unused")
-//    private void downExamRemark(Paper paper, String zipFileName) throws Exception {
-//        // 1.考试说明html转成word
-//        String title = "<p style=\"text-align:center\"><span style=\"font-size:26px\"><span style=\"font-family:宋体\">考&nbsp;试&nbsp;说&nbsp;明</span></span></p>";
-//        WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
-//        DocxProcessUtil.html2Docx(wordMLPackage, CommonUtils.formatHtml(title + paper.getExamRemark()));
-//        // 2.导出考试说明word
-//        File file = new File(TEMP_FILE_EXP + File.separator + zipFileName + File.separator + paper.getCourse().getCode()
-//                + TEMP_FILE_NAME);
-//        Docx4J.save(wordMLPackage, file);
-//    }
-
-//    private void deteleFolder(String sourceFilePath, String zipFileName) {
-//        File ComputerTestPaperfoler = new File(sourceFilePath + File.separator + "json");
-//        if (ComputerTestPaperfoler.exists()) {
-//            FileUtils.deleteQuietly(ComputerTestPaperfoler);
-//        }
-//        File zipFolder = new File(sourceFilePath + File.separator + zipFileName);
-//        if (zipFolder.exists()) {
-//            FileUtils.deleteQuietly(zipFolder);
-//        }
-//        File zipFile = new File(sourceFilePath + File.separator + zipFileName + ".zip");
-//        if (zipFile.exists()) {
-//            FileUtils.deleteQuietly(zipFile);
-//        }
-//    }
-
-    private void downJson(Paper paper, String zipFileName) {
-        ComputerTestPaper computerTestPaper = buildComputerTestPapers(paper);
-        String jsonDirectory = TEMP_FILE_EXP + File.separator+zipFileName+File.separator + "json";
-        try {
-	        // 新建文件夹
-	        File dirFile = new File(jsonDirectory);
-	        if (!dirFile.exists()) {
-	            dirFile.mkdirs();
-	        }
-	        makeComputerTestPaperToJsonFile(paper.getCourse().getCode(), computerTestPaper, jsonDirectory);
-	        downloadAudio(computerTestPaper, jsonDirectory);
-	        // 将文件夹打包成zip压缩包放在docxExport下
-	        FileDisposeUtil.fileToZip(jsonDirectory, TEMP_FILE_EXP + File.separator + zipFileName,
-	                paper.getCourse().getCode() + "_" + paper.getName());
-		} finally {
-			FileUtil.deleteDirectory(jsonDirectory);
-		}
-    }
-    
-    private void downThemisPackage(List<Paper> papers, String zipFileName) {
-        String zipDirectory = TEMP_FILE_EXP + File.separator +zipFileName+ File.separator+ "themis_package";
-        // 新建文件夹
-        File dirFile = new File(zipDirectory);
-        if (!dirFile.exists()) {
-        	dirFile.mkdirs();
-        }
-        try {
-        	for(Paper paper:papers) {
-        		ThemisPaperAndAnswer pa = exportThemisPaperService.buildPaperAndAnswer(paper);
-				String paperDirectory = zipDirectory + File.separator + paper.getCourseNo() + File.separator
-						+ paper.getId();
-				File paperDir = new File(paperDirectory);
-				if (!paperDir.exists()) {
-					paperDir.mkdirs();
-				}
-				exportThemisPaperService.makePaperAnswerToJsonFile(pa, paperDirectory);
-				exportThemisPaperService.downloadAudio(pa.getPaper(), paperDirectory);
-        	}
-			// 将文件夹打包成zip压缩包放在docxExport下
-			File zipFile=new File(TEMP_FILE_EXP + File.separator + zipFileName+ File.separator + "在线考试数据包.zip");
-			FileUtil.doZip(dirFile, zipFile);
-		} finally {
-			FileUtil.deleteDirectory(zipDirectory);
-		}
-    }
-
-    private void downloadAudio(ComputerTestPaper computerTestPaper, String jsonDirectory) {
-        // 取到所有大题
-        List<ComputerTestPaperDetail> details = computerTestPaper.getDetails();
-        if (details != null && details.size() > 0) {
-            for (ComputerTestPaperDetail detail : details) {
-                // 取到所有小题集合
-                List<ComputerTestQuestion> questions = detail.getQuestions();
-                if (questions != null && questions.size() > 0) {
-                    for (ComputerTestQuestion question : questions) {
-                        int bodyNum = 1;
-                        // 取到题干
-                        Sections body = question.getBody();
-                        List<Section> sections = body.getSections();
-                        for (Section section : sections) {
-                            List<Block> blocks = section.getBlocks();
-                            if (blocks != null && blocks.size() > 0) {
-                                for (Block block : blocks) {
-                                    if (block.getType().equals("audio")) {
-                                        String id = block.getValue();
-                                        QuestionAudio questionAudio = Model.of(questionAudioRepo.findById(id));
-                                        String audioFileName = questionAudio.getId() + "_" + detail.getNumber() + "_"
-                                                + question.getNumber() + "_1_" + bodyNum + "."
-                                                + questionAudio.getFileSuffixes();
-
-                                        File file = new File(jsonDirectory + File.separator + audioFileName);
-
-                                        String filePath = FssHelper.fixFilePath(questionAudio.getFileUrl());
-                                        FssFactory.getInstance().readFile(filePath, file);
-
-                                        bodyNum++;
-                                    }
-                                }
-                            }
-                        }
-                        // 取到选项
-                        List<ComputerTestOption> options = question.getOptions();
-                        if (options != null && options.size() > 0) {
-                            for (ComputerTestOption computerTestOption : options) {
-                                int optionNum = 1;
-                                // 获取选项主体
-                                Sections optionBody = computerTestOption.getBody();
-                                List<Section> optionSections = optionBody.getSections();
-                                if (optionSections != null && optionSections.size() > 0) {
-                                    for (Section optionSection : optionSections) {
-                                        List<Block> blocks = optionSection.getBlocks();
-                                        if (blocks != null && blocks.size() > 0) {
-                                            for (Block block : blocks) {
-                                                if (block.getType().equals("audio")) {
-                                                    String id = block.getValue();
-                                                    QuestionAudio questionAudio = Model
-                                                            .of(questionAudioRepo.findById(id));
-                                                    String audioFileName = questionAudio.getId() + "_"
-                                                            + detail.getNumber() + "_" + question.getNumber() + "_2_"
-                                                            + computerTestOption.getNumber() + "_" + optionNum + "."
-                                                            + questionAudio.getFileSuffixes();
-
-                                                    File file = new File(jsonDirectory + File.separator + audioFileName);
-
-                                                    String filePath = FssHelper.fixFilePath(questionAudio.getFileUrl());
-                                                    FssFactory.getInstance().readFile(filePath, file);
-
-                                                    optionNum++;
-                                                }
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * 构建机考数据包实体类
-     *
-     * @return
-     */
-    public ComputerTestPaper buildComputerTestPapers(Paper paper) {
-        // 得到所有旧对象的大题对象
-        List<PaperDetail> paperDetails = paperService.findPaperDetailsById(paper.getId());
-        // 通过 paper 对象 ,生成新的 ComputerTestPaper 对象
-        ComputerTestPaper computerTestPaper = new ComputerTestPaper(paper, "");
-        List<ComputerTestPaperDetail> details = new ArrayList<>();
-        // 遍历所有旧大题对象,得到小题对象的集合
-        for (PaperDetail paperDetail : paperDetails) {
-            List<PaperDetailUnit> paperDetailUnits = paperDetailService.getUnitsByPaperDetailId(paperDetail.getId());
-            ComputerTestPaperDetail computerTestPaperDetail = new ComputerTestPaperDetail(paperDetail);
-            List<ComputerTestQuestion> questions = new ArrayList<>();
-            // 遍历所有的小题对象
-            for (int i = 0; i < paperDetailUnits.size(); i++) {
-                PaperDetailUnit paperDetailUnit = paperDetailUnits.get(i);
-                // 根据旧的小题对象,生成新的小题对象
-                ComputerTestQuestion computerTestQuestion = new ComputerTestQuestion(paperDetailUnit);
-                // 设置小题题号
-                computerTestQuestion.setNumber(i + 1);
-                // 得到小题题干
-                computerTestQuestion
-                        .setBody(getBodyOrAnswer(paperDetailUnit.getQuestion().getQuesBody(), computerTestPaper));
-                // 得到小题所有选项
-                computerTestQuestion.setOptions(getOption(paperDetailUnit.getQuestion(), computerTestPaper));
-                // 得到小题的答案
-                computerTestQuestion
-                        .setAnswer(getBodyOrAnswer(paperDetailUnit.getQuestion().getQuesAnswer(), computerTestPaper));
-                // 查询小题中的 套题
-                List<Question> subQuestionsList = paperDetailUnit.getQuestion().getSubQuestions();
-                // 判断这个小题中是否有套题
-                if (subQuestionsList != null && subQuestionsList.size() > 0) {
-                    List<ComputerTestQuestion> subQuestions = new ArrayList<>();
-                    // 遍历每个套题
-                    for (int j = 0; j < subQuestionsList.size(); j++) {
-                        Question subQuestion = subQuestionsList.get(j);
-                        ComputerTestQuestion subcomputerTestQuestion = new ComputerTestQuestion(subQuestion);
-                        // 设置套题中小题题号
-                        subcomputerTestQuestion.setNumber(j + 1);
-                        subcomputerTestQuestion.setBody(getBodyOrAnswer(subQuestion.getQuesBody(), computerTestPaper));
-                        subcomputerTestQuestion.setOptions(getOption(subQuestion, computerTestPaper));
-                        subcomputerTestQuestion
-                                .setAnswer(getBodyOrAnswer(subQuestion.getQuesAnswer(), computerTestPaper));
-                        subQuestions.add(subcomputerTestQuestion);
-                    }
-                    computerTestQuestion.setSubQuestions(subQuestions);
-                }
-                questions.add(computerTestQuestion);
-            }
-            computerTestPaperDetail.setQuestions(questions);
-            // paperDetail中的题数(unitCount)可能不准确,这里以questions的实际size为准
-            computerTestPaperDetail.setQuestionCount(questions.size());
-            details.add(computerTestPaperDetail);
-        }
-        computerTestPaper.setDetails(details);
-        return computerTestPaper;
-    }
-
-    private Sections getBodyOrAnswer(String str, ComputerTestPaper computerTestPaper) {
-        Sections body = new Sections();
-        List<Section> sections = new ArrayList<>();
-        // 得到小题题干或者答案行数
-        if (StringUtils.isBlank(str)) {
-            return body;
-        }
-        String[] questionRowStrings = str.split("</p>");
-        for (int i = 0; i < questionRowStrings.length; i++) {
-            List<Block> blocks = disposeQuestionBodyOrOption(questionRowStrings[i], computerTestPaper);
-            if (blocks != null && blocks.size() > 0) {
-                Section section = new Section();
-                // 将小题题干拆分为Block集合
-                section.setBlocks(blocks);
-                sections.add(section);
-            }
-        }
-        body.setSections(sections);
-        return body;
-    }
-
-    private List<ComputerTestOption> getOption(Question question, ComputerTestPaper computerTestPaper) {
-        // 得到小题选项
-        List<QuesOption> quesOptions = question.getQuesOptions();
-        List<ComputerTestOption> options = new ArrayList<>();
-        // 遍历小题选项
-        if (quesOptions != null && quesOptions.size() > 0) {
-            for (QuesOption quesOption : quesOptions) {
-                ComputerTestOption option = new ComputerTestOption();
-                option.setNumber(new Integer(quesOption.getNumber()));
-                option.setCorrect(quesOption.getIsCorrect() == 1 ? true : false);
-                Sections body = new Sections();
-
-                List<Section> sections = new ArrayList<>();
-                // 得到小题选项
-                String optionString = quesOption.getOptionBody();
-                String[] optionStrings = optionString.split("</p>");
-                for (int i = 0; i < optionStrings.length; i++) {
-                    List<Block> blocks = disposeQuestionBodyOrOption(optionStrings[i], computerTestPaper);
-                    if (blocks != null && blocks.size() > 0) {
-                        Section section = new Section();
-                        section.setBlocks(blocks);
-                        sections.add(section);
-                    }
-                }
-                body.setSections(sections);
-                option.setBody(body);
-                options.add(option);
-            }
-        }
-        return options;
-    }
-
-    private List<Block> disposeQuestionBodyOrOption(String questionRow, ComputerTestPaper computerTestPaper) {
-        List<Block> blocks = new ArrayList<>();
-        // 去掉每行里面的<p>,<span>,</span>标签
-        questionRow = questionRow.replaceAll("<p>", "").replaceAll("</p>", "").replaceAll("<span>", "")
-                .replaceAll("</span>", "").replaceAll("</a>", "");
-        String[] questionRowStrings = questionRow.split("<|/>|>");
-        boolean hasAudio = false;
-        for (int i = 0; i < questionRowStrings.length; i++) {
-            Block block = new Block();
-            String rowStr = questionRowStrings[i];
-            // 判断是否有图片
-            if (rowStr.startsWith("img")) {
-                rowStr = "<" + rowStr + ">";
-                Map<String, Object> param = new HashMap<>();
-                // 需要继续做截取,取到Parma
-                block.setType("image");
-                // 获取图片的路径
-                List<String> strSrcList = getImg(rowStr, "src");
-                if (strSrcList.size() > 0) {
-                    String strSrc = strSrcList.get(0).replaceAll("src=\"", "").replaceAll("\"", "");
-                    block.setValue(strSrc);
-                }
-                // 获取图片的高度
-                List<String> strHeightList = getImg(rowStr, "height");
-                if (strHeightList.size() > 0) {
-                    String strHeight = strHeightList.get(0).replaceAll("height=\"", "").replaceAll("\"", "");
-                    param.put("height", strHeight);
-                }
-                // 获取图片的宽度
-                List<String> strWidthList = getImg(rowStr, "width");
-                if (strHeightList.size() > 0) {
-                    String strWidth = strWidthList.get(0).replaceAll("width=\"", "").replaceAll("\"", "");
-                    param.put("width", strWidth);
-                }
-                block.setParam(param);
-                blocks.add(block);
-            } else if (rowStr.startsWith("a") && rowStr.contains("id") && rowStr.contains("name")) { // 处理音频
-                rowStr = "<" + rowStr + ">";
-                block.setPlayTime(1);
-                block.setType("audio");
-                block.setValue(CommonUtils.getAttrValue(rowStr, "id"));
-                blocks.add(block);
-                hasAudio = true;
-            } else {
-                block.setType("text");
-                rowStr = rowStr.replace("&nbsp;", "");// 消除空格
-                rowStr = rowStr.replace("&quot;", "\"");// 将&quot;转换成\"
-                rowStr = rowStr.replace("&lt;", "<");// 将&lt;转换成<
-                rowStr = rowStr.replace("&gt;", ">");// 将&gt;转换成>
-                rowStr = rowStr.replace("&amp;", "&");// 将&amp;转换成&
-                if (StringUtils.isNotBlank(rowStr)) {
-                    block.setValue(rowStr);
-                    blocks.add(block);
-                }
-            }
-        }
-        if (hasAudio) {
-            computerTestPaper.setHasVideo(1);
-        }
-        return blocks;
-    }
-
-    /**
-     * 获取图片里面的路径,长度,宽度
-     */
-    private List<String> getImg(String s, String str) {
-        String regex;
-        List<String> list = new ArrayList<>();
-        regex = str + "=\"(.*?)\"";
-        Pattern pa = Pattern.compile(regex, Pattern.DOTALL);
-        Matcher ma = pa.matcher(s);
-        while (ma.find()) {
-            list.add(ma.group());
-        }
-        return list;
-    }
-
-    /**
-     * 将computerTestPaper对象生成JSON文件存放在jsonDirectoryPath中
-     *
-     * @param computerTestPaper
-     * @param jsonDirectoryPath
-     */
-    @SuppressWarnings("deprecation")
-	private void makeComputerTestPaperToJsonFile(String courseCode, ComputerTestPaper computerTestPaper,
-            String jsonDirectoryPath) {
-        // 创建新的JSON文件
-        File file = new File(jsonDirectoryPath + File.separator + courseCode + ".json");
-        // 将对象转成 json对象
-        Gson gson = new Gson();
-        String strJSON = gson.toJson(computerTestPaper);
-
-        strJSON = CommonUtils.replaceUnicodeStr(strJSON);
-        // 生成文件流写入JSON文件
-        FileOutputStream outputStream = null;
-        try {
-            outputStream = new FileOutputStream(file);
-            byte b[] = strJSON.getBytes();
-            outputStream.write(b);
-            outputStream.flush();
-        } catch (FileNotFoundException e) {
-            LOG.error(e.getMessage(), e);
-        } catch (IOException e) {
-            LOG.error(e.getMessage(), e);
-        } finally {
-            IOUtils.closeQuietly(outputStream);
-        }
-    }
-
-    @Override
-    public void exportPaperFiles(List<String> paperIds, String exportContentList,
-            HttpServletResponse response, PaperSeqMode seqMode, String examType, User user) throws Exception {
-        ExportPaperAbstractService exportPaperAbstractService = PaperUtil.getByRootOrgId(user.getRootOrgId().toString());
-        // 根据试卷id查询所有试卷
-        List<Paper> papers = CommonUtils.toList(paperRepo.findByIdIn(paperIds));
-        String zipFileName = IdUtils.uuid();
-        try {
-			// 创建压缩文件夹
-			File directory = new File(TEMP_FILE_EXP + File.separator + zipFileName);
-			directory.mkdirs();
-			// 下载试卷
-			if (exportContentList.indexOf(ExamFileType.PAPER.name()) > -1) {
-				for (Paper paper : papers) {
-					DownloadPaperDto dto=new DownloadPaperDto(user.getRootOrgId(), paper.getId(), zipFileName, examType,seqMode);
-					exportPaperAbstractService.downloadPaper(dto);
-				}
-			}
-			// 下载答案
-			if (exportContentList.indexOf(ExamFileType.ANSWER.name()) > -1) {
-				for (Paper paper : papers) {
-					DownloadPaperDto dto=new DownloadPaperDto(user.getRootOrgId(), paper.getId(), zipFileName, examType,seqMode);
-					exportPaperAbstractService.downloadPaperAnswer(dto);
-				}
-			}
-			// 下载机考数据包
-			if (exportContentList.indexOf(ExamFileType.COMPUTERTEST_PACKAGE.name()) > -1) {
-				for (Paper paper : papers) {
-					downJson(paper, zipFileName);
-				}
-			}
-			// 下载在线考试数据包
-			if (exportContentList.indexOf(ExamFileType.THEMIS_PACKAGE.name()) > -1) {
-				downThemisPackage(papers, zipFileName);
-			}
-			FileDisposeUtil.fileToZip(TEMP_FILE_EXP + File.separator + zipFileName, TEMP_FILE_EXP, zipFileName);
-			FileDisposeUtil.downloadFile(zipFileName + ".zip", TEMP_FILE_EXP + File.separator + zipFileName + ".zip",
-					response);
-		} finally {
-			FileUtil.deleteFolder(TEMP_FILE_EXP+ File.separator + zipFileName);
-			FileUtil.deleteFolder(TEMP_FILE_EXP+ File.separator + zipFileName+ ".zip");
-		}
-        StringBuilder paperInfo=new StringBuilder();
-		paperInfo.append("下载数量:"+paperIds.size());
-		paperInfo.append(getContentName(exportContentList));
-		
-		ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(), AdminOperateType.TYPE37.getDesc(),paperInfo.toString()));
-    
-    }
-
-    @Override
-    public void downQuestionDistribute(String courseCode, HttpServletResponse response) throws IOException {
-        // 生成导出Excle的list集合
-        List<QuestionDistributeDto> questionDistributes = this.downQuestionDistribute(courseCode);
-
-        final String fileName = courseCode + "试题分布.xlsx";
-        final String filePath = TEMP_FILE_EXP + File.separator + fileName;
-
-        // 生成Excel导出
-        File tempFile = this.writeExcel(questionDistributes, filePath);
-        FileDisposeUtil.downloadFile(fileName, filePath, response);
-        FileUtils.deleteQuietly(tempFile);
-    }
-
-    @Override
-    public void downQuestionDistributes(List<Course> courses) throws IOException {
-        if (CollectionUtils.isEmpty(courses)) {
-            return;
-        }
-
-        for (Course course : courses) {
-            List<QuestionDistributeDto> questionDistributes = this.downQuestionDistribute(course.getCode());
-            final String fileName = course.getCode() + "试题分布.xlsx";
-            final String filePath = TEMP_FILE_EXP + File.separator + fileName;
-            this.writeExcel(questionDistributes, filePath);
-        }
-    }
-
-    private List<QuestionDistributeDto> downQuestionDistribute(String courseCode) {
-        // 1.生成导出Excle的list集合
-        List<QuestionDistributeDto> questionDistributes = new ArrayList<>();
-
-        // 2.根据课程code查询课程属性集合
-        List<CourseProperty> courseProperties = coursePropertyRepo.findByCourseCodeAndEnable(courseCode, true);
-        if (CollectionUtils.isEmpty(courseProperties)) {
-            return questionDistributes;
-        }
-
-        // 3.遍历课程属性集合,根据课程属性查询一级
-        for (CourseProperty courseProperty : courseProperties) {
-            List<Property> parentProperties = propertyService.findParentProperties(courseProperty.getId(),
-                    courseProperty.getOrgId());
-            if (parentProperties != null && parentProperties.size() > 0) {
-                for (Property parentProperty : parentProperties) {
-                    List<Property> sonProperties = propertyService.findSonProperties(parentProperty.getId());
-                    if (sonProperties != null && sonProperties.size() > 0) {
-                        for (Property sonProperty : sonProperties) {
-                            // 单选题集合
-                            List<Question> sinList = questionList(courseCode, courseProperty,
-                                    QuesStructType.SINGLE_ANSWER_QUESTION, parentProperty, sonProperty);
-                            // 多选题集合
-                            List<Question> mulList = questionList(courseCode, courseProperty,
-                                    QuesStructType.MULTIPLE_ANSWER_QUESTION, parentProperty, sonProperty);
-                            // 判断题集合
-                            List<Question> bolList = questionList(courseCode, courseProperty,
-                                    QuesStructType.BOOL_ANSWER_QUESTION, parentProperty, sonProperty);
-
-                            List<Question> fillList = null;
-                            // fillList = questionList(courseCode,
-                            // courseProperty,
-                            // QuesStructType.FILL_BLANK_QUESTION,
-                            // parentProperty, sonProperty);
-                            List<Question> textList = null;
-                            // textList = questionList(courseCode,
-                            // courseProperty,
-                            // QuesStructType.TEXT_ANSWER_QUESTION,
-                            // parentProperty, sonProperty);
-
-                            // 计算所有题型数量
-                            Map<Long, Long> map = countQuesType(sinList, mulList, bolList, fillList, textList);
-                            QuestionDistributeDto questionDistributeDto = new QuestionDistributeDto(
-                                    courseProperty.getName(), parentProperty.getName(), sonProperty.getName(), map);
-                            questionDistributes.add(questionDistributeDto);
-                        }
-                    } else {
-                        // 一级属性不为空,二级属性为空
-                        // 单选题集合
-                        List<Question> sinList = questionList(courseCode, courseProperty,
-                                QuesStructType.SINGLE_ANSWER_QUESTION, parentProperty, null);
-                        // 多选题集合
-                        List<Question> mulList = questionList(courseCode, courseProperty,
-                                QuesStructType.MULTIPLE_ANSWER_QUESTION, parentProperty, null);
-                        // 判断题集合
-                        List<Question> bolList = questionList(courseCode, courseProperty,
-                                QuesStructType.BOOL_ANSWER_QUESTION, parentProperty, null);
-
-                        List<Question> fillList = null;
-                        // fillList = questionList(courseCode, courseProperty,
-                        // QuesStructType.FILL_BLANK_QUESTION, parentProperty,
-                        // null);
-                        List<Question> textList = null;
-                        // textList = questionList(courseCode, courseProperty,
-                        // QuesStructType.TEXT_ANSWER_QUESTION, parentProperty,
-                        // null);
-
-                        // 计算所有题型数量
-                        Map<Long, Long> map = countQuesType(sinList, mulList, bolList, fillList, textList);
-                        QuestionDistributeDto questionDistributeDto = new QuestionDistributeDto(
-                                courseProperty.getName(), parentProperty.getName(), null, map);
-                        questionDistributes.add(questionDistributeDto);
-                    }
-                }
-            } else {
-                // 一级属性为空
-                QuestionDistributeDto questionDistributeDto = new QuestionDistributeDto(courseProperty.getName(), null,
-                        null, null);
-                questionDistributes.add(questionDistributeDto);
-            }
-        }
-
-        return questionDistributes;
-    }
-
-    @SuppressWarnings("resource")
-    private File writeExcel(List<QuestionDistributeDto> questionDistributes, String filePath) throws IOException {
-        // 读取Excel模板
-        InputStream in = this.getClass().getResourceAsStream("/quesDistinct.xlsx");
-        // InputStream in =
-        // this.getClass().getResourceAsStream("/quesDistinctAll.xlsx");
-
-        // 获取第一个工作页
-        Workbook workBook = new XSSFWorkbook(in);
-        Sheet sheet = workBook.getSheetAt(0);
-
-        // 往Excel中写入数据,从第5行开始
-        for (int i = 0; i < questionDistributes.size(); i++) {
-            // 创建一行:从第五行开始,跳过表头
-            Row row = sheet.createRow(i + 4);
-
-            // 获取这行的记录
-            QuestionDistributeDto questionDistributeDto = questionDistributes.get(i);
-
-            // 每列赋值
-            row.createCell(0).setCellValue(questionDistributeDto.getCoursePropertyName());
-            row.createCell(1).setCellValue(questionDistributeDto.getFirstPropertyName());
-            row.createCell(2).setCellValue(questionDistributeDto.getSecondPropertyName());
-            Map<Long, Long> map = questionDistributeDto.getMap();
-            if (map == null) {
-                for (int j = 0; j < 18; j++) {
-                    row.createCell(j + 3).setCellValue(0);
-                }
-            } else {
-                int j = 3;
-                for (Long key : map.keySet()) {
-                    row.createCell(j).setCellValue(map.get(key));
-                    j++;
-                }
-            }
-        }
-
-        LOG.info("[WriteExcel] " + filePath);
-
-        File file = new File(filePath);
-        OutputStream out = new FileOutputStream(file);
-        workBook.write(out);
-        out.close();
-        return file;
-    }
-
-    private Map<Long, Long> countQuesType(List<Question> sinList, List<Question> mulList, List<Question> bolList,
-            List<Question> fillList, List<Question> textList) {
-        Map<Long, Long> map = new TreeMap<>();
-        map = buildMap(sinList, map, 1);
-        map = buildMap(mulList, map, 2);
-        map = buildMap(bolList, map, 3);
-
-        if (fillList != null) {
-            map = buildMap(fillList, map, 4);
-        }
-        if (textList != null) {
-            map = buildMap(textList, map, 5);
-        }
-
-        // 给map的键排序
-        Map<Long, Long> resultMap = sortMapByKey(map);
-        return resultMap;
-    }
-
-    private Map<Long, Long> sortMapByKey(Map<Long, Long> map) {
-        if (map == null || map.isEmpty()) {
-            return null;
-        }
-        Map<Long, Long> sortMap = new TreeMap<Long, Long>(new Comparator<Long>() {
-
-            public int compare(Long l1, Long l2) {
-                return l1.compareTo(l2);
-            }
-        });
-        sortMap.putAll(map);
-        return sortMap;
-    }
-
-    private Map<Long, Long> buildMap(List<Question> quesList, Map<Long, Long> map, int questionType) {
-        // 初始化map
-        for (int i = 1; i < 7; i++) {
-            if (i < 4) {
-                map.put((long) (questionType * 100 + i), 0L);
-            } else {
-                map.put((long) (questionType * 100 + 10 + i - 3), 0L);
-            }
-        }
-        for (Question question : quesList) {
-            if (question.getPublicity()) {
-                // 公开
-                if (question.getDifficulty() != null && question.getDifficulty().equals("难")
-                        || question.getDifficultyDegree() < 0.4 && question.getDifficultyDegree() > 0) {
-                    map = buildMapSum(questionType * 100L + 1L, map);
-                } else if (question.getDifficulty() != null && question.getDifficulty().equals("中")
-                        || question.getDifficultyDegree() < 0.8 && question.getDifficultyDegree() > 0.3) {
-                    map = buildMapSum(questionType * 100L + 2L, map);
-                } else {
-                    map = buildMapSum(questionType * 100L + 3L, map);
-                }
-            } else {
-                // 非公开
-                if (question.getDifficulty() != null && question.getDifficulty().equals("难")
-                        || question.getDifficultyDegree() < 0.4 && question.getDifficultyDegree() > 0) {
-                    map = buildMapSum(questionType * 100L + 11L, map);
-                } else if (question.getDifficulty() != null && question.getDifficulty().equals("中")
-                        || question.getDifficultyDegree() < 0.8 && question.getDifficultyDegree() > 0.3) {
-                    map = buildMapSum(questionType * 100L + 12L, map);
-                } else {
-                    map = buildMapSum(questionType * 100L + 13L, map);
-                }
-            }
-        }
-        return map;
-    }
-
-    private Map<Long, Long> buildMapSum(long key, Map<Long, Long> map) {
-        Long sum = map.get(key);
-        map.put(key, sum + 1);
-        return map;
-    }
-
-    public List<Question> questionList(String courseNo, CourseProperty courseProperty, QuesStructType quesStructType,
-            Property parentProperty, Property sonProperty) {
-        Query query = new Query();
-        query.addCriteria(Criteria.where("orgId").is(courseProperty.getOrgId().toString()));
-        query.addCriteria(Criteria.where("course.enable").is("true"));
-        query.addCriteria(Criteria.where("course.code").is(courseNo));
-        query.addCriteria(Criteria.where("questionType").is(quesStructType.name()));
-        query.addCriteria(Criteria.where("quesProperties.coursePropertyName").is(courseProperty.getName()));
-        // 二级属性不为空,那么一级属性也不为空
-        if (sonProperty != null && sonProperty.getId() != null) {
-            query.addCriteria(Criteria.where("quesProperties").elemMatch(Criteria.where("firstProperty.id")
-                    .is(parentProperty.getId()).and("secondProperty.id").is(sonProperty.getId())));
-        } else {
-            if (parentProperty != null && parentProperty.getId() != null) {
-                query.addCriteria(Criteria.where("quesProperties")
-                        .elemMatch(Criteria.where("firstProperty.id").is(parentProperty.getId())));
-            }
-        }
-        List<Question> questionList = this.mongoTemplate.find(query, Question.class);
-        return questionList;
-    }
-
-    public List<Question> questionList2(String courseNo, CourseProperty courseProperty, QuesStructType quesStructType,
-            Property parentProperty, Property sonProperty, List<Question> questions) {
-        List<Question> questionList = new ArrayList<>();
-        String id = courseNo + quesStructType.name() + courseProperty.getName();
-        // 二级属性不为空,那么一级属性也不为空
-        if (sonProperty != null && sonProperty.getId() != null) {
-            id = id + parentProperty.getId() + sonProperty.getId();
-        } else {
-            if (parentProperty != null && parentProperty.getId() != null) {
-                id = id + parentProperty.getId();
-            }
-        }
-        for (Question question : questions) {
-            List<String> idStrings = new ArrayList<>();
-            String id_Q = question.getCourseNo() + question.getQuestionType();
-            List<QuesProperty> quesProperties = question.getQuesProperties();
-            if (quesProperties != null && quesProperties.size() > 0) {
-                for (QuesProperty property : quesProperties) {
-                    String idP = id_Q + property.getCoursePropertyName() + property.getFirstProperty().getId();
-                    if (property.getSecondProperty() != null) {
-                        idP = id_Q + property.getCoursePropertyName() + property.getFirstProperty().getId()
-                                + property.getSecondProperty().getId();
-                    }
-                    idStrings.add(idP);
-                }
-                if (idStrings.contains(id)) {
-                    questionList.add(question);
-                }
-            }
-        }
-        return questionList;
-    }
-
-    @Override
-    public void downOriginalPaper(String paperId, String loginName, HttpServletResponse response) throws Exception {
-//        String zipFileName = loginName + System.currentTimeMillis() + "";
-//        try {
-//            // 生成导出的试卷对象
-//            PaperExp paperExp = paperService.getDownPaperExp(paperId);
-//            File directory = new File(TEMP_FILE_EXP + File.separator + zipFileName);
-//            if (!directory.exists()) {
-//                directory.mkdirs();
-//            }
-//            String paperfileName = paperExp.getName() + "_" + paperExp.getCourseNo() + "_"
-//                    + ExamFileType.PAPER.getName() + DOCX_SUFFIX;
-//            File file = new File(TEMP_FILE_EXP + File.separator + zipFileName + File.separator + paperfileName);
-//            List<WordprocessingMLPackage> wordPackages = getPkgList(paperId);
-//            DocxProcessUtil.exportWordNew(paperExp, file, ExportPaperAbstractService.ORIGINAL_PAPER);
-//            DocxProcessUtil.processImage(zipFileName + File.separator + paperfileName, wordPackages);
-//            FileDisposeUtil.fileToZip(TEMP_FILE_EXP + File.separator + zipFileName, TEMP_FILE_EXP, zipFileName);
-//            FileDisposeUtil.downloadFile(paperExp.getName() + "_" + paperExp.getCourse().getCode() + ".zip",
-//                    TEMP_FILE_EXP + File.separator + zipFileName + ".zip", response);
-//        } finally {
-//            deteleFolder(TEMP_FILE_EXP, zipFileName);
-//        }
-    }
-
-    /**
-     * 获取当前试卷下所有试题WordPkg
-     *
-     * @param id
-     * @return
-     */
-//    protected List<WordprocessingMLPackage> getPkgList(String id) {
-//        Paper paper = Model.of(paperRepo.findById(id));
-//        List<WordprocessingMLPackage> wordMLPackages = paperDetailUnitRepo.findByPaperOrderByNumber(paper).stream()
-//                .map(PaperDetailUnit::getQuestion).collect(Collectors.toList()).stream()
-//                .map(question -> getPkgObj(question)).collect(Collectors.toList());
-//        return wordMLPackages;
-//    }
-//
-//    private WordprocessingMLPackage getPkgObj(Question question) {
-//        String pkgPathId = question.getQuesPkgPathId();
-//        QuestionPkgPath quesPkg = quesPkgPathRepo.findFirstById(pkgPathId);
-//        if (quesPkg == null) {
-//            byte[] bytes = new byte[0];
-//            return DocxProcessUtil.getPkg(bytes);
-//        }
-//        byte[] pkgByte = quesPkg.getQuesPkg();
-//        return DocxProcessUtil.getPkg(pkgByte);
-//    }
-
-    @Override
-    public void downQuestionDistributeByPapers(String paperIds, HttpServletResponse response) throws IOException {
-        List<QuestionDistributeDto> questionDistributes = new ArrayList<>();
-
-        // 定义课程集合
-        List<String> courseCodes = new ArrayList<>();
-
-        // 定义试题集合
-        List<Question> questions = new ArrayList<>();
-
-        // 查询试卷集合
-        String[] paperIdArray = paperIds.split(",");
-        for (int i = 0; i < paperIdArray.length; i++) {
-            Paper basePaper = Model.of(paperRepo.findById(paperIdArray[i]));
-            courseCodes.add(basePaper.getCourse().getCode());
-            // 将小题全部取出来,只取一次,减少对数据库的查询
-            List<PaperDetailUnit> allPaperDetailUnits = paperDetailUnitRepo.findByPaper(basePaper);
-            for (PaperDetailUnit unit : allPaperDetailUnits) {
-                if (unit.getQuestionType().equals(QuesStructType.SINGLE_ANSWER_QUESTION)
-                        || unit.getQuestionType().equals(QuesStructType.MULTIPLE_ANSWER_QUESTION)
-                        || unit.getQuestionType().equals(QuesStructType.BOOL_ANSWER_QUESTION)) {
-                    questions.add(unit.getQuestion());
-                }
-            }
-        }
-
-        // 根据课程code查询课程属性集合
-        for (String courseCode : courseCodes) {
-            List<CourseProperty> courseProperties = coursePropertyRepo.findByCourseCodeAndEnable(courseCode, true);
-            // 遍历课程属性集合,根据课程属性查询一级
-            if (courseProperties != null && courseProperties.size() > 0) {
-                for (CourseProperty courseProperty : courseProperties) {
-                    List<Property> parentProperties = propertyService.findParentProperties(courseProperty.getId(),
-                            courseProperty.getOrgId());
-                    if (parentProperties != null && parentProperties.size() > 0) {
-                        for (Property parentProperty : parentProperties) {
-                            List<Property> sonProperties = propertyService.findSonProperties(parentProperty.getId());
-                            if (sonProperties != null && sonProperties.size() > 0) {
-                                for (Property sonProperty : sonProperties) {
-                                    // 单选题集合
-                                    List<Question> sinList = questionList2(courseCode, courseProperty,
-                                            QuesStructType.SINGLE_ANSWER_QUESTION, parentProperty, sonProperty,
-                                            questions);
-                                    // 多选题集合
-                                    List<Question> mulList = questionList2(courseCode, courseProperty,
-                                            QuesStructType.MULTIPLE_ANSWER_QUESTION, parentProperty, sonProperty,
-                                            questions);
-                                    // 判断题集合
-                                    List<Question> bolList = questionList2(courseCode, courseProperty,
-                                            QuesStructType.BOOL_ANSWER_QUESTION, parentProperty, sonProperty,
-                                            questions);
-
-                                    List<Question> fillList = null;
-                                    // fillList = questionList2(courseNo,
-                                    // courseProperty,
-                                    // QuesStructType.FILL_BLANK_QUESTION,
-                                    // parentProperty, sonProperty, questions);
-                                    List<Question> textList = null;
-                                    // textList = questionList2(courseNo,
-                                    // courseProperty,
-                                    // QuesStructType.TEXT_ANSWER_QUESTION,
-                                    // parentProperty, sonProperty, questions);
-
-                                    // 计算所有题型数量
-                                    Map<Long, Long> map = countQuesType(sinList, mulList, bolList, fillList, textList);
-                                    QuestionDistributeDto questionDistributeDto = new QuestionDistributeDto(
-                                            courseProperty.getName(), parentProperty.getName(), sonProperty.getName(),
-                                            map);
-                                    questionDistributes.add(questionDistributeDto);
-                                }
-                            } else {
-                                // 一级属性不为空,二级属性为空
-                                // 单选题集合
-                                List<Question> sinList = questionList2(courseCode, courseProperty,
-                                        QuesStructType.SINGLE_ANSWER_QUESTION, parentProperty, null, questions);
-                                // 多选题集合
-                                List<Question> mulList = questionList2(courseCode, courseProperty,
-                                        QuesStructType.MULTIPLE_ANSWER_QUESTION, parentProperty, null, questions);
-                                // 判断题集合
-                                List<Question> bolList = questionList2(courseCode, courseProperty,
-                                        QuesStructType.BOOL_ANSWER_QUESTION, parentProperty, null, questions);
-
-                                List<Question> fillList = null;
-                                // fillList = questionList2(courseNo,
-                                // courseProperty,
-                                // QuesStructType.FILL_BLANK_QUESTION,
-                                // parentProperty, null, questions);
-                                List<Question> textList = null;
-                                // textList = questionList2(courseNo,
-                                // courseProperty,
-                                // QuesStructType.TEXT_ANSWER_QUESTION,
-                                // parentProperty, null, questions);
-
-                                // 计算所有题型数量
-                                Map<Long, Long> map = countQuesType(sinList, mulList, bolList, fillList, textList);
-                                QuestionDistributeDto questionDistributeDto = new QuestionDistributeDto(
-                                        courseProperty.getName(), parentProperty.getName(), null, map);
-                                questionDistributes.add(questionDistributeDto);
-                            }
-                        }
-                    } else {
-                        // 一级属性为空
-                        QuestionDistributeDto questionDistributeDto = new QuestionDistributeDto(
-                                courseProperty.getName(), null, null, null);
-                        questionDistributes.add(questionDistributeDto);
-                    }
-                }
-            }
-
-            final String fileName = System.currentTimeMillis() + "试题分布.xlsx";
-            final String filePath = TEMP_FILE_EXP + File.separator + fileName;
-
-            // 生成Excel导出
-            File tempFile = this.writeExcel(questionDistributes, filePath);
-            FileDisposeUtil.downloadFile(fileName, filePath, response);
-            FileUtils.deleteQuietly(tempFile);
-        }
-    }
-
-    @Override
-    public void downOriginalPaperPlus(String paperId, Long rootOrgId, HttpServletResponse response) throws IOException{
-        String zipFileName = IdUtils.uuid();
-        File directory = new File(TEMP_FILE_EXP + File.separator + zipFileName);
-        if (!directory.exists()) {
-            directory.mkdirs();
-        }
-        // doc固定源文件目录
-//        File docxDir = new File(JsonExportUtil.getDocxBasePath());
-//        // 将要生成的doc源文件目录
-//        File docxTargetDir = new File(directory.getAbsolutePath() + "/docx/");
-//        docxTargetDir.mkdir();
-        try {
-            // 复制docx基础文件
-//            FileUtils.copyDirectory(docxDir, docxTargetDir);
-            // 生成导出的试卷对象
-            PaperExp paperExp = paperService.getDownPaperExp(paperId);
-            
-            PaperUtil.setQuestionSeq(paperExp.getPaperDetails(), PaperSeqMode.MODE4);
-//            // 处理并生成doc源文件
-//            dispose(docxTargetDir, paperExp);
-//            // 压缩docx源文件
-//            String paperfileName = paperExp.getName() + "_" + paperExp.getCourseNo() + "_"
-//                    + ExamFileType.PAPER.getName();
-//            File zipfile = new File(docxTargetDir.getParentFile().getAbsolutePath() + File.separator + "data"
-//                    + File.separator + paperfileName + ZIP_SUFFIX);
-//            zipfile.getParentFile().mkdir();
-//            File docfile = new File(docxTargetDir.getParentFile().getAbsolutePath() + File.separator + "data"
-//                    + File.separator + File.separator + paperfileName + DOCX_SUFFIX);
-//            FileDisposeUtil.createZip(docxTargetDir.getAbsolutePath(), zipfile.getAbsolutePath());
-//            // 修改压缩包为doc文件
-//            zipfile.renameTo(docfile);
-            File docfile= ExportPaperUtil.createOriginPaperDocFile(paperExp, directory);
-            // doc文件加入下载包中
-            FileDisposeUtil.fileToZip(docfile.getParentFile().getAbsolutePath(),
-                    directory.getAbsolutePath(), zipFileName);
-            // 下载文件
-            FileDisposeUtil.downloadFile(paperExp.getName() + "_" + paperExp.getCourse().getCode() + ".zip",
-                    directory.getAbsolutePath() + File.separator + zipFileName + ".zip", response);
-        } finally {
-            FileUtils.deleteDirectory(directory);
-        }
-
-    }
-
-//    private void dispose(File docxTargetDir, PaperExp paperExp) throws IOException {
-//        ExportTempDataDto dto = new ExportTempDataDto();
-//        if (paperExp.getPaperDetails() != null && paperExp.getPaperDetails().size() > 0) {
-//            for (PaperDetailExp pde : paperExp.getPaperDetails()) {
-//                dto.setMainNum(dto.getMainNum() + 1);
-//                dto.setSubNum(0);
-//                if (pde.getPaperDetailUnits() != null && pde.getPaperDetailUnits().size() > 0) {
-//                    for (PaperDetailUnitExp pdue : pde.getPaperDetailUnits()) {
-//                        Question qes = pdue.getQuestion();
-//                        disposeQuestion(qes, dto);
-//                    }
-//                }
-//            }
-//        }
-//        // content-type
-//        writeContentType(docxTargetDir, dto);
-//        // document
-//        writeDocument(docxTargetDir, paperExp);
-//        // document-rel
-//        writeDocumentRel(docxTargetDir, dto);
-//        // image file
-//        writeImage(docxTargetDir, dto);
-//    }
-//
-//    private void writeImage(File docxTargetDir, ExportTempDataDto dto) throws IOException {
-//        for (SectionElement se : dto.getImages()) {
-//            File file = new File(docxTargetDir.getAbsolutePath() + "/word/media/image" + se.getParams().getIndex() + "."
-//                    + se.getParams().getType());
-//            String base64 = se.getValue();
-//            if (base64.contains("data:image")) {
-//                base64 = base64.substring(base64.indexOf(",") + 1);
-//            }
-//            BASE64Decoder decoder = new BASE64Decoder();
-//            byte[] bytes = decoder.decodeBuffer(base64);
-//            FileUtils.writeByteArrayToFile(file, bytes);
-//        }
-//    }
-//
-//    private void writeDocumentRel(File docxTargetDir, ExportTempDataDto dto) throws IOException {
-//        Map<String, Object> map = new HashMap<String, Object>();
-//        map.put("images", dto.getImages());
-//        String doc = JsonExportUtil.getDocumentRelDoc(map);
-//        File file = new File(docxTargetDir.getAbsolutePath() + "/word/_rels/document.xml.rels");
-//        FileUtils.writeStringToFile(file, doc, "utf-8");
-//    }
-//
-//    private void writeContentType(File docxTargetDir, ExportTempDataDto dto) throws IOException {
-//        Map<String, Object> map = new HashMap<String, Object>();
-//        map.put("images", dto.getTypes());
-//        String doc = JsonExportUtil.getContentTypesDoc(map);
-//        File file = new File(docxTargetDir.getAbsolutePath() + "/[Content_Types].xml");
-//        FileUtils.writeStringToFile(file, doc, "utf-8");
-//    }
-//
-//    private void writeDocument(File docxTargetDir, PaperExp paperExp) throws IOException {
-//        String doc = JsonExportUtil.getDocumentDoc(paperExp);
-//        File file = new File(docxTargetDir.getAbsolutePath() + "/word/document.xml");
-//        FileUtils.writeStringToFile(file, doc, "utf-8");
-//    }
-//
-//    private void disposeQuestion(Question qes, ExportTempDataDto dto) {
-//        if (qes != null) {
-//            List<JSection> slist1 = JsonExportUtil.getSections(qes.getQuesBody());
-//            if (slist1 != null && slist1.size() > 0) {
-//                if (qes.getSubQuestions() == null || qes.getSubQuestions().size() == 0) {// 套题题干不加题号
-//                    dto.setSubNum(dto.getSubNum() + 1);
-//                    SectionElement se = new SectionElement();
-//                    se.setType(JsonExportUtil.ELEMENT_TYPE_TEXT);
-//                    se.setValue(dto.getSubNum() + ".");
-//                    slist1.get(0).getElements().add(0, se);
-//                }
-//
-//                htmlToDoc(slist1, dto);
-//                qes.setQuesBodyWord(getQuestionDoc(slist1));
-//            }
-//
-//            if (qes.getQuesOptions() != null && qes.getQuesOptions().size() > 0) {
-//                int index = 0;
-//                for (QuesOption qo : qes.getQuesOptions()) {
-//                    List<JSection> slist2 = JsonExportUtil.getSections(qo.getOptionBody());
-//                    if (slist2 != null && slist2.size() > 0) {
-//                        SectionElement se = new SectionElement();
-//                        se.setType(JsonExportUtil.ELEMENT_TYPE_TEXT);
-//                        se.setValue(JsonExportUtil.QUESOPS.charAt(index) + ".");
-//                        index++;
-//                        slist2.get(0).getElements().add(0, se);
-//                        htmlToDoc(slist2, dto);
-//                        qo.setOptionBodyWord(getQuestionDoc(slist2));
-//                    }
-//
-//                }
-//            }
-//            List<JSection> slist3 = JsonExportUtil.getSections(qes.getQuesAnswer());
-//            if (slist3 != null && slist3.size() > 0) {
-//                SectionElement se = new SectionElement();
-//                se.setType(JsonExportUtil.ELEMENT_TYPE_TEXT);
-//                se.setValue("[答案]:");
-//                slist3.get(0).getElements().add(0, se);
-//
-//                htmlToDoc(slist3, dto);
-//                qes.setQuesAnswerWord(getQuestionDoc(slist3));
-//            }
-//
-//            if (qes.getSubQuestions() != null && qes.getSubQuestions().size() > 0) {
-//                dto.setSubNum(0);
-//                for (Question sunqes : qes.getSubQuestions()) {
-//                    disposeQuestion(sunqes, dto);// 递归处理套题
-//                }
-//            }
-//        }
-//    }
-//
-//    private void htmlToDoc(List<JSection> slist, ExportTempDataDto dto) {
-//        for (JSection js : slist) {
-//            for (SectionElement se : js.getElements()) {
-//                if (JsonExportUtil.ELEMENT_TYPE_IMG.equals(se.getType())) {
-//                    dto.setIndex(dto.getIndex() + 1);
-//                    se.getParams().setIndex(dto.getIndex());
-//                    se.getParams().setRid(JsonExportUtil.ELEMENT_TYPE_RID + dto.getIndex());
-//                    se.getParams().setType(getImageType(se.getValue()));
-//                    dto.getTypes().add(se.getParams().getType());
-//                    dto.getImages().add(se);
-//                }
-//            }
-//        }
-//    }
-//
-//    private String getImageType(String base64) {
-//        return base64.substring(11, base64.indexOf(";"));
-//    }
-//
-//    private String getQuestionDoc(List<JSection> sections) {
-//        Map<String, Object> map = new HashMap<String, Object>();
-//        map.put("sections", sections);
-//        String doc = JsonExportUtil.getQuestionSectionDoc(map);
-//        return doc;
-//    }
+package cn.com.qmth.examcloud.core.questions.service.impl;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.servlet.http.HttpServletResponse;
+
+import cn.com.qmth.examcloud.support.fss.FssFactory;
+import cn.com.qmth.examcloud.support.fss.FssHelper;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Service;
+
+import com.google.common.collect.Lists;
+import com.google.gson.Gson;
+
+import cn.com.qmth.examcloud.api.commons.enums.AdminOperateType;
+import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.core.questions.base.CommonUtils;
+import cn.com.qmth.examcloud.core.questions.base.FileDisposeUtil;
+import cn.com.qmth.examcloud.core.questions.base.IdUtils;
+import cn.com.qmth.examcloud.core.questions.base.Model;
+import cn.com.qmth.examcloud.core.questions.base.converter.utils.FileUtil;
+import cn.com.qmth.examcloud.core.questions.base.enums.ExamFileType;
+import cn.com.qmth.examcloud.core.questions.base.enums.PaperSeqMode;
+import cn.com.qmth.examcloud.core.questions.base.question.enums.QuesStructType;
+import cn.com.qmth.examcloud.core.questions.dao.CoursePropertyRepo;
+import cn.com.qmth.examcloud.core.questions.dao.PaperDetailUnitRepo;
+import cn.com.qmth.examcloud.core.questions.dao.PaperRepo;
+import cn.com.qmth.examcloud.core.questions.dao.QuestionAudioRepo;
+import cn.com.qmth.examcloud.core.questions.dao.entity.Course;
+import cn.com.qmth.examcloud.core.questions.dao.entity.CourseProperty;
+import cn.com.qmth.examcloud.core.questions.dao.entity.Paper;
+import cn.com.qmth.examcloud.core.questions.dao.entity.PaperDetail;
+import cn.com.qmth.examcloud.core.questions.dao.entity.PaperDetailUnit;
+import cn.com.qmth.examcloud.core.questions.dao.entity.Property;
+import cn.com.qmth.examcloud.core.questions.dao.entity.QuesOption;
+import cn.com.qmth.examcloud.core.questions.dao.entity.QuesProperty;
+import cn.com.qmth.examcloud.core.questions.dao.entity.Question;
+import cn.com.qmth.examcloud.core.questions.dao.entity.QuestionAudio;
+import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.Block;
+import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.ComputerTestOption;
+import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.ComputerTestPaper;
+import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.ComputerTestPaperDetail;
+import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.ComputerTestQuestion;
+import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.Section;
+import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.Sections;
+import cn.com.qmth.examcloud.core.questions.service.ExportPaperService;
+import cn.com.qmth.examcloud.core.questions.service.ExportThemisPaperService;
+import cn.com.qmth.examcloud.core.questions.service.PaperDetailService;
+import cn.com.qmth.examcloud.core.questions.service.PaperService;
+import cn.com.qmth.examcloud.core.questions.service.PropertyService;
+import cn.com.qmth.examcloud.core.questions.service.bean.dto.DownloadPaperDto;
+import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperExp;
+import cn.com.qmth.examcloud.core.questions.service.bean.dto.QuestionDistributeDto;
+import cn.com.qmth.examcloud.core.questions.service.converter.PrintExamPaperService;
+import cn.com.qmth.examcloud.core.questions.service.export.ExportPaperAbstractService;
+import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisPaperAndAnswer;
+import cn.com.qmth.examcloud.core.questions.service.util.ExportPaperUtil;
+import cn.com.qmth.examcloud.core.questions.service.util.PaperUtil;
+import cn.com.qmth.examcloud.reports.commons.bean.AdminOperateReport;
+import cn.com.qmth.examcloud.reports.commons.util.ReportsUtil;
+
+@Service("exportPaperService")
+public class ExportPaperServiceImpl implements ExportPaperService {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ExportPaperServiceImpl.class);
+
+    public static final String TEMP_FILE_EXP = "docxExport/";
+
+    public static final String TEMP_FILE_NAME = "_考试说明.docx";
+
+    public static final String DOCX_SUFFIX = ".docx";
+
+    public static final String ZIP_SUFFIX = ".zip";
+
+    @Autowired
+    private PaperRepo paperRepo;
+
+    @Autowired
+    private PaperService paperService;
+
+    @Autowired
+    private PaperDetailService paperDetailService;
+
+    @Autowired
+    private MongoTemplate mongoTemplate;
+
+    @Autowired
+    private CoursePropertyRepo coursePropertyRepo;
+
+    @Autowired
+    private PropertyService propertyService;
+
+    @Autowired
+    private QuestionAudioRepo questionAudioRepo;
+
+    @Autowired
+    private PrintExamPaperService printExamPaperService;
+
+    @Autowired
+    private PaperDetailUnitRepo paperDetailUnitRepo;
+
+    @Autowired
+    private ExportThemisPaperService exportThemisPaperService;
+
+    // @Autowired
+    // protected QuesPkgPathRepo quesPkgPathRepo;
+
+    // @Autowired
+    // private SysProperty sysProperty;
+    @Override
+    public void exportPaperFile(String paperId, String exportContentList, HttpServletResponse response,
+            PaperSeqMode seqMode, String examType, String psw, User user) {
+        ExportPaperAbstractService exportPaperAbstractService = PaperUtil
+                .getByRootOrgId(user.getRootOrgId().toString());
+        // 根据试卷id查询试卷
+        Paper paper = Model.of(paperRepo.findById(paperId));
+
+        String zipFileName = IdUtils.uuid();
+        long startTime;
+        try {
+            File directory = new File(TEMP_FILE_EXP + File.separator + zipFileName);
+            if (!directory.exists()) {
+                directory.mkdirs();
+            }
+            if (exportContentList.indexOf(ExamFileType.PRINT_EXAM_PACKAGE.name()) > -1) {
+                printExamPaperService.downloadPaper(Lists.newArrayList(paper), directory.getAbsolutePath(), psw);
+            }
+            if (exportContentList.indexOf(ExamFileType.COMPUTERTEST_PACKAGE.name()) > -1) {
+                downJson(paper, zipFileName);
+            }
+            if (exportContentList.indexOf(ExamFileType.THEMIS_PACKAGE.name()) > -1) {
+                List<Paper> papers = new ArrayList<>();
+                papers.add(paper);
+                downThemisPackage(papers, zipFileName);
+            }
+            try {
+                DownloadPaperDto dto = new DownloadPaperDto(user.getRootOrgId(), paperId, zipFileName, examType,
+                        seqMode);
+                if (exportContentList.indexOf(ExamFileType.PAPER.name()) > -1) {
+                    exportPaperAbstractService.downloadPaper(dto);
+                }
+
+                if (exportContentList.indexOf(ExamFileType.ANSWER.name()) > -1) {
+                    exportPaperAbstractService.downloadPaperAnswer(dto);
+                }
+            } catch (StatusException e) {
+                LOG.error(e.getMessage(), e);
+                throw e;
+            } catch (Exception e) {
+                LOG.error(e.getMessage(), e);
+                throw new StatusException("100001", e.getMessage());
+            }
+            // 下载考试说明 2018-2-27 weiwehai
+            /*
+             * if(examType.equals("offLine") &&
+             * StringUtils.isNotBlank(paper.getExamRemark())){
+             * downExamRemark(paper,zipFileName); }
+             */
+            LOG.debug("开始压缩成zip...");
+            startTime = System.currentTimeMillis();
+            FileDisposeUtil.fileToZip(TEMP_FILE_EXP + File.separator + zipFileName, TEMP_FILE_EXP, zipFileName);
+            FileDisposeUtil.downloadFile(paper.getName() + "_" + paper.getCourse().getCode() + ".zip",
+                    TEMP_FILE_EXP + File.separator + zipFileName + ".zip", response);
+            long endTime = System.currentTimeMillis();
+            LOG.debug("下载zip耗时:" + (endTime - startTime) + "ms");
+        } finally {
+            long endTime = System.currentTimeMillis();
+            FileUtil.deleteFolder(TEMP_FILE_EXP + File.separator + zipFileName);
+            FileUtil.deleteFolder(TEMP_FILE_EXP + File.separator + zipFileName + ".zip");
+            // deteleFolder(TEMP_FILE_EXP, zipFileName);
+            long deleteTime = System.currentTimeMillis();
+            LOG.debug("删除文件耗时:" + (deleteTime - endTime) + "ms");
+        }
+        StringBuilder paperInfo = new StringBuilder();
+        paperInfo.append("课程:" + paper.getCourse().getName() + "(" + paper.getCourse().getCode() + ")");
+        paperInfo.append(" 试卷名称:" + paper.getName());
+        paperInfo.append(getContentName(exportContentList));
+
+        ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
+                AdminOperateType.TYPE36.getDesc(), paperInfo.toString()));
+    }
+
+    private String getContentName(String exportContentList) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(" 下载内容:");
+        for (String content : exportContentList.split(",")) {
+            sb.append(ExamFileType.valueOf(content).getName() + ",");
+        }
+        sb.deleteCharAt(sb.length() - 1);
+        return sb.toString();
+    }
+
+    /**
+     * 下载考试说明
+     *
+     * @param zipFileName
+     * @throws Exception
+     */
+    // @SuppressWarnings("unused")
+    // private void downExamRemark(Paper paper, String zipFileName) throws
+    // Exception {
+    // // 1.考试说明html转成word
+    // String title = "<p style=\"text-align:center\"><span
+    // style=\"font-size:26px\"><span
+    // style=\"font-family:宋体\">考&nbsp;试&nbsp;说&nbsp;明</span></span></p>";
+    // WordprocessingMLPackage wordMLPackage =
+    // WordprocessingMLPackage.createPackage();
+    // DocxProcessUtil.html2Docx(wordMLPackage, CommonUtils.formatHtml(title +
+    // paper.getExamRemark()));
+    // // 2.导出考试说明word
+    // File file = new File(TEMP_FILE_EXP + File.separator + zipFileName +
+    // File.separator + paper.getCourse().getCode()
+    // + TEMP_FILE_NAME);
+    // Docx4J.save(wordMLPackage, file);
+    // }
+
+    // private void deteleFolder(String sourceFilePath, String zipFileName) {
+    // File ComputerTestPaperfoler = new File(sourceFilePath + File.separator +
+    // "json");
+    // if (ComputerTestPaperfoler.exists()) {
+    // FileUtils.deleteQuietly(ComputerTestPaperfoler);
+    // }
+    // File zipFolder = new File(sourceFilePath + File.separator + zipFileName);
+    // if (zipFolder.exists()) {
+    // FileUtils.deleteQuietly(zipFolder);
+    // }
+    // File zipFile = new File(sourceFilePath + File.separator + zipFileName +
+    // ".zip");
+    // if (zipFile.exists()) {
+    // FileUtils.deleteQuietly(zipFile);
+    // }
+    // }
+
+    private void downJson(Paper paper, String zipFileName) {
+        ComputerTestPaper computerTestPaper = buildComputerTestPapers(paper);
+        String jsonDirectory = TEMP_FILE_EXP + File.separator + zipFileName + File.separator + "json";
+        try {
+            // 新建文件夹
+            File dirFile = new File(jsonDirectory);
+            if (!dirFile.exists()) {
+                dirFile.mkdirs();
+            }
+            makeComputerTestPaperToJsonFile(paper.getCourse().getCode(), computerTestPaper, jsonDirectory);
+            downloadAudio(computerTestPaper, jsonDirectory);
+            // 将文件夹打包成zip压缩包放在docxExport下
+            FileDisposeUtil.fileToZip(jsonDirectory, TEMP_FILE_EXP + File.separator + zipFileName,
+                    paper.getCourse().getCode() + "_" + paper.getName());
+        } finally {
+            FileUtil.deleteDirectory(jsonDirectory);
+        }
+    }
+
+    private void downThemisPackage(List<Paper> papers, String zipFileName) {
+        String zipDirectory = TEMP_FILE_EXP + File.separator + zipFileName + File.separator + "themis_package";
+        // 新建文件夹
+        File dirFile = new File(zipDirectory);
+        if (!dirFile.exists()) {
+            dirFile.mkdirs();
+        }
+        try {
+            for (Paper paper : papers) {
+                ThemisPaperAndAnswer pa = null;
+                try {
+                    pa = exportThemisPaperService.buildPaperAndAnswer(paper);
+                } catch (StatusException e) {
+                    throw new StatusException("试卷 " + paper.getName() + " " + e.getDesc());
+                }
+                String paperDirectory = zipDirectory + File.separator + paper.getCourseNo() + File.separator
+                        + paper.getId();
+                File paperDir = new File(paperDirectory);
+                if (!paperDir.exists()) {
+                    paperDir.mkdirs();
+                }
+                exportThemisPaperService.makePaperAnswerToJsonFile(pa, paperDirectory);
+                exportThemisPaperService.downloadAudio(pa.getPaper(), paperDirectory);
+            }
+            // 将文件夹打包成zip压缩包放在docxExport下
+            File zipFile = new File(TEMP_FILE_EXP + File.separator + zipFileName + File.separator + "在线考试数据包.zip");
+            FileUtil.doZip(dirFile, zipFile);
+        } finally {
+            FileUtil.deleteDirectory(zipDirectory);
+        }
+    }
+
+    private void downloadAudio(ComputerTestPaper computerTestPaper, String jsonDirectory) {
+        // 取到所有大题
+        List<ComputerTestPaperDetail> details = computerTestPaper.getDetails();
+        if (details != null && details.size() > 0) {
+            for (ComputerTestPaperDetail detail : details) {
+                // 取到所有小题集合
+                List<ComputerTestQuestion> questions = detail.getQuestions();
+                if (questions != null && questions.size() > 0) {
+                    for (ComputerTestQuestion question : questions) {
+                        int bodyNum = 1;
+                        // 取到题干
+                        Sections body = question.getBody();
+                        List<Section> sections = body.getSections();
+                        for (Section section : sections) {
+                            List<Block> blocks = section.getBlocks();
+                            if (blocks != null && blocks.size() > 0) {
+                                for (Block block : blocks) {
+                                    if (block.getType().equals("audio")) {
+                                        String id = block.getValue();
+                                        QuestionAudio questionAudio = Model.of(questionAudioRepo.findById(id));
+                                        String audioFileName = questionAudio.getId() + "_" + detail.getNumber() + "_"
+                                                + question.getNumber() + "_1_" + bodyNum + "."
+                                                + questionAudio.getFileSuffixes();
+
+                                        File file = new File(jsonDirectory + File.separator + audioFileName);
+
+                                        String filePath = FssHelper.fixFilePath(questionAudio.getFileUrl());
+                                        FssFactory.getInstance().readFile(filePath, file);
+
+                                        bodyNum++;
+                                    }
+                                }
+                            }
+                        }
+                        // 取到选项
+                        List<ComputerTestOption> options = question.getOptions();
+                        if (options != null && options.size() > 0) {
+                            for (ComputerTestOption computerTestOption : options) {
+                                int optionNum = 1;
+                                // 获取选项主体
+                                Sections optionBody = computerTestOption.getBody();
+                                List<Section> optionSections = optionBody.getSections();
+                                if (optionSections != null && optionSections.size() > 0) {
+                                    for (Section optionSection : optionSections) {
+                                        List<Block> blocks = optionSection.getBlocks();
+                                        if (blocks != null && blocks.size() > 0) {
+                                            for (Block block : blocks) {
+                                                if (block.getType().equals("audio")) {
+                                                    String id = block.getValue();
+                                                    QuestionAudio questionAudio = Model
+                                                            .of(questionAudioRepo.findById(id));
+                                                    String audioFileName = questionAudio.getId() + "_"
+                                                            + detail.getNumber() + "_" + question.getNumber() + "_2_"
+                                                            + computerTestOption.getNumber() + "_" + optionNum + "."
+                                                            + questionAudio.getFileSuffixes();
+
+                                                    File file = new File(
+                                                            jsonDirectory + File.separator + audioFileName);
+
+                                                    String filePath = FssHelper.fixFilePath(questionAudio.getFileUrl());
+                                                    FssFactory.getInstance().readFile(filePath, file);
+
+                                                    optionNum++;
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 构建机考数据包实体类
+     *
+     * @return
+     */
+    public ComputerTestPaper buildComputerTestPapers(Paper paper) {
+        // 得到所有旧对象的大题对象
+        List<PaperDetail> paperDetails = paperService.findPaperDetailsById(paper.getId());
+        // 通过 paper 对象 ,生成新的 ComputerTestPaper 对象
+        ComputerTestPaper computerTestPaper = new ComputerTestPaper(paper, "");
+        List<ComputerTestPaperDetail> details = new ArrayList<>();
+        // 遍历所有旧大题对象,得到小题对象的集合
+        for (PaperDetail paperDetail : paperDetails) {
+            List<PaperDetailUnit> paperDetailUnits = paperDetailService.getUnitsByPaperDetailId(paperDetail.getId());
+            ComputerTestPaperDetail computerTestPaperDetail = new ComputerTestPaperDetail(paperDetail);
+            List<ComputerTestQuestion> questions = new ArrayList<>();
+            // 遍历所有的小题对象
+            for (int i = 0; i < paperDetailUnits.size(); i++) {
+                PaperDetailUnit paperDetailUnit = paperDetailUnits.get(i);
+                // 根据旧的小题对象,生成新的小题对象
+                ComputerTestQuestion computerTestQuestion = new ComputerTestQuestion(paperDetailUnit);
+                // 设置小题题号
+                computerTestQuestion.setNumber(i + 1);
+                // 得到小题题干
+                computerTestQuestion
+                        .setBody(getBodyOrAnswer(paperDetailUnit.getQuestion().getQuesBody(), computerTestPaper));
+                // 得到小题所有选项
+                computerTestQuestion.setOptions(getOption(paperDetailUnit.getQuestion(), computerTestPaper));
+                // 得到小题的答案
+                computerTestQuestion
+                        .setAnswer(getBodyOrAnswer(paperDetailUnit.getQuestion().getQuesAnswer(), computerTestPaper));
+                // 查询小题中的 套题
+                List<Question> subQuestionsList = paperDetailUnit.getQuestion().getSubQuestions();
+                // 判断这个小题中是否有套题
+                if (subQuestionsList != null && subQuestionsList.size() > 0) {
+                    List<ComputerTestQuestion> subQuestions = new ArrayList<>();
+                    // 遍历每个套题
+                    for (int j = 0; j < subQuestionsList.size(); j++) {
+                        Question subQuestion = subQuestionsList.get(j);
+                        ComputerTestQuestion subcomputerTestQuestion = new ComputerTestQuestion(subQuestion);
+                        // 设置套题中小题题号
+                        subcomputerTestQuestion.setNumber(j + 1);
+                        subcomputerTestQuestion.setBody(getBodyOrAnswer(subQuestion.getQuesBody(), computerTestPaper));
+                        subcomputerTestQuestion.setOptions(getOption(subQuestion, computerTestPaper));
+                        subcomputerTestQuestion
+                                .setAnswer(getBodyOrAnswer(subQuestion.getQuesAnswer(), computerTestPaper));
+                        subQuestions.add(subcomputerTestQuestion);
+                    }
+                    computerTestQuestion.setSubQuestions(subQuestions);
+                }
+                questions.add(computerTestQuestion);
+            }
+            computerTestPaperDetail.setQuestions(questions);
+            // paperDetail中的题数(unitCount)可能不准确,这里以questions的实际size为准
+            computerTestPaperDetail.setQuestionCount(questions.size());
+            details.add(computerTestPaperDetail);
+        }
+        computerTestPaper.setDetails(details);
+        return computerTestPaper;
+    }
+
+    private Sections getBodyOrAnswer(String str, ComputerTestPaper computerTestPaper) {
+        Sections body = new Sections();
+        List<Section> sections = new ArrayList<>();
+        // 得到小题题干或者答案行数
+        if (StringUtils.isBlank(str)) {
+            return body;
+        }
+        String[] questionRowStrings = str.split("</p>");
+        for (int i = 0; i < questionRowStrings.length; i++) {
+            List<Block> blocks = disposeQuestionBodyOrOption(questionRowStrings[i], computerTestPaper);
+            if (blocks != null && blocks.size() > 0) {
+                Section section = new Section();
+                // 将小题题干拆分为Block集合
+                section.setBlocks(blocks);
+                sections.add(section);
+            }
+        }
+        body.setSections(sections);
+        return body;
+    }
+
+    private List<ComputerTestOption> getOption(Question question, ComputerTestPaper computerTestPaper) {
+        // 得到小题选项
+        List<QuesOption> quesOptions = question.getQuesOptions();
+        List<ComputerTestOption> options = new ArrayList<>();
+        // 遍历小题选项
+        if (quesOptions != null && quesOptions.size() > 0) {
+            for (QuesOption quesOption : quesOptions) {
+                ComputerTestOption option = new ComputerTestOption();
+                option.setNumber(new Integer(quesOption.getNumber()));
+                option.setCorrect(quesOption.getIsCorrect() == 1 ? true : false);
+                Sections body = new Sections();
+
+                List<Section> sections = new ArrayList<>();
+                // 得到小题选项
+                String optionString = quesOption.getOptionBody();
+                String[] optionStrings = optionString.split("</p>");
+                for (int i = 0; i < optionStrings.length; i++) {
+                    List<Block> blocks = disposeQuestionBodyOrOption(optionStrings[i], computerTestPaper);
+                    if (blocks != null && blocks.size() > 0) {
+                        Section section = new Section();
+                        section.setBlocks(blocks);
+                        sections.add(section);
+                    }
+                }
+                body.setSections(sections);
+                option.setBody(body);
+                options.add(option);
+            }
+        }
+        return options;
+    }
+
+    private List<Block> disposeQuestionBodyOrOption(String questionRow, ComputerTestPaper computerTestPaper) {
+        List<Block> blocks = new ArrayList<>();
+        // 去掉每行里面的<p>,<span>,</span>标签
+        questionRow = questionRow.replaceAll("<p>", "").replaceAll("</p>", "").replaceAll("<span>", "")
+                .replaceAll("</span>", "").replaceAll("</a>", "");
+        String[] questionRowStrings = questionRow.split("<|/>|>");
+        boolean hasAudio = false;
+        for (int i = 0; i < questionRowStrings.length; i++) {
+            Block block = new Block();
+            String rowStr = questionRowStrings[i];
+            // 判断是否有图片
+            if (rowStr.startsWith("img")) {
+                rowStr = "<" + rowStr + ">";
+                Map<String, Object> param = new HashMap<>();
+                // 需要继续做截取,取到Parma
+                block.setType("image");
+                // 获取图片的路径
+                List<String> strSrcList = getImg(rowStr, "src");
+                if (strSrcList.size() > 0) {
+                    String strSrc = strSrcList.get(0).replaceAll("src=\"", "").replaceAll("\"", "");
+                    block.setValue(strSrc);
+                }
+                // 获取图片的高度
+                List<String> strHeightList = getImg(rowStr, "height");
+                if (strHeightList.size() > 0) {
+                    String strHeight = strHeightList.get(0).replaceAll("height=\"", "").replaceAll("\"", "");
+                    param.put("height", strHeight);
+                }
+                // 获取图片的宽度
+                List<String> strWidthList = getImg(rowStr, "width");
+                if (strHeightList.size() > 0) {
+                    String strWidth = strWidthList.get(0).replaceAll("width=\"", "").replaceAll("\"", "");
+                    param.put("width", strWidth);
+                }
+                block.setParam(param);
+                blocks.add(block);
+            } else if (rowStr.startsWith("a") && rowStr.contains("id") && rowStr.contains("name")) { // 处理音频
+                rowStr = "<" + rowStr + ">";
+                block.setPlayTime(1);
+                block.setType("audio");
+                block.setValue(CommonUtils.getAttrValue(rowStr, "id"));
+                blocks.add(block);
+                hasAudio = true;
+            } else {
+                block.setType("text");
+                rowStr = rowStr.replace("&nbsp;", "");// 消除空格
+                rowStr = rowStr.replace("&quot;", "\"");// 将&quot;转换成\"
+                rowStr = rowStr.replace("&lt;", "<");// 将&lt;转换成<
+                rowStr = rowStr.replace("&gt;", ">");// 将&gt;转换成>
+                rowStr = rowStr.replace("&amp;", "&");// 将&amp;转换成&
+                if (StringUtils.isNotBlank(rowStr)) {
+                    block.setValue(rowStr);
+                    blocks.add(block);
+                }
+            }
+        }
+        if (hasAudio) {
+            computerTestPaper.setHasVideo(1);
+        }
+        return blocks;
+    }
+
+    /**
+     * 获取图片里面的路径,长度,宽度
+     */
+    private List<String> getImg(String s, String str) {
+        String regex;
+        List<String> list = new ArrayList<>();
+        regex = str + "=\"(.*?)\"";
+        Pattern pa = Pattern.compile(regex, Pattern.DOTALL);
+        Matcher ma = pa.matcher(s);
+        while (ma.find()) {
+            list.add(ma.group());
+        }
+        return list;
+    }
+
+    /**
+     * 将computerTestPaper对象生成JSON文件存放在jsonDirectoryPath中
+     *
+     * @param computerTestPaper
+     * @param jsonDirectoryPath
+     */
+    @SuppressWarnings("deprecation")
+    private void makeComputerTestPaperToJsonFile(String courseCode, ComputerTestPaper computerTestPaper,
+            String jsonDirectoryPath) {
+        // 创建新的JSON文件
+        File file = new File(jsonDirectoryPath + File.separator + courseCode + ".json");
+        // 将对象转成 json对象
+        Gson gson = new Gson();
+        String strJSON = gson.toJson(computerTestPaper);
+
+        strJSON = CommonUtils.replaceUnicodeStr(strJSON);
+        // 生成文件流写入JSON文件
+        FileOutputStream outputStream = null;
+        try {
+            outputStream = new FileOutputStream(file);
+            byte b[] = strJSON.getBytes();
+            outputStream.write(b);
+            outputStream.flush();
+        } catch (FileNotFoundException e) {
+            LOG.error(e.getMessage(), e);
+        } catch (IOException e) {
+            LOG.error(e.getMessage(), e);
+        } finally {
+            IOUtils.closeQuietly(outputStream);
+        }
+    }
+
+    @Override
+    public void exportPaperFiles(List<String> paperIds, String exportContentList, HttpServletResponse response,
+            PaperSeqMode seqMode, String examType, User user) throws Exception {
+        ExportPaperAbstractService exportPaperAbstractService = PaperUtil
+                .getByRootOrgId(user.getRootOrgId().toString());
+        // 根据试卷id查询所有试卷
+        List<Paper> papers = CommonUtils.toList(paperRepo.findByIdIn(paperIds));
+        String zipFileName = IdUtils.uuid();
+        try {
+            // 创建压缩文件夹
+            File directory = new File(TEMP_FILE_EXP + File.separator + zipFileName);
+            directory.mkdirs();
+            // 下载试卷
+            if (exportContentList.indexOf(ExamFileType.PAPER.name()) > -1) {
+                for (Paper paper : papers) {
+                    DownloadPaperDto dto = new DownloadPaperDto(user.getRootOrgId(), paper.getId(), zipFileName,
+                            examType, seqMode);
+                    exportPaperAbstractService.downloadPaper(dto);
+                }
+            }
+            // 下载答案
+            if (exportContentList.indexOf(ExamFileType.ANSWER.name()) > -1) {
+                for (Paper paper : papers) {
+                    DownloadPaperDto dto = new DownloadPaperDto(user.getRootOrgId(), paper.getId(), zipFileName,
+                            examType, seqMode);
+                    exportPaperAbstractService.downloadPaperAnswer(dto);
+                }
+            }
+            // 下载机考数据包
+            if (exportContentList.indexOf(ExamFileType.COMPUTERTEST_PACKAGE.name()) > -1) {
+                for (Paper paper : papers) {
+                    downJson(paper, zipFileName);
+                }
+            }
+            // 下载在线考试数据包
+            if (exportContentList.indexOf(ExamFileType.THEMIS_PACKAGE.name()) > -1) {
+                downThemisPackage(papers, zipFileName);
+            }
+            FileDisposeUtil.fileToZip(TEMP_FILE_EXP + File.separator + zipFileName, TEMP_FILE_EXP, zipFileName);
+            FileDisposeUtil.downloadFile(zipFileName + ".zip", TEMP_FILE_EXP + File.separator + zipFileName + ".zip",
+                    response);
+        } finally {
+            FileUtil.deleteFolder(TEMP_FILE_EXP + File.separator + zipFileName);
+            FileUtil.deleteFolder(TEMP_FILE_EXP + File.separator + zipFileName + ".zip");
+        }
+        StringBuilder paperInfo = new StringBuilder();
+        paperInfo.append("下载数量:" + paperIds.size());
+        paperInfo.append(getContentName(exportContentList));
+
+        ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
+                AdminOperateType.TYPE37.getDesc(), paperInfo.toString()));
+
+    }
+
+    @Override
+    public void downQuestionDistribute(String courseCode, HttpServletResponse response) throws IOException {
+        // 生成导出Excle的list集合
+        List<QuestionDistributeDto> questionDistributes = this.downQuestionDistribute(courseCode);
+
+        final String fileName = courseCode + "试题分布.xlsx";
+        final String filePath = TEMP_FILE_EXP + File.separator + fileName;
+
+        // 生成Excel导出
+        File tempFile = this.writeExcel(questionDistributes, filePath);
+        FileDisposeUtil.downloadFile(fileName, filePath, response);
+        FileUtils.deleteQuietly(tempFile);
+    }
+
+    @Override
+    public void downQuestionDistributes(List<Course> courses) throws IOException {
+        if (CollectionUtils.isEmpty(courses)) {
+            return;
+        }
+
+        for (Course course : courses) {
+            List<QuestionDistributeDto> questionDistributes = this.downQuestionDistribute(course.getCode());
+            final String fileName = course.getCode() + "试题分布.xlsx";
+            final String filePath = TEMP_FILE_EXP + File.separator + fileName;
+            this.writeExcel(questionDistributes, filePath);
+        }
+    }
+
+    private List<QuestionDistributeDto> downQuestionDistribute(String courseCode) {
+        // 1.生成导出Excle的list集合
+        List<QuestionDistributeDto> questionDistributes = new ArrayList<>();
+
+        // 2.根据课程code查询课程属性集合
+        List<CourseProperty> courseProperties = coursePropertyRepo.findByCourseCodeAndEnable(courseCode, true);
+        if (CollectionUtils.isEmpty(courseProperties)) {
+            return questionDistributes;
+        }
+
+        // 3.遍历课程属性集合,根据课程属性查询一级
+        for (CourseProperty courseProperty : courseProperties) {
+            List<Property> parentProperties = propertyService.findParentProperties(courseProperty.getId(),
+                    courseProperty.getOrgId());
+            if (parentProperties != null && parentProperties.size() > 0) {
+                for (Property parentProperty : parentProperties) {
+                    List<Property> sonProperties = propertyService.findSonProperties(parentProperty.getId());
+                    if (sonProperties != null && sonProperties.size() > 0) {
+                        for (Property sonProperty : sonProperties) {
+                            // 单选题集合
+                            List<Question> sinList = questionList(courseCode, courseProperty,
+                                    QuesStructType.SINGLE_ANSWER_QUESTION, parentProperty, sonProperty);
+                            // 多选题集合
+                            List<Question> mulList = questionList(courseCode, courseProperty,
+                                    QuesStructType.MULTIPLE_ANSWER_QUESTION, parentProperty, sonProperty);
+                            // 判断题集合
+                            List<Question> bolList = questionList(courseCode, courseProperty,
+                                    QuesStructType.BOOL_ANSWER_QUESTION, parentProperty, sonProperty);
+
+                            List<Question> fillList = null;
+                            // fillList = questionList(courseCode,
+                            // courseProperty,
+                            // QuesStructType.FILL_BLANK_QUESTION,
+                            // parentProperty, sonProperty);
+                            List<Question> textList = null;
+                            // textList = questionList(courseCode,
+                            // courseProperty,
+                            // QuesStructType.TEXT_ANSWER_QUESTION,
+                            // parentProperty, sonProperty);
+
+                            // 计算所有题型数量
+                            Map<Long, Long> map = countQuesType(sinList, mulList, bolList, fillList, textList);
+                            QuestionDistributeDto questionDistributeDto = new QuestionDistributeDto(
+                                    courseProperty.getName(), parentProperty.getName(), sonProperty.getName(), map);
+                            questionDistributes.add(questionDistributeDto);
+                        }
+                    } else {
+                        // 一级属性不为空,二级属性为空
+                        // 单选题集合
+                        List<Question> sinList = questionList(courseCode, courseProperty,
+                                QuesStructType.SINGLE_ANSWER_QUESTION, parentProperty, null);
+                        // 多选题集合
+                        List<Question> mulList = questionList(courseCode, courseProperty,
+                                QuesStructType.MULTIPLE_ANSWER_QUESTION, parentProperty, null);
+                        // 判断题集合
+                        List<Question> bolList = questionList(courseCode, courseProperty,
+                                QuesStructType.BOOL_ANSWER_QUESTION, parentProperty, null);
+
+                        List<Question> fillList = null;
+                        // fillList = questionList(courseCode, courseProperty,
+                        // QuesStructType.FILL_BLANK_QUESTION, parentProperty,
+                        // null);
+                        List<Question> textList = null;
+                        // textList = questionList(courseCode, courseProperty,
+                        // QuesStructType.TEXT_ANSWER_QUESTION, parentProperty,
+                        // null);
+
+                        // 计算所有题型数量
+                        Map<Long, Long> map = countQuesType(sinList, mulList, bolList, fillList, textList);
+                        QuestionDistributeDto questionDistributeDto = new QuestionDistributeDto(
+                                courseProperty.getName(), parentProperty.getName(), null, map);
+                        questionDistributes.add(questionDistributeDto);
+                    }
+                }
+            } else {
+                // 一级属性为空
+                QuestionDistributeDto questionDistributeDto = new QuestionDistributeDto(courseProperty.getName(), null,
+                        null, null);
+                questionDistributes.add(questionDistributeDto);
+            }
+        }
+
+        return questionDistributes;
+    }
+
+    @SuppressWarnings("resource")
+    private File writeExcel(List<QuestionDistributeDto> questionDistributes, String filePath) throws IOException {
+        // 读取Excel模板
+        InputStream in = this.getClass().getResourceAsStream("/quesDistinct.xlsx");
+        // InputStream in =
+        // this.getClass().getResourceAsStream("/quesDistinctAll.xlsx");
+
+        // 获取第一个工作页
+        Workbook workBook = new XSSFWorkbook(in);
+        Sheet sheet = workBook.getSheetAt(0);
+
+        // 往Excel中写入数据,从第5行开始
+        for (int i = 0; i < questionDistributes.size(); i++) {
+            // 创建一行:从第五行开始,跳过表头
+            Row row = sheet.createRow(i + 4);
+
+            // 获取这行的记录
+            QuestionDistributeDto questionDistributeDto = questionDistributes.get(i);
+
+            // 每列赋值
+            row.createCell(0).setCellValue(questionDistributeDto.getCoursePropertyName());
+            row.createCell(1).setCellValue(questionDistributeDto.getFirstPropertyName());
+            row.createCell(2).setCellValue(questionDistributeDto.getSecondPropertyName());
+            Map<Long, Long> map = questionDistributeDto.getMap();
+            if (map == null) {
+                for (int j = 0; j < 18; j++) {
+                    row.createCell(j + 3).setCellValue(0);
+                }
+            } else {
+                int j = 3;
+                for (Long key : map.keySet()) {
+                    row.createCell(j).setCellValue(map.get(key));
+                    j++;
+                }
+            }
+        }
+
+        LOG.info("[WriteExcel] " + filePath);
+
+        File file = new File(filePath);
+        OutputStream out = new FileOutputStream(file);
+        workBook.write(out);
+        out.close();
+        return file;
+    }
+
+    private Map<Long, Long> countQuesType(List<Question> sinList, List<Question> mulList, List<Question> bolList,
+            List<Question> fillList, List<Question> textList) {
+        Map<Long, Long> map = new TreeMap<>();
+        map = buildMap(sinList, map, 1);
+        map = buildMap(mulList, map, 2);
+        map = buildMap(bolList, map, 3);
+
+        if (fillList != null) {
+            map = buildMap(fillList, map, 4);
+        }
+        if (textList != null) {
+            map = buildMap(textList, map, 5);
+        }
+
+        // 给map的键排序
+        Map<Long, Long> resultMap = sortMapByKey(map);
+        return resultMap;
+    }
+
+    private Map<Long, Long> sortMapByKey(Map<Long, Long> map) {
+        if (map == null || map.isEmpty()) {
+            return null;
+        }
+        Map<Long, Long> sortMap = new TreeMap<Long, Long>(new Comparator<Long>() {
+
+            public int compare(Long l1, Long l2) {
+                return l1.compareTo(l2);
+            }
+        });
+        sortMap.putAll(map);
+        return sortMap;
+    }
+
+    private Map<Long, Long> buildMap(List<Question> quesList, Map<Long, Long> map, int questionType) {
+        // 初始化map
+        for (int i = 1; i < 7; i++) {
+            if (i < 4) {
+                map.put((long) (questionType * 100 + i), 0L);
+            } else {
+                map.put((long) (questionType * 100 + 10 + i - 3), 0L);
+            }
+        }
+        for (Question question : quesList) {
+            if (question.getPublicity()) {
+                // 公开
+                if (question.getDifficulty() != null && question.getDifficulty().equals("难")
+                        || question.getDifficultyDegree() < 0.4 && question.getDifficultyDegree() > 0) {
+                    map = buildMapSum(questionType * 100L + 1L, map);
+                } else if (question.getDifficulty() != null && question.getDifficulty().equals("中")
+                        || question.getDifficultyDegree() < 0.8 && question.getDifficultyDegree() > 0.3) {
+                    map = buildMapSum(questionType * 100L + 2L, map);
+                } else {
+                    map = buildMapSum(questionType * 100L + 3L, map);
+                }
+            } else {
+                // 非公开
+                if (question.getDifficulty() != null && question.getDifficulty().equals("难")
+                        || question.getDifficultyDegree() < 0.4 && question.getDifficultyDegree() > 0) {
+                    map = buildMapSum(questionType * 100L + 11L, map);
+                } else if (question.getDifficulty() != null && question.getDifficulty().equals("中")
+                        || question.getDifficultyDegree() < 0.8 && question.getDifficultyDegree() > 0.3) {
+                    map = buildMapSum(questionType * 100L + 12L, map);
+                } else {
+                    map = buildMapSum(questionType * 100L + 13L, map);
+                }
+            }
+        }
+        return map;
+    }
+
+    private Map<Long, Long> buildMapSum(long key, Map<Long, Long> map) {
+        Long sum = map.get(key);
+        map.put(key, sum + 1);
+        return map;
+    }
+
+    public List<Question> questionList(String courseNo, CourseProperty courseProperty, QuesStructType quesStructType,
+            Property parentProperty, Property sonProperty) {
+        Query query = new Query();
+        query.addCriteria(Criteria.where("orgId").is(courseProperty.getOrgId().toString()));
+        query.addCriteria(Criteria.where("course.enable").is("true"));
+        query.addCriteria(Criteria.where("course.code").is(courseNo));
+        query.addCriteria(Criteria.where("questionType").is(quesStructType.name()));
+        query.addCriteria(Criteria.where("quesProperties.coursePropertyName").is(courseProperty.getName()));
+        // 二级属性不为空,那么一级属性也不为空
+        if (sonProperty != null && sonProperty.getId() != null) {
+            query.addCriteria(Criteria.where("quesProperties").elemMatch(Criteria.where("firstProperty.id")
+                    .is(parentProperty.getId()).and("secondProperty.id").is(sonProperty.getId())));
+        } else {
+            if (parentProperty != null && parentProperty.getId() != null) {
+                query.addCriteria(Criteria.where("quesProperties")
+                        .elemMatch(Criteria.where("firstProperty.id").is(parentProperty.getId())));
+            }
+        }
+        List<Question> questionList = this.mongoTemplate.find(query, Question.class);
+        return questionList;
+    }
+
+    public List<Question> questionList2(String courseNo, CourseProperty courseProperty, QuesStructType quesStructType,
+            Property parentProperty, Property sonProperty, List<Question> questions) {
+        List<Question> questionList = new ArrayList<>();
+        String id = courseNo + quesStructType.name() + courseProperty.getName();
+        // 二级属性不为空,那么一级属性也不为空
+        if (sonProperty != null && sonProperty.getId() != null) {
+            id = id + parentProperty.getId() + sonProperty.getId();
+        } else {
+            if (parentProperty != null && parentProperty.getId() != null) {
+                id = id + parentProperty.getId();
+            }
+        }
+        for (Question question : questions) {
+            List<String> idStrings = new ArrayList<>();
+            String id_Q = question.getCourseNo() + question.getQuestionType();
+            List<QuesProperty> quesProperties = question.getQuesProperties();
+            if (quesProperties != null && quesProperties.size() > 0) {
+                for (QuesProperty property : quesProperties) {
+                    String idP = id_Q + property.getCoursePropertyName() + property.getFirstProperty().getId();
+                    if (property.getSecondProperty() != null) {
+                        idP = id_Q + property.getCoursePropertyName() + property.getFirstProperty().getId()
+                                + property.getSecondProperty().getId();
+                    }
+                    idStrings.add(idP);
+                }
+                if (idStrings.contains(id)) {
+                    questionList.add(question);
+                }
+            }
+        }
+        return questionList;
+    }
+
+    @Override
+    public void downOriginalPaper(String paperId, String loginName, HttpServletResponse response) throws Exception {
+        // String zipFileName = loginName + System.currentTimeMillis() + "";
+        // try {
+        // // 生成导出的试卷对象
+        // PaperExp paperExp = paperService.getDownPaperExp(paperId);
+        // File directory = new File(TEMP_FILE_EXP + File.separator +
+        // zipFileName);
+        // if (!directory.exists()) {
+        // directory.mkdirs();
+        // }
+        // String paperfileName = paperExp.getName() + "_" +
+        // paperExp.getCourseNo() + "_"
+        // + ExamFileType.PAPER.getName() + DOCX_SUFFIX;
+        // File file = new File(TEMP_FILE_EXP + File.separator + zipFileName +
+        // File.separator + paperfileName);
+        // List<WordprocessingMLPackage> wordPackages = getPkgList(paperId);
+        // DocxProcessUtil.exportWordNew(paperExp, file,
+        // ExportPaperAbstractService.ORIGINAL_PAPER);
+        // DocxProcessUtil.processImage(zipFileName + File.separator +
+        // paperfileName, wordPackages);
+        // FileDisposeUtil.fileToZip(TEMP_FILE_EXP + File.separator +
+        // zipFileName, TEMP_FILE_EXP, zipFileName);
+        // FileDisposeUtil.downloadFile(paperExp.getName() + "_" +
+        // paperExp.getCourse().getCode() + ".zip",
+        // TEMP_FILE_EXP + File.separator + zipFileName + ".zip", response);
+        // } finally {
+        // deteleFolder(TEMP_FILE_EXP, zipFileName);
+        // }
+    }
+
+    /**
+     * 获取当前试卷下所有试题WordPkg
+     *
+     * @param id
+     * @return
+     */
+    // protected List<WordprocessingMLPackage> getPkgList(String id) {
+    // Paper paper = Model.of(paperRepo.findById(id));
+    // List<WordprocessingMLPackage> wordMLPackages =
+    // paperDetailUnitRepo.findByPaperOrderByNumber(paper).stream()
+    // .map(PaperDetailUnit::getQuestion).collect(Collectors.toList()).stream()
+    // .map(question -> getPkgObj(question)).collect(Collectors.toList());
+    // return wordMLPackages;
+    // }
+    //
+    // private WordprocessingMLPackage getPkgObj(Question question) {
+    // String pkgPathId = question.getQuesPkgPathId();
+    // QuestionPkgPath quesPkg = quesPkgPathRepo.findFirstById(pkgPathId);
+    // if (quesPkg == null) {
+    // byte[] bytes = new byte[0];
+    // return DocxProcessUtil.getPkg(bytes);
+    // }
+    // byte[] pkgByte = quesPkg.getQuesPkg();
+    // return DocxProcessUtil.getPkg(pkgByte);
+    // }
+
+    @Override
+    public void downQuestionDistributeByPapers(String paperIds, HttpServletResponse response) throws IOException {
+        List<QuestionDistributeDto> questionDistributes = new ArrayList<>();
+
+        // 定义课程集合
+        List<String> courseCodes = new ArrayList<>();
+
+        // 定义试题集合
+        List<Question> questions = new ArrayList<>();
+
+        // 查询试卷集合
+        String[] paperIdArray = paperIds.split(",");
+        for (int i = 0; i < paperIdArray.length; i++) {
+            Paper basePaper = Model.of(paperRepo.findById(paperIdArray[i]));
+            courseCodes.add(basePaper.getCourse().getCode());
+            // 将小题全部取出来,只取一次,减少对数据库的查询
+            List<PaperDetailUnit> allPaperDetailUnits = paperDetailUnitRepo.findByPaper(basePaper);
+            for (PaperDetailUnit unit : allPaperDetailUnits) {
+                if (unit.getQuestionType().equals(QuesStructType.SINGLE_ANSWER_QUESTION)
+                        || unit.getQuestionType().equals(QuesStructType.MULTIPLE_ANSWER_QUESTION)
+                        || unit.getQuestionType().equals(QuesStructType.BOOL_ANSWER_QUESTION)) {
+                    questions.add(unit.getQuestion());
+                }
+            }
+        }
+
+        // 根据课程code查询课程属性集合
+        for (String courseCode : courseCodes) {
+            List<CourseProperty> courseProperties = coursePropertyRepo.findByCourseCodeAndEnable(courseCode, true);
+            // 遍历课程属性集合,根据课程属性查询一级
+            if (courseProperties != null && courseProperties.size() > 0) {
+                for (CourseProperty courseProperty : courseProperties) {
+                    List<Property> parentProperties = propertyService.findParentProperties(courseProperty.getId(),
+                            courseProperty.getOrgId());
+                    if (parentProperties != null && parentProperties.size() > 0) {
+                        for (Property parentProperty : parentProperties) {
+                            List<Property> sonProperties = propertyService.findSonProperties(parentProperty.getId());
+                            if (sonProperties != null && sonProperties.size() > 0) {
+                                for (Property sonProperty : sonProperties) {
+                                    // 单选题集合
+                                    List<Question> sinList = questionList2(courseCode, courseProperty,
+                                            QuesStructType.SINGLE_ANSWER_QUESTION, parentProperty, sonProperty,
+                                            questions);
+                                    // 多选题集合
+                                    List<Question> mulList = questionList2(courseCode, courseProperty,
+                                            QuesStructType.MULTIPLE_ANSWER_QUESTION, parentProperty, sonProperty,
+                                            questions);
+                                    // 判断题集合
+                                    List<Question> bolList = questionList2(courseCode, courseProperty,
+                                            QuesStructType.BOOL_ANSWER_QUESTION, parentProperty, sonProperty,
+                                            questions);
+
+                                    List<Question> fillList = null;
+                                    // fillList = questionList2(courseNo,
+                                    // courseProperty,
+                                    // QuesStructType.FILL_BLANK_QUESTION,
+                                    // parentProperty, sonProperty, questions);
+                                    List<Question> textList = null;
+                                    // textList = questionList2(courseNo,
+                                    // courseProperty,
+                                    // QuesStructType.TEXT_ANSWER_QUESTION,
+                                    // parentProperty, sonProperty, questions);
+
+                                    // 计算所有题型数量
+                                    Map<Long, Long> map = countQuesType(sinList, mulList, bolList, fillList, textList);
+                                    QuestionDistributeDto questionDistributeDto = new QuestionDistributeDto(
+                                            courseProperty.getName(), parentProperty.getName(), sonProperty.getName(),
+                                            map);
+                                    questionDistributes.add(questionDistributeDto);
+                                }
+                            } else {
+                                // 一级属性不为空,二级属性为空
+                                // 单选题集合
+                                List<Question> sinList = questionList2(courseCode, courseProperty,
+                                        QuesStructType.SINGLE_ANSWER_QUESTION, parentProperty, null, questions);
+                                // 多选题集合
+                                List<Question> mulList = questionList2(courseCode, courseProperty,
+                                        QuesStructType.MULTIPLE_ANSWER_QUESTION, parentProperty, null, questions);
+                                // 判断题集合
+                                List<Question> bolList = questionList2(courseCode, courseProperty,
+                                        QuesStructType.BOOL_ANSWER_QUESTION, parentProperty, null, questions);
+
+                                List<Question> fillList = null;
+                                // fillList = questionList2(courseNo,
+                                // courseProperty,
+                                // QuesStructType.FILL_BLANK_QUESTION,
+                                // parentProperty, null, questions);
+                                List<Question> textList = null;
+                                // textList = questionList2(courseNo,
+                                // courseProperty,
+                                // QuesStructType.TEXT_ANSWER_QUESTION,
+                                // parentProperty, null, questions);
+
+                                // 计算所有题型数量
+                                Map<Long, Long> map = countQuesType(sinList, mulList, bolList, fillList, textList);
+                                QuestionDistributeDto questionDistributeDto = new QuestionDistributeDto(
+                                        courseProperty.getName(), parentProperty.getName(), null, map);
+                                questionDistributes.add(questionDistributeDto);
+                            }
+                        }
+                    } else {
+                        // 一级属性为空
+                        QuestionDistributeDto questionDistributeDto = new QuestionDistributeDto(
+                                courseProperty.getName(), null, null, null);
+                        questionDistributes.add(questionDistributeDto);
+                    }
+                }
+            }
+
+            final String fileName = System.currentTimeMillis() + "试题分布.xlsx";
+            final String filePath = TEMP_FILE_EXP + File.separator + fileName;
+
+            // 生成Excel导出
+            File tempFile = this.writeExcel(questionDistributes, filePath);
+            FileDisposeUtil.downloadFile(fileName, filePath, response);
+            FileUtils.deleteQuietly(tempFile);
+        }
+    }
+
+    @Override
+    public void downOriginalPaperPlus(String paperId, Long rootOrgId, HttpServletResponse response) throws IOException {
+        String zipFileName = IdUtils.uuid();
+        File directory = new File(TEMP_FILE_EXP + File.separator + zipFileName);
+        if (!directory.exists()) {
+            directory.mkdirs();
+        }
+        // doc固定源文件目录
+        // File docxDir = new File(JsonExportUtil.getDocxBasePath());
+        // // 将要生成的doc源文件目录
+        // File docxTargetDir = new File(directory.getAbsolutePath() +
+        // "/docx/");
+        // docxTargetDir.mkdir();
+        try {
+            // 复制docx基础文件
+            // FileUtils.copyDirectory(docxDir, docxTargetDir);
+            // 生成导出的试卷对象
+            PaperExp paperExp = paperService.getDownPaperExp(paperId);
+
+            PaperUtil.setQuestionSeq(paperExp.getPaperDetails(), PaperSeqMode.MODE4);
+            // // 处理并生成doc源文件
+            // dispose(docxTargetDir, paperExp);
+            // // 压缩docx源文件
+            // String paperfileName = paperExp.getName() + "_" +
+            // paperExp.getCourseNo() + "_"
+            // + ExamFileType.PAPER.getName();
+            // File zipfile = new
+            // File(docxTargetDir.getParentFile().getAbsolutePath() +
+            // File.separator + "data"
+            // + File.separator + paperfileName + ZIP_SUFFIX);
+            // zipfile.getParentFile().mkdir();
+            // File docfile = new
+            // File(docxTargetDir.getParentFile().getAbsolutePath() +
+            // File.separator + "data"
+            // + File.separator + File.separator + paperfileName + DOCX_SUFFIX);
+            // FileDisposeUtil.createZip(docxTargetDir.getAbsolutePath(),
+            // zipfile.getAbsolutePath());
+            // // 修改压缩包为doc文件
+            // zipfile.renameTo(docfile);
+            File docfile = ExportPaperUtil.createOriginPaperDocFile(paperExp, directory);
+            // doc文件加入下载包中
+            FileDisposeUtil.fileToZip(docfile.getParentFile().getAbsolutePath(), directory.getAbsolutePath(),
+                    zipFileName);
+            // 下载文件
+            FileDisposeUtil.downloadFile(paperExp.getName() + "_" + paperExp.getCourse().getCode() + ".zip",
+                    directory.getAbsolutePath() + File.separator + zipFileName + ".zip", response);
+        } finally {
+            FileUtils.deleteDirectory(directory);
+        }
+
+    }
+
+    // private void dispose(File docxTargetDir, PaperExp paperExp) throws
+    // IOException {
+    // ExportTempDataDto dto = new ExportTempDataDto();
+    // if (paperExp.getPaperDetails() != null &&
+    // paperExp.getPaperDetails().size() > 0) {
+    // for (PaperDetailExp pde : paperExp.getPaperDetails()) {
+    // dto.setMainNum(dto.getMainNum() + 1);
+    // dto.setSubNum(0);
+    // if (pde.getPaperDetailUnits() != null && pde.getPaperDetailUnits().size()
+    // > 0) {
+    // for (PaperDetailUnitExp pdue : pde.getPaperDetailUnits()) {
+    // Question qes = pdue.getQuestion();
+    // disposeQuestion(qes, dto);
+    // }
+    // }
+    // }
+    // }
+    // // content-type
+    // writeContentType(docxTargetDir, dto);
+    // // document
+    // writeDocument(docxTargetDir, paperExp);
+    // // document-rel
+    // writeDocumentRel(docxTargetDir, dto);
+    // // image file
+    // writeImage(docxTargetDir, dto);
+    // }
+    //
+    // private void writeImage(File docxTargetDir, ExportTempDataDto dto) throws
+    // IOException {
+    // for (SectionElement se : dto.getImages()) {
+    // File file = new File(docxTargetDir.getAbsolutePath() +
+    // "/word/media/image" + se.getParams().getIndex() + "."
+    // + se.getParams().getType());
+    // String base64 = se.getValue();
+    // if (base64.contains("data:image")) {
+    // base64 = base64.substring(base64.indexOf(",") + 1);
+    // }
+    // BASE64Decoder decoder = new BASE64Decoder();
+    // byte[] bytes = decoder.decodeBuffer(base64);
+    // FileUtils.writeByteArrayToFile(file, bytes);
+    // }
+    // }
+    //
+    // private void writeDocumentRel(File docxTargetDir, ExportTempDataDto dto)
+    // throws IOException {
+    // Map<String, Object> map = new HashMap<String, Object>();
+    // map.put("images", dto.getImages());
+    // String doc = JsonExportUtil.getDocumentRelDoc(map);
+    // File file = new File(docxTargetDir.getAbsolutePath() +
+    // "/word/_rels/document.xml.rels");
+    // FileUtils.writeStringToFile(file, doc, "utf-8");
+    // }
+    //
+    // private void writeContentType(File docxTargetDir, ExportTempDataDto dto)
+    // throws IOException {
+    // Map<String, Object> map = new HashMap<String, Object>();
+    // map.put("images", dto.getTypes());
+    // String doc = JsonExportUtil.getContentTypesDoc(map);
+    // File file = new File(docxTargetDir.getAbsolutePath() +
+    // "/[Content_Types].xml");
+    // FileUtils.writeStringToFile(file, doc, "utf-8");
+    // }
+    //
+    // private void writeDocument(File docxTargetDir, PaperExp paperExp) throws
+    // IOException {
+    // String doc = JsonExportUtil.getDocumentDoc(paperExp);
+    // File file = new File(docxTargetDir.getAbsolutePath() +
+    // "/word/document.xml");
+    // FileUtils.writeStringToFile(file, doc, "utf-8");
+    // }
+    //
+    // private void disposeQuestion(Question qes, ExportTempDataDto dto) {
+    // if (qes != null) {
+    // List<JSection> slist1 = JsonExportUtil.getSections(qes.getQuesBody());
+    // if (slist1 != null && slist1.size() > 0) {
+    // if (qes.getSubQuestions() == null || qes.getSubQuestions().size() == 0)
+    // {// 套题题干不加题号
+    // dto.setSubNum(dto.getSubNum() + 1);
+    // SectionElement se = new SectionElement();
+    // se.setType(JsonExportUtil.ELEMENT_TYPE_TEXT);
+    // se.setValue(dto.getSubNum() + ".");
+    // slist1.get(0).getElements().add(0, se);
+    // }
+    //
+    // htmlToDoc(slist1, dto);
+    // qes.setQuesBodyWord(getQuestionDoc(slist1));
+    // }
+    //
+    // if (qes.getQuesOptions() != null && qes.getQuesOptions().size() > 0) {
+    // int index = 0;
+    // for (QuesOption qo : qes.getQuesOptions()) {
+    // List<JSection> slist2 = JsonExportUtil.getSections(qo.getOptionBody());
+    // if (slist2 != null && slist2.size() > 0) {
+    // SectionElement se = new SectionElement();
+    // se.setType(JsonExportUtil.ELEMENT_TYPE_TEXT);
+    // se.setValue(JsonExportUtil.QUESOPS.charAt(index) + ".");
+    // index++;
+    // slist2.get(0).getElements().add(0, se);
+    // htmlToDoc(slist2, dto);
+    // qo.setOptionBodyWord(getQuestionDoc(slist2));
+    // }
+    //
+    // }
+    // }
+    // List<JSection> slist3 = JsonExportUtil.getSections(qes.getQuesAnswer());
+    // if (slist3 != null && slist3.size() > 0) {
+    // SectionElement se = new SectionElement();
+    // se.setType(JsonExportUtil.ELEMENT_TYPE_TEXT);
+    // se.setValue("[答案]:");
+    // slist3.get(0).getElements().add(0, se);
+    //
+    // htmlToDoc(slist3, dto);
+    // qes.setQuesAnswerWord(getQuestionDoc(slist3));
+    // }
+    //
+    // if (qes.getSubQuestions() != null && qes.getSubQuestions().size() > 0) {
+    // dto.setSubNum(0);
+    // for (Question sunqes : qes.getSubQuestions()) {
+    // disposeQuestion(sunqes, dto);// 递归处理套题
+    // }
+    // }
+    // }
+    // }
+    //
+    // private void htmlToDoc(List<JSection> slist, ExportTempDataDto dto) {
+    // for (JSection js : slist) {
+    // for (SectionElement se : js.getElements()) {
+    // if (JsonExportUtil.ELEMENT_TYPE_IMG.equals(se.getType())) {
+    // dto.setIndex(dto.getIndex() + 1);
+    // se.getParams().setIndex(dto.getIndex());
+    // se.getParams().setRid(JsonExportUtil.ELEMENT_TYPE_RID + dto.getIndex());
+    // se.getParams().setType(getImageType(se.getValue()));
+    // dto.getTypes().add(se.getParams().getType());
+    // dto.getImages().add(se);
+    // }
+    // }
+    // }
+    // }
+    //
+    // private String getImageType(String base64) {
+    // return base64.substring(11, base64.indexOf(";"));
+    // }
+    //
+    // private String getQuestionDoc(List<JSection> sections) {
+    // Map<String, Object> map = new HashMap<String, Object>();
+    // map.put("sections", sections);
+    // String doc = JsonExportUtil.getQuestionSectionDoc(map);
+    // return doc;
+    // }
 }

+ 857 - 834
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/impl/ExportThemisPaperServiceImpl.java

@@ -1,835 +1,858 @@
-package cn.com.qmth.examcloud.core.questions.service.impl;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import cn.com.qmth.examcloud.support.fss.FssFactory;
-import cn.com.qmth.examcloud.support.fss.FssHelper;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
-import org.jsoup.nodes.Node;
-import org.jsoup.nodes.TextNode;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import com.google.gson.Gson;
-import com.google.gson.JsonArray;
-
-import cn.com.qmth.examcloud.core.questions.base.CommonUtils;
-import cn.com.qmth.examcloud.core.questions.base.Model;
-import cn.com.qmth.examcloud.core.questions.base.converter.utils.FileUtil;
-import cn.com.qmth.examcloud.core.questions.base.question.enums.QuesStructType;
-import cn.com.qmth.examcloud.core.questions.dao.QuestionAudioRepo;
-import cn.com.qmth.examcloud.core.questions.dao.entity.Paper;
-import cn.com.qmth.examcloud.core.questions.dao.entity.PaperDetail;
-import cn.com.qmth.examcloud.core.questions.dao.entity.PaperDetailUnit;
-import cn.com.qmth.examcloud.core.questions.dao.entity.QuesOption;
-import cn.com.qmth.examcloud.core.questions.dao.entity.Question;
-import cn.com.qmth.examcloud.core.questions.dao.entity.QuestionAudio;
-import cn.com.qmth.examcloud.core.questions.service.ExportThemisPaperService;
-import cn.com.qmth.examcloud.core.questions.service.PaperDetailService;
-import cn.com.qmth.examcloud.core.questions.service.PaperService;
-import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisAnswer;
-import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisAnswerContent;
-import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisAnswerDetail;
-import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisBlock;
-import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisSubjectiveAnswer;
-import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisOption;
-import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisPaper;
-import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisPaperAndAnswer;
-import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisPaperDetail;
-import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisQuestion;
-import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisSection;
-import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisSections;
-
-@Service("exportThemisPaperService")
-public class ExportThemisPaperServiceImpl implements ExportThemisPaperService {
-
-	private static final Logger LOG = LoggerFactory.getLogger(ExportThemisPaperServiceImpl.class);
-
-	@Autowired
-	private PaperService paperService;
-
-	@Autowired
-	private PaperDetailService paperDetailService;
-
-	@Autowired
-	private QuestionAudioRepo questionAudioRepo;
-
-	@Override
-	public void downloadAudio(ThemisPaper pa, String paperDirectory) {
-		String attDirectory = paperDirectory + File.separator + "attachment" + File.separator;
-		File attDir = new File(attDirectory);
-		if (!attDir.exists()) {
-			attDir.mkdirs();
-		}
-		int count = 0;
-		// 取到所有大题
-		List<ThemisPaperDetail> details = pa.getDetails();
-		if (details != null && details.size() > 0) {
-			for (ThemisPaperDetail detail : details) {
-				// 取到所有小题集合
-				List<ThemisQuestion> questions = detail.getQuestions();
-				if (questions != null && questions.size() > 0) {
-					for (ThemisQuestion question : questions) {
-//						int bodyNum = 1;
-						// 取到题干
-						ThemisSections body = question.getBody();
-						List<ThemisSection> sections = body.getSections();
-						for (ThemisSection section : sections) {
-							List<ThemisBlock> blocks = section.getBlocks();
-							if (blocks != null && blocks.size() > 0) {
-								for (ThemisBlock block : blocks) {
-									if (block.getType().equals("audio")) {
-										String val=block.getValue().toString();
-										String id = val.substring(0, val.lastIndexOf("."));
-										QuestionAudio questionAudio = Model.of(questionAudioRepo.findById(id));
-										String audioFileName = questionAudio.getId() + "."
-												+ questionAudio.getFileSuffixes();
-										File file = new File(attDirectory + audioFileName);
-
-										String filePath = FssHelper.fixFilePath(questionAudio.getFileUrl());
-										FssFactory.getInstance().readFile(filePath, file);
-
-										count++;
-//										bodyNum++;
-									}
-								}
-							}
-						}
-						// 取到选项
-						List<ThemisOption> options = question.getOptions();
-						if (options != null && options.size() > 0) {
-							for (ThemisOption computerTestOption : options) {
-//								int optionNum = 1;
-								// 获取选项主体
-								ThemisSections optionBody = computerTestOption.getBody();
-								List<ThemisSection> optionSections = optionBody.getSections();
-								if (optionSections != null && optionSections.size() > 0) {
-									for (ThemisSection optionSection : optionSections) {
-										List<ThemisBlock> blocks = optionSection.getBlocks();
-										if (blocks != null && blocks.size() > 0) {
-											for (ThemisBlock block : blocks) {
-												if (block.getType().equals("audio")) {
-													String val=block.getValue().toString();
-													String id = val.substring(0, val.lastIndexOf("."));
-													QuestionAudio questionAudio = Model
-															.of(questionAudioRepo.findById(id));
-													String audioFileName = questionAudio.getId() + "."
-															+ questionAudio.getFileSuffixes();
-													File file = new File(attDirectory + audioFileName);
-
-													String filePath = FssHelper.fixFilePath(questionAudio.getFileUrl());
-													FssFactory.getInstance().readFile(filePath, file);
-
-													count++;
-//													optionNum++;
-												}
-											}
-										}
-									}
-								}
-							}
-						}
-					}
-				}
-			}
-		}
-		if (count == 0) {
-			FileUtil.deleteFolder(attDirectory);
-		}
-	}
-
-	@Override
-	public void makePaperAnswerToJsonFile(ThemisPaperAndAnswer pa, String jsonDirectoryPath) {
-		makeAnswerToJsonFile(pa.getAnswer(), jsonDirectoryPath);
-		makePaperToJsonFile(pa.getPaper(), jsonDirectoryPath);
-	}
-
-	@SuppressWarnings("deprecation")
-	private void makeAnswerToJsonFile(ThemisAnswer pa, String jsonDirectoryPath) {
-		// 创建新的JSON文件
-		File file = new File(jsonDirectoryPath + File.separator + "answer.json");
-		// 将对象转成 json对象
-		Gson gson = new Gson();
-		String strJSON = gson.toJson(pa);
-
-		strJSON = CommonUtils.replaceUnicodeStr(strJSON);
-		// 生成文件流写入JSON文件
-		FileOutputStream outputStream = null;
-		try {
-			outputStream = new FileOutputStream(file);
-			byte b[] = strJSON.getBytes("UTF-8");
-			outputStream.write(b);
-			outputStream.flush();
-		} catch (FileNotFoundException e) {
-			LOG.error(e.getMessage(), e);
-		} catch (IOException e) {
-			LOG.error(e.getMessage(), e);
-		} finally {
-			IOUtils.closeQuietly(outputStream);
-		}
-	}
-
-	@SuppressWarnings("deprecation")
-	private void makePaperToJsonFile(ThemisPaper pa, String jsonDirectoryPath) {
-		// 创建新的JSON文件
-		File file = new File(jsonDirectoryPath + File.separator + "paper.json");
-		// 将对象转成 json对象
-		Gson gson = new Gson();
-		String strJSON = gson.toJson(pa);
-
-		strJSON = CommonUtils.replaceUnicodeStr(strJSON);
-		// 生成文件流写入JSON文件
-		FileOutputStream outputStream = null;
-		try {
-			outputStream = new FileOutputStream(file);
-			byte b[] = strJSON.getBytes("UTF-8");
-			outputStream.write(b);
-			outputStream.flush();
-		} catch (FileNotFoundException e) {
-			LOG.error(e.getMessage(), e);
-		} catch (IOException e) {
-			LOG.error(e.getMessage(), e);
-		} finally {
-			IOUtils.closeQuietly(outputStream);
-		}
-	}
-
-	@Override
-	public ThemisPaperAndAnswer buildPaperAndAnswer(Paper paper) {
-		// 得到所有旧对象的大题对象
-		List<PaperDetail> paperDetails = paperService.findPaperDetailsById(paper.getId());
-		// 通过 paper 对象 ,生成新的 ComputerTestPaper 对象
-		ThemisPaper computerTestPaper = new ThemisPaper(paper, "");
-		ThemisAnswer themisAnswer = new ThemisAnswer();
-		List<ThemisPaperDetail> details = new ArrayList<>();
-		List<ThemisAnswerDetail> answerdetails = new ArrayList<>();
-		// 遍历所有旧大题对象,得到小题对象的集合
-		for (PaperDetail paperDetail : paperDetails) {
-			List<PaperDetailUnit> paperDetailUnits = paperDetailService.getUnitsByPaperDetailId(paperDetail.getId());
-			ThemisPaperDetail computerTestPaperDetail = new ThemisPaperDetail(paperDetail);
-			ThemisAnswerDetail answerDetail = new ThemisAnswerDetail(paperDetail);
-			List<ThemisQuestion> questions = new ArrayList<>();
-			List<ThemisAnswerContent> answers = new ArrayList<>();
-			// 遍历所有的小题对象
-			for (int i = 0; i < paperDetailUnits.size(); i++) {
-				PaperDetailUnit paperDetailUnit = paperDetailUnits.get(i);
-				// 根据旧的小题对象,生成新的小题对象
-				ThemisQuestion computerTestQuestion = new ThemisQuestion(paperDetailUnit);
-				ThemisAnswerContent themisAnswerContent = new ThemisAnswerContent(paperDetailUnit);
-				// 设置小题题号
-				computerTestQuestion.setNumber(i + 1);
-				themisAnswerContent.setNumber(i + 1);
-				// 得到小题题干
-				if(computerTestQuestion.getStructType()==4) {
-					computerTestQuestion.setBody(getFillBlankBody(paperDetailUnit.getQuestion().getQuesBody(), computerTestPaper));
-				}else if(computerTestQuestion.getStructType()==6){
-					computerTestQuestion.setBody(getNestedBody(paperDetailUnit.getQuestion().getQuesBody(), computerTestPaper));
-				}else {
-					computerTestQuestion.setBody(getBody(paperDetailUnit.getQuestion().getQuesBody(), computerTestPaper));
-				}
-				// 得到小题所有选项
-				computerTestQuestion.setOptions(getOption(paperDetailUnit.getQuestion(), computerTestPaper));
-				// 得到小题的答案
-				if (paperDetailUnit.getQuestionType() == QuesStructType.SINGLE_ANSWER_QUESTION
-						|| paperDetailUnit.getQuestionType() == QuesStructType.MULTIPLE_ANSWER_QUESTION) {
-					themisAnswerContent.setAnswer(getSelectAnswer(paperDetailUnit.getQuestion()));
-				} else if (paperDetailUnit.getQuestionType() == QuesStructType.BOOL_ANSWER_QUESTION) {
-					themisAnswerContent.setAnswer(getBoolAnswer(paperDetailUnit.getQuestion()));
-				} else if (paperDetailUnit.getQuestionType() == QuesStructType.FILL_BLANK_QUESTION) {
-					themisAnswerContent.setAnswer(getFillBlankAnswer(paperDetailUnit.getQuestion()));
-				} else {
-					themisAnswerContent
-							.setAnswer(getAnswer(paperDetailUnit.getQuestion().getQuesAnswer(), computerTestPaper));
-				}
-				// 查询小题中的 套题
-				List<Question> subQuestionsList = paperDetailUnit.getQuestion().getSubQuestions();
-				// 判断这个小题中是否有套题
-				if (subQuestionsList != null && subQuestionsList.size() > 0) {
-					List<ThemisQuestion> subQuestions = new ArrayList<>();
-					List<ThemisAnswerContent> subAnswers = new ArrayList<>();
-					// 遍历每个套题
-					for (int j = 0; j < subQuestionsList.size(); j++) {
-						Question subQuestion = subQuestionsList.get(j);
-						ThemisQuestion subcomputerTestQuestion = new ThemisQuestion(subQuestion);
-						subcomputerTestQuestion.setScore(paperDetailUnit.getSubScoreList().get(j));
-						ThemisAnswerContent subthemisAnswerContent = new ThemisAnswerContent(subQuestion);
-						// 设置套题中小题题号
-						subcomputerTestQuestion.setNumber(j + 1);
-						subthemisAnswerContent.setNumber(j + 1);
-						
-						if(subcomputerTestQuestion.getStructType()==4) {
-							subcomputerTestQuestion.setBody(getFillBlankBody(subQuestion.getQuesBody(), computerTestPaper));
-						}else if(computerTestQuestion.getStructType()==6){
-							subcomputerTestQuestion.setBody(getNestedBody(subQuestion.getQuesBody(), computerTestPaper));
-						}else {
-							subcomputerTestQuestion.setBody(getBody(subQuestion.getQuesBody(), computerTestPaper));
-						}
-						subcomputerTestQuestion.setOptions(getOption(subQuestion, computerTestPaper));
-						if (subQuestion.getQuestionType() == QuesStructType.SINGLE_ANSWER_QUESTION
-								|| subQuestion.getQuestionType() == QuesStructType.MULTIPLE_ANSWER_QUESTION) {
-							subthemisAnswerContent.setAnswer(getSelectAnswer(subQuestion));
-						} else if (subQuestion.getQuestionType() == QuesStructType.BOOL_ANSWER_QUESTION) {
-							subthemisAnswerContent.setAnswer(getBoolAnswer(subQuestion));
-						} else if (subQuestion.getQuestionType() == QuesStructType.FILL_BLANK_QUESTION) {
-							subthemisAnswerContent.setAnswer(getFillBlankAnswer(subQuestion));
-						} else {
-							subthemisAnswerContent.setAnswer(getAnswer(subQuestion.getQuesAnswer(), computerTestPaper));
-						}
-						subQuestions.add(subcomputerTestQuestion);
-						subAnswers.add(subthemisAnswerContent);
-					}
-					computerTestQuestion.setSubQuestions(subQuestions);
-					themisAnswerContent.setSubQuestions(subAnswers);
-				}
-				questions.add(computerTestQuestion);
-				answers.add(themisAnswerContent);
-			}
-			computerTestPaperDetail.setQuestions(questions);
-			answerDetail.setQuestions(answers);
-			// paperDetail中的题数(unitCount)可能不准确,这里以questions的实际size为准
-			computerTestPaperDetail.setQuestionCount(questions.size());
-			details.add(computerTestPaperDetail);
-			answerdetails.add(answerDetail);
-		}
-		computerTestPaper.setDetails(details);
-		themisAnswer.setDetails(answerdetails);
-
-		ThemisPaperAndAnswer ret = new ThemisPaperAndAnswer();
-		computerTestPaper.setId(null);
-		ret.setPaper(computerTestPaper);
-		ret.setAnswer(themisAnswer);
-		return ret;
-	}
-	private ThemisSections getBody(String str, ThemisPaper computerTestPaper) {
-		ThemisSections body = new ThemisSections();
-		List<ThemisSection> sections = new ArrayList<>();
-		// 得到小题题干或者答案行数
-		if (StringUtils.isBlank(str)) {
-			return body;
-		}
-		String[] questionRowStrings = str.split("</p>");
-		for (int i = 0; i < questionRowStrings.length; i++) {
-			List<ThemisBlock> blocks = disposeQuestionBodyOrOption(questionRowStrings[i], computerTestPaper);
-			if (blocks != null && blocks.size() > 0) {
-				ThemisSection section = new ThemisSection();
-				// 将小题题干拆分为Block集合
-				section.setBlocks(blocks);
-				sections.add(section);
-			}
-		}
-		body.setSections(sections);
-		return body;
-	}
-	private ThemisSections getFillBlankBody(String str, ThemisPaper computerTestPaper) {
-		ThemisSections body = new ThemisSections();
-		List<ThemisSection> sections = new ArrayList<>();
-		// 得到小题题干或者答案行数
-		if (StringUtils.isBlank(str)) {
-			return body;
-		}
-		String[] questionRowStrings = str.split("</p>");
-		for (int i = 0; i < questionRowStrings.length; i++) {
-			List<ThemisBlock> blocks = disposeFillBlankQuestionBody(questionRowStrings[i], computerTestPaper);
-			if (blocks != null && blocks.size() > 0) {
-				ThemisSection section = new ThemisSection();
-				// 将小题题干拆分为Block集合
-				section.setBlocks(blocks);
-				sections.add(section);
-			}
-		}
-		body.setSections(sections);
-		return body;
-	}
-	
-	private List<ThemisSubjectiveAnswer> getAnswer(String str, ThemisPaper computerTestPaper) {
-		List<ThemisSection> sections = new ArrayList<>();
-		// 得到小题题干或者答案行数
-		if (StringUtils.isBlank(str)) {
-			return null;
-		}
-		String[] questionRowStrings = str.split("</p>");
-		for (int i = 0; i < questionRowStrings.length; i++) {
-			List<ThemisBlock> blocks = disposeQuestionBodyOrOption(questionRowStrings[i], computerTestPaper);
-			if (blocks != null && blocks.size() > 0) {
-				ThemisSection section = new ThemisSection();
-				// 将小题题干拆分为Block集合
-				section.setBlocks(blocks);
-				sections.add(section);
-			}
-		}
-		List<ThemisSubjectiveAnswer> ans=new ArrayList<>();
-		ThemisSubjectiveAnswer an=new ThemisSubjectiveAnswer();
-		ans.add(an);
-		an.setIndex(1);
-		an.setSections(sections);
-		return ans;
-	}
-	private String changeCloze(String text) {
-		StringBuffer buffer = new StringBuffer();
-        String regex = "##(\\d)##";
-
-        Pattern pattern = Pattern.compile(regex);
-        Matcher matcher = pattern.matcher(text);
-        // 使用find()方法查找匹配项
-        while (matcher.find()) {
-        	matcher.appendReplacement(buffer, "__"+matcher.group(1)+"__");
-        }
-        //fixbug
-        matcher.appendTail(buffer);
-        return buffer.toString();
-	}
-	private ThemisSections getNestedBody(String str, ThemisPaper computerTestPaper) {
-		ThemisSections body = new ThemisSections();
-		List<ThemisSection> sections = new ArrayList<>();
-		// 得到小题题干或者答案行数
-		if (StringUtils.isBlank(str)) {
-			return body;
-		}
-		String[] questionRowStrings = str.split("</p>");
-		for (int i = 0; i < questionRowStrings.length; i++) {
-			List<ThemisBlock> blocks = disposeNestedQuestionBody(questionRowStrings[i], computerTestPaper);
-			if (blocks != null && blocks.size() > 0) {
-				ThemisSection section = new ThemisSection();
-				// 将小题题干拆分为Block集合
-				section.setBlocks(blocks);
-				sections.add(section);
-			}
-		}
-		body.setSections(sections);
-		return body;
-	}
-	private List<ThemisBlock> disposeNestedQuestionBody(String questionRow, ThemisPaper computerTestPaper) {
-		List<ThemisBlock> blocks = new ArrayList<>();
-		// 去掉每行里面的<p>,<span>,</span>标签
-		questionRow = questionRow.replaceAll("<p>", "").replaceAll("</p>", "").replaceAll("<span>", "")
-				.replaceAll("</span>", "").replaceAll("</a>", "");
-		String[] questionRowStrings = questionRow.split("<|/>|>");
-		boolean hasAudio = false;
-		for (int i = 0; i < questionRowStrings.length; i++) {
-			ThemisBlock block = new ThemisBlock();
-			String rowStr = questionRowStrings[i];
-			// 判断是否有图片
-			if (rowStr.startsWith("img")) {
-				rowStr = "<" + rowStr + ">";
-				Map<String, Object> param = new HashMap<>();
-				// 需要继续做截取,取到Parma
-				block.setType("image");
-				// 获取图片的路径
-				List<String> strSrcList = getImg(rowStr, "src");
-				if (strSrcList.size() > 0) {
-					String strSrc = strSrcList.get(0).replaceAll("src=\"", "").replaceAll("\"", "");
-					block.setValue(strSrc);
-				}
-				// 获取图片的高度
-				List<String> strHeightList = getImg(rowStr, "height");
-				if (strHeightList.size() > 0) {
-					String strHeight = strHeightList.get(0).replaceAll("height=\"", "").replaceAll("\"", "");
-					Integer px=getIntFromString(strHeight);
-					if(px!=null) {
-						param.put("height", px);
-					}
-				}
-				// 获取图片的宽度
-				List<String> strWidthList = getImg(rowStr, "width");
-				if (strHeightList.size() > 0) {
-					String strWidth = strWidthList.get(0).replaceAll("width=\"", "").replaceAll("\"", "");
-					Integer px=getIntFromString(strWidth);
-					if(px!=null) {
-						param.put("width", px);
-					}
-				}
-				block.setParam(param);
-				blocks.add(block);
-			} else if (rowStr.startsWith("a") && rowStr.contains("id") && rowStr.contains("name")) { // 处理音频
-				rowStr = "<" + rowStr + ">";
-				block.setType("audio");
-				String id=CommonUtils.getAttrValue(rowStr, "id");
-				QuestionAudio questionAudio = Model.of(questionAudioRepo.findById(id));
-				block.setValue(questionAudio.getId() + "."+ questionAudio.getFileSuffixes());
-				blocks.add(block);
-				hasAudio = true;
-			} else {
-				block.setType("text");
-				rowStr = rowStr.replace("&nbsp;", "");// 消除空格
-				rowStr = rowStr.replace("&quot;", "\"");// 将&quot;转换成\"
-				rowStr = rowStr.replace("&lt;", "<");// 将&lt;转换成<
-				rowStr = rowStr.replace("&gt;", ">");// 将&gt;转换成>
-				rowStr = rowStr.replace("&amp;", "&");// 将&amp;转换成&
-				if (StringUtils.isNotBlank(rowStr)) {
-					block.setValue(changeCloze(rowStr));
-					blocks.add(block);
-				}
-			}
-		}
-		if (hasAudio) {
-			computerTestPaper.setHasAudio(hasAudio);
-		}
-		return blocks;
-	}
-	
-	private List<ThemisBlock> disposeFillBlankQuestionBody(String questionRow, ThemisPaper computerTestPaper) {
-		List<ThemisBlock> blocks = new ArrayList<>();
-		// 去掉每行里面的<p>,<span>,</span>标签
-		questionRow = questionRow.replaceAll("<p>", "").replaceAll("</p>", "").replaceAll("<span>", "")
-				.replaceAll("</span>", "").replaceAll("</a>", "");
-		String[] questionRowStrings = questionRow.split("<|/>|>");
-		boolean hasAudio = false;
-		int blankIndex=0;
-		for (int i = 0; i < questionRowStrings.length; i++) {
-			ThemisBlock block = new ThemisBlock();
-			String rowStr = questionRowStrings[i];
-			// 判断是否有图片
-			if (rowStr.startsWith("img")) {
-				rowStr = "<" + rowStr + ">";
-				Map<String, Object> param = new HashMap<>();
-				// 需要继续做截取,取到Parma
-				block.setType("image");
-				// 获取图片的路径
-				List<String> strSrcList = getImg(rowStr, "src");
-				if (strSrcList.size() > 0) {
-					String strSrc = strSrcList.get(0).replaceAll("src=\"", "").replaceAll("\"", "");
-					block.setValue(strSrc);
-				}
-				// 获取图片的高度
-				List<String> strHeightList = getImg(rowStr, "height");
-				if (strHeightList.size() > 0) {
-					String strHeight = strHeightList.get(0).replaceAll("height=\"", "").replaceAll("\"", "");
-					Integer px=getIntFromString(strHeight);
-					if(px!=null) {
-						param.put("height", px);
-					}
-				}
-				// 获取图片的宽度
-				List<String> strWidthList = getImg(rowStr, "width");
-				if (strHeightList.size() > 0) {
-					String strWidth = strWidthList.get(0).replaceAll("width=\"", "").replaceAll("\"", "");
-					Integer px=getIntFromString(strWidth);
-					if(px!=null) {
-						param.put("width", px);
-					}
-				}
-				block.setParam(param);
-				blocks.add(block);
-			} else if (rowStr.startsWith("a") && rowStr.contains("id") && rowStr.contains("name")) { // 处理音频
-				rowStr = "<" + rowStr + ">";
-				block.setType("audio");
-				String id=CommonUtils.getAttrValue(rowStr, "id");
-				QuestionAudio questionAudio = Model.of(questionAudioRepo.findById(id));
-				block.setValue(questionAudio.getId() + "."+ questionAudio.getFileSuffixes());
-				blocks.add(block);
-				hasAudio = true;
-			} else {
-				rowStr = rowStr.replace("&nbsp;", "");// 消除空格
-				rowStr = rowStr.replace("&quot;", "\"");// 将&quot;转换成\"
-				rowStr = rowStr.replace("&lt;", "<");// 将&lt;转换成<
-				rowStr = rowStr.replace("&gt;", ">");// 将&gt;转换成>
-				rowStr = rowStr.replace("&amp;", "&");// 将&amp;转换成&
-		        
-				String regex = "###";
-
-		        Pattern pattern = Pattern.compile(regex);
-		        Matcher matcher = pattern.matcher(rowStr);
-		        int indexStart=0;
-		        // 使用find()方法查找匹配项
-		        while (matcher.find()) {
-		        	blankIndex++;
-		            String content=rowStr.substring(indexStart, matcher.start());
-		            if(StringUtils.isNotEmpty(content)) {
-		            	ThemisBlock temblock = new ThemisBlock();
-			            temblock.setType("text");
-			            temblock.setValue(content);
-						blocks.add(temblock);
-		            }
-		            ThemisBlock blankblock = new ThemisBlock();
-		            blankblock.setType("cloze");
-		            blankblock.setValue(blankIndex);
-		            blocks.add(blankblock);
-		            indexStart=matcher.start()+regex.length();
-		        }
-		        if(indexStart<rowStr.length()) {
-		        	// 输出最后一个分隔符之后的字符串
-			        String content=rowStr.substring(indexStart, rowStr.length());
-		            if(StringUtils.isNotEmpty(content)) {
-		            	ThemisBlock temblock = new ThemisBlock();
-			            temblock.setType("text");
-			            temblock.setValue(content);
-						blocks.add(temblock);
-		            }
-		        }
-			}
-		}
-		if (hasAudio) {
-			computerTestPaper.setHasAudio(hasAudio);
-		}
-		return blocks;
-	}
-	
-	private Integer getIntFromString(String s) {
-		if(StringUtils.isBlank(s)) {
-			return null;
-		}
-		s=s.trim();
-		s=s.replace("px", "");
-		try {
-			Integer i=Integer.valueOf(s);
-			return i;
-		} catch (NumberFormatException e) {
-			return null;
-		}
-	}
-	
-
-	private List<ThemisBlock> disposeQuestionBodyOrOption(String questionRow, ThemisPaper computerTestPaper) {
-		List<ThemisBlock> blocks = new ArrayList<>();
-		// 去掉每行里面的<p>,<span>,</span>标签
-		questionRow = questionRow.replaceAll("<p>", "").replaceAll("</p>", "").replaceAll("<span>", "")
-				.replaceAll("</span>", "").replaceAll("</a>", "");
-		String[] questionRowStrings = questionRow.split("<|/>|>");
-		boolean hasAudio = false;
-		for (int i = 0; i < questionRowStrings.length; i++) {
-			ThemisBlock block = new ThemisBlock();
-			String rowStr = questionRowStrings[i];
-			// 判断是否有图片
-			if (rowStr.startsWith("img")) {
-				rowStr = "<" + rowStr + ">";
-				Map<String, Object> param = new HashMap<>();
-				// 需要继续做截取,取到Parma
-				block.setType("image");
-				// 获取图片的路径
-				List<String> strSrcList = getImg(rowStr, "src");
-				if (strSrcList.size() > 0) {
-					String strSrc = strSrcList.get(0).replaceAll("src=\"", "").replaceAll("\"", "");
-					block.setValue(strSrc);
-				}
-				// 获取图片的高度
-				List<String> strHeightList = getImg(rowStr, "height");
-				if (strHeightList.size() > 0) {
-					String strHeight = strHeightList.get(0).replaceAll("height=\"", "").replaceAll("\"", "");
-					Integer px=getIntFromString(strHeight);
-					if(px!=null) {
-						param.put("height", px);
-					}
-				}
-				// 获取图片的宽度
-				List<String> strWidthList = getImg(rowStr, "width");
-				if (strHeightList.size() > 0) {
-					String strWidth = strWidthList.get(0).replaceAll("width=\"", "").replaceAll("\"", "");
-					Integer px=getIntFromString(strWidth);
-					if(px!=null) {
-						param.put("width", px);
-					}
-				}
-				block.setParam(param);
-				blocks.add(block);
-			} else if (rowStr.startsWith("a") && rowStr.contains("id") && rowStr.contains("name")) { // 处理音频
-				rowStr = "<" + rowStr + ">";
-				block.setType("audio");
-				String id=CommonUtils.getAttrValue(rowStr, "id");
-				QuestionAudio questionAudio = Model.of(questionAudioRepo.findById(id));
-				block.setValue(questionAudio.getId() + "."+ questionAudio.getFileSuffixes());
-				blocks.add(block);
-				hasAudio = true;
-			} else {
-				block.setType("text");
-				rowStr = rowStr.replace("&nbsp;", "");// 消除空格
-				rowStr = rowStr.replace("&quot;", "\"");// 将&quot;转换成\"
-				rowStr = rowStr.replace("&lt;", "<");// 将&lt;转换成<
-				rowStr = rowStr.replace("&gt;", ">");// 将&gt;转换成>
-				rowStr = rowStr.replace("&amp;", "&");// 将&amp;转换成&
-				if (StringUtils.isNotBlank(rowStr)) {
-					block.setValue(rowStr);
-					blocks.add(block);
-				}
-			}
-		}
-		if (hasAudio) {
-			computerTestPaper.setHasAudio(hasAudio);
-		}
-		return blocks;
-	}
-
-	/**
-	 * 获取图片里面的路径,长度,宽度
-	 */
-	private List<String> getImg(String s, String str) {
-		String regex;
-		List<String> list = new ArrayList<>();
-		regex = str + "=\"(.*?)\"";
-		Pattern pa = Pattern.compile(regex, Pattern.DOTALL);
-		Matcher ma = pa.matcher(s);
-		while (ma.find()) {
-			list.add(ma.group());
-		}
-		return list;
-	}
-
-	private List<ThemisOption> getOption(Question question, ThemisPaper computerTestPaper) {
-		// 得到小题选项
-		List<QuesOption> quesOptions = question.getQuesOptions();
-		List<ThemisOption> options = new ArrayList<>();
-		// 遍历小题选项
-		if (quesOptions != null && quesOptions.size() > 0) {
-			for (QuesOption quesOption : quesOptions) {
-				ThemisOption option = new ThemisOption();
-				option.setNumber(new Integer(quesOption.getNumber()));
-				ThemisSections body = new ThemisSections();
-
-				List<ThemisSection> sections = new ArrayList<>();
-				// 得到小题选项
-				String optionString = quesOption.getOptionBody();
-				String[] optionStrings = optionString.split("</p>");
-				for (int i = 0; i < optionStrings.length; i++) {
-					List<ThemisBlock> blocks = disposeQuestionBodyOrOption(optionStrings[i], computerTestPaper);
-					if (blocks != null && blocks.size() > 0) {
-						ThemisSection section = new ThemisSection();
-						section.setBlocks(blocks);
-						sections.add(section);
-					}
-				}
-				body.setSections(sections);
-				option.setBody(body);
-				options.add(option);
-			}
-		}
-		return options;
-	}
-
-	private JsonArray getSelectAnswer(Question question) {
-		// 得到小题选项
-		List<QuesOption> quesOptions = question.getQuesOptions();
-		int index = 0;
-		// 遍历小题选项
-		if (quesOptions != null && quesOptions.size() > 0) {
-			JsonArray ja = new JsonArray();
-			for (QuesOption quesOption : quesOptions) {
-				index++;
-				if (quesOption.getIsCorrect() == 1) {
-					ja.add(index);
-				}
-			}
-			if (ja.size() > 0) {
-				return ja;
-			} else {
-				return null;
-			}
-		}
-		return null;
-	}
-
-	private Boolean getBoolAnswer(Question question) {
-		String as = question.getQuesAnswer();
-		if (StringUtils.isBlank(as)) {
-			return null;
-		}
-		if (as.contains("正确")) {
-			return true;
-		} else {
-			return false;
-		}
-	}
-
-	private void getSectionElement(Node ce, StringBuilder sb) {
-		if (("span".equals(ce.nodeName()) || "p".equals(ce.nodeName())) && ce.childNodeSize() > 0) {
-			for (Node e : ce.childNodes()) {
-				getSectionElement(e, sb);
-			}
-		} else {
-			if (ce instanceof TextNode) {
-				TextNode tn = (TextNode) ce;
-				String text = tn.text();
-				sb.append(text);
-			} else if (ce instanceof Element) {
-				if ("img".equals(ce.nodeName())) {
-					Element el = (Element) ce;
-					sb.append(el.outerHtml());
-				} else {
-					Element el = (Element) ce;
-					sb.append(el.text());
-				}
-			}
-		}
-	}
-
-	private List<ThemisSubjectiveAnswer> getFillBlankAnswer(Question question) {
-		String html = question.getQuesAnswer();
-		if (StringUtils.isBlank(html)) {
-			return null;
-		}
-		StringBuilder sb = new StringBuilder();
-		Document doc = Jsoup.parse(html);
-		Element b = doc.body();
-		for (Node ce : b.childNodes()) {
-			getSectionElement(ce, sb);
-		}
-
-		if (StringUtils.isBlank(sb.toString())) {
-			return null;
-		}
-		List<ThemisSubjectiveAnswer> tas = new ArrayList<>();
-		String[] sbs = sb.toString().split("##");
-		int index = 0;
-		for (String an : sbs) {
-			index++;
-			ThemisSubjectiveAnswer ta = new ThemisSubjectiveAnswer();
-			ta.setIndex(index);
-			List<ThemisSection> sections = new ArrayList<>();
-			ThemisSection sec = new ThemisSection();
-			List<ThemisBlock> blocks = new ArrayList<>();
-			Document subdoc = Jsoup.parse(an);
-			for (Node ce : subdoc.body().childNodes()) {
-				ThemisBlock block = new ThemisBlock();
-				if (ce instanceof TextNode) {
-					TextNode tn = (TextNode) ce;
-					String text = tn.text();
-					block.setType("text");
-					block.setValue(text);
-				} else if (ce instanceof Element) {
-					if ("img".equals(ce.nodeName())) {
-						Element el = (Element) ce;
-						block.setType("image");
-						block.setValue(el.attr("src"));
-						String h = el.attr("height");
-						String w = el.attr("width");
-						if (StringUtils.isNotBlank(w) && StringUtils.isNotBlank(h)) {
-							Map<String, Object> param = new HashMap<String, Object>();
-							Integer hpx=getIntFromString(h);
-							if(hpx!=null) {
-								param.put("height", hpx);
-							}
-							Integer wpx=getIntFromString(w);
-							if(wpx!=null) {
-								param.put("width", wpx);
-							}
-							block.setParam(param);
-						}
-					} else {
-						Element el = (Element) ce;
-						block.setType("text");
-						block.setValue(el.text());
-					}
-				}
-				blocks.add(block);
-			}
-			sec.setBlocks(blocks);
-			sections.add(sec);
-			ta.setSections(sections);
-			tas.add(ta);
-		}
-		return tas;
-	}
+package cn.com.qmth.examcloud.core.questions.service.impl;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import cn.com.qmth.examcloud.support.fss.FssFactory;
+import cn.com.qmth.examcloud.support.fss.FssHelper;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.nodes.Node;
+import org.jsoup.nodes.TextNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.core.questions.base.CommonUtils;
+import cn.com.qmth.examcloud.core.questions.base.Model;
+import cn.com.qmth.examcloud.core.questions.base.converter.utils.FileUtil;
+import cn.com.qmth.examcloud.core.questions.base.question.enums.QuesStructType;
+import cn.com.qmth.examcloud.core.questions.dao.QuestionAudioRepo;
+import cn.com.qmth.examcloud.core.questions.dao.entity.Paper;
+import cn.com.qmth.examcloud.core.questions.dao.entity.PaperDetail;
+import cn.com.qmth.examcloud.core.questions.dao.entity.PaperDetailUnit;
+import cn.com.qmth.examcloud.core.questions.dao.entity.QuesOption;
+import cn.com.qmth.examcloud.core.questions.dao.entity.Question;
+import cn.com.qmth.examcloud.core.questions.dao.entity.QuestionAudio;
+import cn.com.qmth.examcloud.core.questions.service.ExportThemisPaperService;
+import cn.com.qmth.examcloud.core.questions.service.PaperDetailService;
+import cn.com.qmth.examcloud.core.questions.service.PaperService;
+import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisAnswer;
+import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisAnswerContent;
+import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisAnswerDetail;
+import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisBlock;
+import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisSubjectiveAnswer;
+import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisOption;
+import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisPaper;
+import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisPaperAndAnswer;
+import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisPaperDetail;
+import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisQuestion;
+import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisSection;
+import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisSections;
+
+@Service("exportThemisPaperService")
+public class ExportThemisPaperServiceImpl implements ExportThemisPaperService {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ExportThemisPaperServiceImpl.class);
+
+    @Autowired
+    private PaperService paperService;
+
+    @Autowired
+    private PaperDetailService paperDetailService;
+
+    @Autowired
+    private QuestionAudioRepo questionAudioRepo;
+
+    @Override
+    public void downloadAudio(ThemisPaper pa, String paperDirectory) {
+        String attDirectory = paperDirectory + File.separator + "attachment" + File.separator;
+        File attDir = new File(attDirectory);
+        if (!attDir.exists()) {
+            attDir.mkdirs();
+        }
+        int count = 0;
+        // 取到所有大题
+        List<ThemisPaperDetail> details = pa.getDetails();
+        if (details != null && details.size() > 0) {
+            for (ThemisPaperDetail detail : details) {
+                // 取到所有小题集合
+                List<ThemisQuestion> questions = detail.getQuestions();
+                if (questions != null && questions.size() > 0) {
+                    for (ThemisQuestion question : questions) {
+                        // int bodyNum = 1;
+                        // 取到题干
+                        ThemisSections body = question.getBody();
+                        List<ThemisSection> sections = body.getSections();
+                        for (ThemisSection section : sections) {
+                            List<ThemisBlock> blocks = section.getBlocks();
+                            if (blocks != null && blocks.size() > 0) {
+                                for (ThemisBlock block : blocks) {
+                                    if (block.getType().equals("audio")) {
+                                        String val = block.getValue().toString();
+                                        String id = val.substring(0, val.lastIndexOf("."));
+                                        QuestionAudio questionAudio = Model.of(questionAudioRepo.findById(id));
+                                        String audioFileName = questionAudio.getId() + "."
+                                                + questionAudio.getFileSuffixes();
+                                        File file = new File(attDirectory + audioFileName);
+
+                                        String filePath = FssHelper.fixFilePath(questionAudio.getFileUrl());
+                                        FssFactory.getInstance().readFile(filePath, file);
+
+                                        count++;
+                                        // bodyNum++;
+                                    }
+                                }
+                            }
+                        }
+                        // 取到选项
+                        List<ThemisOption> options = question.getOptions();
+                        if (options != null && options.size() > 0) {
+                            for (ThemisOption computerTestOption : options) {
+                                // int optionNum = 1;
+                                // 获取选项主体
+                                ThemisSections optionBody = computerTestOption.getBody();
+                                List<ThemisSection> optionSections = optionBody.getSections();
+                                if (optionSections != null && optionSections.size() > 0) {
+                                    for (ThemisSection optionSection : optionSections) {
+                                        List<ThemisBlock> blocks = optionSection.getBlocks();
+                                        if (blocks != null && blocks.size() > 0) {
+                                            for (ThemisBlock block : blocks) {
+                                                if (block.getType().equals("audio")) {
+                                                    String val = block.getValue().toString();
+                                                    String id = val.substring(0, val.lastIndexOf("."));
+                                                    QuestionAudio questionAudio = Model
+                                                            .of(questionAudioRepo.findById(id));
+                                                    String audioFileName = questionAudio.getId() + "."
+                                                            + questionAudio.getFileSuffixes();
+                                                    File file = new File(attDirectory + audioFileName);
+
+                                                    String filePath = FssHelper.fixFilePath(questionAudio.getFileUrl());
+                                                    FssFactory.getInstance().readFile(filePath, file);
+
+                                                    count++;
+                                                    // optionNum++;
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if (count == 0) {
+            FileUtil.deleteFolder(attDirectory);
+        }
+    }
+
+    @Override
+    public void makePaperAnswerToJsonFile(ThemisPaperAndAnswer pa, String jsonDirectoryPath) {
+        makeAnswerToJsonFile(pa.getAnswer(), jsonDirectoryPath);
+        makePaperToJsonFile(pa.getPaper(), jsonDirectoryPath);
+    }
+
+    @SuppressWarnings("deprecation")
+    private void makeAnswerToJsonFile(ThemisAnswer pa, String jsonDirectoryPath) {
+        // 创建新的JSON文件
+        File file = new File(jsonDirectoryPath + File.separator + "answer.json");
+        // 将对象转成 json对象
+        Gson gson = new Gson();
+        String strJSON = gson.toJson(pa);
+
+        strJSON = CommonUtils.replaceUnicodeStr(strJSON);
+        // 生成文件流写入JSON文件
+        FileOutputStream outputStream = null;
+        try {
+            outputStream = new FileOutputStream(file);
+            byte b[] = strJSON.getBytes("UTF-8");
+            outputStream.write(b);
+            outputStream.flush();
+        } catch (FileNotFoundException e) {
+            LOG.error(e.getMessage(), e);
+        } catch (IOException e) {
+            LOG.error(e.getMessage(), e);
+        } finally {
+            IOUtils.closeQuietly(outputStream);
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    private void makePaperToJsonFile(ThemisPaper pa, String jsonDirectoryPath) {
+        // 创建新的JSON文件
+        File file = new File(jsonDirectoryPath + File.separator + "paper.json");
+        // 将对象转成 json对象
+        Gson gson = new Gson();
+        String strJSON = gson.toJson(pa);
+
+        strJSON = CommonUtils.replaceUnicodeStr(strJSON);
+        // 生成文件流写入JSON文件
+        FileOutputStream outputStream = null;
+        try {
+            outputStream = new FileOutputStream(file);
+            byte b[] = strJSON.getBytes("UTF-8");
+            outputStream.write(b);
+            outputStream.flush();
+        } catch (FileNotFoundException e) {
+            LOG.error(e.getMessage(), e);
+        } catch (IOException e) {
+            LOG.error(e.getMessage(), e);
+        } finally {
+            IOUtils.closeQuietly(outputStream);
+        }
+    }
+
+    @Override
+    public ThemisPaperAndAnswer buildPaperAndAnswer(Paper paper) {
+        // 得到所有旧对象的大题对象
+        List<PaperDetail> paperDetails = paperService.findPaperDetailsById(paper.getId());
+        // 通过 paper 对象 ,生成新的 ComputerTestPaper 对象
+        ThemisPaper computerTestPaper = new ThemisPaper(paper, "");
+        ThemisAnswer themisAnswer = new ThemisAnswer();
+        List<ThemisPaperDetail> details = new ArrayList<>();
+        List<ThemisAnswerDetail> answerdetails = new ArrayList<>();
+        // 遍历所有旧大题对象,得到小题对象的集合
+        for (PaperDetail paperDetail : paperDetails) {
+            List<PaperDetailUnit> paperDetailUnits = paperDetailService.getUnitsByPaperDetailId(paperDetail.getId());
+            ThemisPaperDetail computerTestPaperDetail = new ThemisPaperDetail(paperDetail);
+            ThemisAnswerDetail answerDetail = new ThemisAnswerDetail(paperDetail);
+            List<ThemisQuestion> questions = new ArrayList<>();
+            List<ThemisAnswerContent> answers = new ArrayList<>();
+            // 遍历所有的小题对象
+            for (int i = 0; i < paperDetailUnits.size(); i++) {
+                PaperDetailUnit paperDetailUnit = paperDetailUnits.get(i);
+                try {
+                    // 根据旧的小题对象,生成新的小题对象
+                    ThemisQuestion computerTestQuestion = new ThemisQuestion(paperDetailUnit);
+                    ThemisAnswerContent themisAnswerContent = new ThemisAnswerContent(paperDetailUnit);
+                    // 设置小题题号
+                    computerTestQuestion.setNumber(i + 1);
+                    themisAnswerContent.setNumber(i + 1);
+                    // 得到小题题干
+                    if (computerTestQuestion.getStructType() == 4) {
+                        computerTestQuestion.setBody(
+                                getFillBlankBody(paperDetailUnit.getQuestion().getQuesBody(), computerTestPaper));
+                    } else if (computerTestQuestion.getStructType() == 6) {
+                        computerTestQuestion
+                                .setBody(getNestedBody(paperDetailUnit.getQuestion().getQuesBody(), computerTestPaper));
+                    } else {
+                        computerTestQuestion
+                                .setBody(getBody(paperDetailUnit.getQuestion().getQuesBody(), computerTestPaper));
+                    }
+                    // 得到小题所有选项
+                    computerTestQuestion.setOptions(getOption(paperDetailUnit.getQuestion(), computerTestPaper));
+                    // 得到小题的答案
+                    if (paperDetailUnit.getQuestionType() == QuesStructType.SINGLE_ANSWER_QUESTION
+                            || paperDetailUnit.getQuestionType() == QuesStructType.MULTIPLE_ANSWER_QUESTION) {
+                        themisAnswerContent.setAnswer(getSelectAnswer(paperDetailUnit.getQuestion()));
+                    } else if (paperDetailUnit.getQuestionType() == QuesStructType.BOOL_ANSWER_QUESTION) {
+                        themisAnswerContent.setAnswer(getBoolAnswer(paperDetailUnit.getQuestion()));
+                    } else if (paperDetailUnit.getQuestionType() == QuesStructType.FILL_BLANK_QUESTION) {
+                        themisAnswerContent.setAnswer(getFillBlankAnswer(paperDetailUnit.getQuestion()));
+                    } else {
+                        themisAnswerContent
+                                .setAnswer(getAnswer(paperDetailUnit.getQuestion().getQuesAnswer(), computerTestPaper));
+                    }
+                    // 查询小题中的 套题
+                    List<Question> subQuestionsList = paperDetailUnit.getQuestion().getSubQuestions();
+                    // 判断这个小题中是否有套题
+                    if (subQuestionsList != null && subQuestionsList.size() > 0) {
+                        List<ThemisQuestion> subQuestions = new ArrayList<>();
+                        List<ThemisAnswerContent> subAnswers = new ArrayList<>();
+                        // 遍历每个套题
+                        for (int j = 0; j < subQuestionsList.size(); j++) {
+                            Question subQuestion = subQuestionsList.get(j);
+                            ThemisQuestion subcomputerTestQuestion = new ThemisQuestion(subQuestion);
+                            subcomputerTestQuestion.setScore(paperDetailUnit.getSubScoreList().get(j));
+                            ThemisAnswerContent subthemisAnswerContent = new ThemisAnswerContent(subQuestion);
+                            // 设置套题中小题题号
+                            subcomputerTestQuestion.setNumber(j + 1);
+                            subthemisAnswerContent.setNumber(j + 1);
+
+                            if (subcomputerTestQuestion.getStructType() == 4) {
+                                subcomputerTestQuestion
+                                        .setBody(getFillBlankBody(subQuestion.getQuesBody(), computerTestPaper));
+                            } else if (computerTestQuestion.getStructType() == 6) {
+                                subcomputerTestQuestion
+                                        .setBody(getNestedBody(subQuestion.getQuesBody(), computerTestPaper));
+                            } else {
+                                subcomputerTestQuestion.setBody(getBody(subQuestion.getQuesBody(), computerTestPaper));
+                            }
+                            subcomputerTestQuestion.setOptions(getOption(subQuestion, computerTestPaper));
+                            if (subQuestion.getQuestionType() == QuesStructType.SINGLE_ANSWER_QUESTION
+                                    || subQuestion.getQuestionType() == QuesStructType.MULTIPLE_ANSWER_QUESTION) {
+                                subthemisAnswerContent.setAnswer(getSelectAnswer(subQuestion));
+                            } else if (subQuestion.getQuestionType() == QuesStructType.BOOL_ANSWER_QUESTION) {
+                                subthemisAnswerContent.setAnswer(getBoolAnswer(subQuestion));
+                            } else if (subQuestion.getQuestionType() == QuesStructType.FILL_BLANK_QUESTION) {
+                                subthemisAnswerContent.setAnswer(getFillBlankAnswer(subQuestion));
+                            } else {
+                                subthemisAnswerContent
+                                        .setAnswer(getAnswer(subQuestion.getQuesAnswer(), computerTestPaper));
+                            }
+                            subQuestions.add(subcomputerTestQuestion);
+                            subAnswers.add(subthemisAnswerContent);
+                        }
+                        computerTestQuestion.setSubQuestions(subQuestions);
+                        themisAnswerContent.setSubQuestions(subAnswers);
+                    }
+                    questions.add(computerTestQuestion);
+                    answers.add(themisAnswerContent);
+                } catch (StatusException e) {
+                    throw new StatusException(
+                            "第" + paperDetail.getNumber() + "大题,第" + paperDetailUnit.getNumber() + "小题 " + e.getDesc());
+                }
+            }
+            computerTestPaperDetail.setQuestions(questions);
+            answerDetail.setQuestions(answers);
+            // paperDetail中的题数(unitCount)可能不准确,这里以questions的实际size为准
+            computerTestPaperDetail.setQuestionCount(questions.size());
+            details.add(computerTestPaperDetail);
+            answerdetails.add(answerDetail);
+        }
+        computerTestPaper.setDetails(details);
+        themisAnswer.setDetails(answerdetails);
+
+        ThemisPaperAndAnswer ret = new ThemisPaperAndAnswer();
+        computerTestPaper.setId(null);
+        ret.setPaper(computerTestPaper);
+        ret.setAnswer(themisAnswer);
+        return ret;
+    }
+
+    private ThemisSections getBody(String str, ThemisPaper computerTestPaper) {
+        ThemisSections body = new ThemisSections();
+        List<ThemisSection> sections = new ArrayList<>();
+        // 得到小题题干或者答案行数
+        if (StringUtils.isBlank(str)) {
+            return body;
+        }
+        String[] questionRowStrings = str.split("</p>");
+        for (int i = 0; i < questionRowStrings.length; i++) {
+            List<ThemisBlock> blocks = disposeQuestionBodyOrOption(questionRowStrings[i], computerTestPaper);
+            if (blocks != null && blocks.size() > 0) {
+                ThemisSection section = new ThemisSection();
+                // 将小题题干拆分为Block集合
+                section.setBlocks(blocks);
+                sections.add(section);
+            }
+        }
+        body.setSections(sections);
+        return body;
+    }
+
+    private ThemisSections getFillBlankBody(String str, ThemisPaper computerTestPaper) {
+        ThemisSections body = new ThemisSections();
+        List<ThemisSection> sections = new ArrayList<>();
+        // 得到小题题干或者答案行数
+        if (StringUtils.isBlank(str)) {
+            return body;
+        }
+        String[] questionRowStrings = str.split("</p>");
+        for (int i = 0; i < questionRowStrings.length; i++) {
+            List<ThemisBlock> blocks = disposeFillBlankQuestionBody(questionRowStrings[i], computerTestPaper);
+            if (blocks != null && blocks.size() > 0) {
+                ThemisSection section = new ThemisSection();
+                // 将小题题干拆分为Block集合
+                section.setBlocks(blocks);
+                sections.add(section);
+            }
+        }
+        body.setSections(sections);
+        return body;
+    }
+
+    private List<ThemisSubjectiveAnswer> getAnswer(String str, ThemisPaper computerTestPaper) {
+        List<ThemisSection> sections = new ArrayList<>();
+        // 得到小题题干或者答案行数
+        if (StringUtils.isBlank(str)) {
+            return null;
+        }
+        String[] questionRowStrings = str.split("</p>");
+        for (int i = 0; i < questionRowStrings.length; i++) {
+            List<ThemisBlock> blocks = disposeQuestionBodyOrOption(questionRowStrings[i], computerTestPaper);
+            if (blocks != null && blocks.size() > 0) {
+                ThemisSection section = new ThemisSection();
+                // 将小题题干拆分为Block集合
+                section.setBlocks(blocks);
+                sections.add(section);
+            }
+        }
+        List<ThemisSubjectiveAnswer> ans = new ArrayList<>();
+        ThemisSubjectiveAnswer an = new ThemisSubjectiveAnswer();
+        ans.add(an);
+        an.setIndex(1);
+        an.setSections(sections);
+        return ans;
+    }
+
+    private String changeCloze(String text) {
+        StringBuffer buffer = new StringBuffer();
+        String regex = "##(\\d)##";
+
+        Pattern pattern = Pattern.compile(regex);
+        Matcher matcher = pattern.matcher(text);
+        // 使用find()方法查找匹配项
+        while (matcher.find()) {
+            matcher.appendReplacement(buffer, "__" + matcher.group(1) + "__");
+        }
+        // fixbug
+        matcher.appendTail(buffer);
+        return buffer.toString();
+    }
+
+    private ThemisSections getNestedBody(String str, ThemisPaper computerTestPaper) {
+        ThemisSections body = new ThemisSections();
+        List<ThemisSection> sections = new ArrayList<>();
+        // 得到小题题干或者答案行数
+        if (StringUtils.isBlank(str)) {
+            return body;
+        }
+        String[] questionRowStrings = str.split("</p>");
+        for (int i = 0; i < questionRowStrings.length; i++) {
+            List<ThemisBlock> blocks = disposeNestedQuestionBody(questionRowStrings[i], computerTestPaper);
+            if (blocks != null && blocks.size() > 0) {
+                ThemisSection section = new ThemisSection();
+                // 将小题题干拆分为Block集合
+                section.setBlocks(blocks);
+                sections.add(section);
+            }
+        }
+        body.setSections(sections);
+        return body;
+    }
+
+    private List<ThemisBlock> disposeNestedQuestionBody(String questionRow, ThemisPaper computerTestPaper) {
+        List<ThemisBlock> blocks = new ArrayList<>();
+        // 去掉每行里面的<p>,<span>,</span>标签
+        questionRow = questionRow.replaceAll("<p>", "").replaceAll("</p>", "").replaceAll("<span>", "")
+                .replaceAll("</span>", "").replaceAll("</a>", "");
+        String[] questionRowStrings = questionRow.split("<|/>|>");
+        boolean hasAudio = false;
+        for (int i = 0; i < questionRowStrings.length; i++) {
+            ThemisBlock block = new ThemisBlock();
+            String rowStr = questionRowStrings[i];
+            // 判断是否有图片
+            if (rowStr.startsWith("img")) {
+                rowStr = "<" + rowStr + ">";
+                Map<String, Object> param = new HashMap<>();
+                // 需要继续做截取,取到Parma
+                block.setType("image");
+                // 获取图片的路径
+                List<String> strSrcList = getImg(rowStr, "src");
+                if (strSrcList.size() > 0) {
+                    String strSrc = strSrcList.get(0).replaceAll("src=\"", "").replaceAll("\"", "");
+                    block.setValue(strSrc);
+                }
+                // 获取图片的高度
+                List<String> strHeightList = getImg(rowStr, "height");
+                if (strHeightList.size() > 0) {
+                    String strHeight = strHeightList.get(0).replaceAll("height=\"", "").replaceAll("\"", "");
+                    Integer px = getIntFromString(strHeight);
+                    if (px != null) {
+                        param.put("height", px);
+                    }
+                }
+                // 获取图片的宽度
+                List<String> strWidthList = getImg(rowStr, "width");
+                if (strHeightList.size() > 0) {
+                    String strWidth = strWidthList.get(0).replaceAll("width=\"", "").replaceAll("\"", "");
+                    Integer px = getIntFromString(strWidth);
+                    if (px != null) {
+                        param.put("width", px);
+                    }
+                }
+                block.setParam(param);
+                blocks.add(block);
+            } else if (rowStr.startsWith("a") && rowStr.contains("id") && rowStr.contains("name")) { // 处理音频
+                rowStr = "<" + rowStr + ">";
+                block.setType("audio");
+                String id = CommonUtils.getAttrValue(rowStr, "id");
+                QuestionAudio questionAudio = Model.of(questionAudioRepo.findById(id));
+                block.setValue(questionAudio.getId() + "." + questionAudio.getFileSuffixes());
+                blocks.add(block);
+                hasAudio = true;
+            } else {
+                block.setType("text");
+                rowStr = rowStr.replace("&nbsp;", "");// 消除空格
+                rowStr = rowStr.replace("&quot;", "\"");// 将&quot;转换成\"
+                rowStr = rowStr.replace("&lt;", "<");// 将&lt;转换成<
+                rowStr = rowStr.replace("&gt;", ">");// 将&gt;转换成>
+                rowStr = rowStr.replace("&amp;", "&");// 将&amp;转换成&
+                if (StringUtils.isNotBlank(rowStr)) {
+                    block.setValue(changeCloze(rowStr));
+                    blocks.add(block);
+                }
+            }
+        }
+        if (hasAudio) {
+            computerTestPaper.setHasAudio(hasAudio);
+        }
+        return blocks;
+    }
+
+    private List<ThemisBlock> disposeFillBlankQuestionBody(String questionRow, ThemisPaper computerTestPaper) {
+        List<ThemisBlock> blocks = new ArrayList<>();
+        // 去掉每行里面的<p>,<span>,</span>标签
+        questionRow = questionRow.replaceAll("<p>", "").replaceAll("</p>", "").replaceAll("<span>", "")
+                .replaceAll("</span>", "").replaceAll("</a>", "");
+        String[] questionRowStrings = questionRow.split("<|/>|>");
+        boolean hasAudio = false;
+        int blankIndex = 0;
+        for (int i = 0; i < questionRowStrings.length; i++) {
+            ThemisBlock block = new ThemisBlock();
+            String rowStr = questionRowStrings[i];
+            // 判断是否有图片
+            if (rowStr.startsWith("img")) {
+                rowStr = "<" + rowStr + ">";
+                Map<String, Object> param = new HashMap<>();
+                // 需要继续做截取,取到Parma
+                block.setType("image");
+                // 获取图片的路径
+                List<String> strSrcList = getImg(rowStr, "src");
+                if (strSrcList.size() > 0) {
+                    String strSrc = strSrcList.get(0).replaceAll("src=\"", "").replaceAll("\"", "");
+                    block.setValue(strSrc);
+                }
+                // 获取图片的高度
+                List<String> strHeightList = getImg(rowStr, "height");
+                if (strHeightList.size() > 0) {
+                    String strHeight = strHeightList.get(0).replaceAll("height=\"", "").replaceAll("\"", "");
+                    Integer px = getIntFromString(strHeight);
+                    if (px != null) {
+                        param.put("height", px);
+                    }
+                }
+                // 获取图片的宽度
+                List<String> strWidthList = getImg(rowStr, "width");
+                if (strHeightList.size() > 0) {
+                    String strWidth = strWidthList.get(0).replaceAll("width=\"", "").replaceAll("\"", "");
+                    Integer px = getIntFromString(strWidth);
+                    if (px != null) {
+                        param.put("width", px);
+                    }
+                }
+                block.setParam(param);
+                blocks.add(block);
+            } else if (rowStr.startsWith("a") && rowStr.contains("id") && rowStr.contains("name")) { // 处理音频
+                rowStr = "<" + rowStr + ">";
+                block.setType("audio");
+                String id = CommonUtils.getAttrValue(rowStr, "id");
+                QuestionAudio questionAudio = Model.of(questionAudioRepo.findById(id));
+                block.setValue(questionAudio.getId() + "." + questionAudio.getFileSuffixes());
+                blocks.add(block);
+                hasAudio = true;
+            } else {
+                rowStr = rowStr.replace("&nbsp;", "");// 消除空格
+                rowStr = rowStr.replace("&quot;", "\"");// 将&quot;转换成\"
+                rowStr = rowStr.replace("&lt;", "<");// 将&lt;转换成<
+                rowStr = rowStr.replace("&gt;", ">");// 将&gt;转换成>
+                rowStr = rowStr.replace("&amp;", "&");// 将&amp;转换成&
+
+                String regex = "###";
+
+                Pattern pattern = Pattern.compile(regex);
+                Matcher matcher = pattern.matcher(rowStr);
+                int indexStart = 0;
+                // 使用find()方法查找匹配项
+                while (matcher.find()) {
+                    blankIndex++;
+                    String content = rowStr.substring(indexStart, matcher.start());
+                    if (StringUtils.isNotEmpty(content)) {
+                        ThemisBlock temblock = new ThemisBlock();
+                        temblock.setType("text");
+                        temblock.setValue(content);
+                        blocks.add(temblock);
+                    }
+                    ThemisBlock blankblock = new ThemisBlock();
+                    blankblock.setType("cloze");
+                    blankblock.setValue(blankIndex);
+                    blocks.add(blankblock);
+                    indexStart = matcher.start() + regex.length();
+                }
+                if (indexStart < rowStr.length()) {
+                    // 输出最后一个分隔符之后的字符串
+                    String content = rowStr.substring(indexStart, rowStr.length());
+                    if (StringUtils.isNotEmpty(content)) {
+                        ThemisBlock temblock = new ThemisBlock();
+                        temblock.setType("text");
+                        temblock.setValue(content);
+                        blocks.add(temblock);
+                    }
+                }
+            }
+        }
+        if (hasAudio) {
+            computerTestPaper.setHasAudio(hasAudio);
+        }
+        return blocks;
+    }
+
+    private Integer getIntFromString(String s) {
+        if (StringUtils.isBlank(s)) {
+            return null;
+        }
+        s = s.trim();
+        s = s.replace("px", "");
+        try {
+            Integer i = Integer.valueOf(s);
+            return i;
+        } catch (NumberFormatException e) {
+            return null;
+        }
+    }
+
+    private List<ThemisBlock> disposeQuestionBodyOrOption(String questionRow, ThemisPaper computerTestPaper) {
+        List<ThemisBlock> blocks = new ArrayList<>();
+        // 去掉每行里面的<p>,<span>,</span>标签
+        questionRow = questionRow.replaceAll("<p>", "").replaceAll("</p>", "").replaceAll("<span>", "")
+                .replaceAll("</span>", "").replaceAll("</a>", "");
+        String[] questionRowStrings = questionRow.split("<|/>|>");
+        boolean hasAudio = false;
+        for (int i = 0; i < questionRowStrings.length; i++) {
+            ThemisBlock block = new ThemisBlock();
+            String rowStr = questionRowStrings[i];
+            // 判断是否有图片
+            if (rowStr.startsWith("img")) {
+                rowStr = "<" + rowStr + ">";
+                Map<String, Object> param = new HashMap<>();
+                // 需要继续做截取,取到Parma
+                block.setType("image");
+                // 获取图片的路径
+                List<String> strSrcList = getImg(rowStr, "src");
+                if (strSrcList.size() > 0) {
+                    String strSrc = strSrcList.get(0).replaceAll("src=\"", "").replaceAll("\"", "");
+                    block.setValue(strSrc);
+                }
+                // 获取图片的高度
+                List<String> strHeightList = getImg(rowStr, "height");
+                if (strHeightList.size() > 0) {
+                    String strHeight = strHeightList.get(0).replaceAll("height=\"", "").replaceAll("\"", "");
+                    Integer px = getIntFromString(strHeight);
+                    if (px != null) {
+                        param.put("height", px);
+                    }
+                }
+                // 获取图片的宽度
+                List<String> strWidthList = getImg(rowStr, "width");
+                if (strHeightList.size() > 0) {
+                    String strWidth = strWidthList.get(0).replaceAll("width=\"", "").replaceAll("\"", "");
+                    Integer px = getIntFromString(strWidth);
+                    if (px != null) {
+                        param.put("width", px);
+                    }
+                }
+                block.setParam(param);
+                blocks.add(block);
+            } else if (rowStr.startsWith("a")) { // 处理音频
+                if (rowStr.contains("id") && rowStr.contains("name")) { // 处理音频
+                    rowStr = "<" + rowStr + ">";
+                    block.setType("audio");
+                    String id = CommonUtils.getAttrValue(rowStr, "id");
+                    QuestionAudio questionAudio = Model.of(questionAudioRepo.findById(id));
+                    if (questionAudio == null) {
+                        throw new StatusException("音频标签错误");
+                    }
+                    block.setValue(questionAudio.getId() + "." + questionAudio.getFileSuffixes());
+                    blocks.add(block);
+                    hasAudio = true;
+                } else {
+                    throw new StatusException("音频标签错误");
+                }
+            } else {
+                block.setType("text");
+                rowStr = rowStr.replace("&nbsp;", "");// 消除空格
+                rowStr = rowStr.replace("&quot;", "\"");// 将&quot;转换成\"
+                rowStr = rowStr.replace("&lt;", "<");// 将&lt;转换成<
+                rowStr = rowStr.replace("&gt;", ">");// 将&gt;转换成>
+                rowStr = rowStr.replace("&amp;", "&");// 将&amp;转换成&
+                if (StringUtils.isNotBlank(rowStr)) {
+                    block.setValue(rowStr);
+                    blocks.add(block);
+                }
+            }
+        }
+        if (hasAudio) {
+            computerTestPaper.setHasAudio(hasAudio);
+        }
+        return blocks;
+    }
+
+    /**
+     * 获取图片里面的路径,长度,宽度
+     */
+    private List<String> getImg(String s, String str) {
+        String regex;
+        List<String> list = new ArrayList<>();
+        regex = str + "=\"(.*?)\"";
+        Pattern pa = Pattern.compile(regex, Pattern.DOTALL);
+        Matcher ma = pa.matcher(s);
+        while (ma.find()) {
+            list.add(ma.group());
+        }
+        return list;
+    }
+
+    private List<ThemisOption> getOption(Question question, ThemisPaper computerTestPaper) {
+        // 得到小题选项
+        List<QuesOption> quesOptions = question.getQuesOptions();
+        List<ThemisOption> options = new ArrayList<>();
+        // 遍历小题选项
+        if (quesOptions != null && quesOptions.size() > 0) {
+            for (QuesOption quesOption : quesOptions) {
+                ThemisOption option = new ThemisOption();
+                option.setNumber(new Integer(quesOption.getNumber()));
+                ThemisSections body = new ThemisSections();
+
+                List<ThemisSection> sections = new ArrayList<>();
+                // 得到小题选项
+                String optionString = quesOption.getOptionBody();
+                String[] optionStrings = optionString.split("</p>");
+                for (int i = 0; i < optionStrings.length; i++) {
+                    List<ThemisBlock> blocks = disposeQuestionBodyOrOption(optionStrings[i], computerTestPaper);
+                    if (blocks != null && blocks.size() > 0) {
+                        ThemisSection section = new ThemisSection();
+                        section.setBlocks(blocks);
+                        sections.add(section);
+                    }
+                }
+                body.setSections(sections);
+                option.setBody(body);
+                options.add(option);
+            }
+        }
+        return options;
+    }
+
+    private JsonArray getSelectAnswer(Question question) {
+        // 得到小题选项
+        List<QuesOption> quesOptions = question.getQuesOptions();
+        int index = 0;
+        // 遍历小题选项
+        if (quesOptions != null && quesOptions.size() > 0) {
+            JsonArray ja = new JsonArray();
+            for (QuesOption quesOption : quesOptions) {
+                index++;
+                if (quesOption.getIsCorrect() == 1) {
+                    ja.add(index);
+                }
+            }
+            if (ja.size() > 0) {
+                return ja;
+            } else {
+                return null;
+            }
+        }
+        return null;
+    }
+
+    private Boolean getBoolAnswer(Question question) {
+        String as = question.getQuesAnswer();
+        if (StringUtils.isBlank(as)) {
+            return null;
+        }
+        if (as.contains("正确")) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private void getSectionElement(Node ce, StringBuilder sb) {
+        if (("span".equals(ce.nodeName()) || "p".equals(ce.nodeName())) && ce.childNodeSize() > 0) {
+            for (Node e : ce.childNodes()) {
+                getSectionElement(e, sb);
+            }
+        } else {
+            if (ce instanceof TextNode) {
+                TextNode tn = (TextNode) ce;
+                String text = tn.text();
+                sb.append(text);
+            } else if (ce instanceof Element) {
+                if ("img".equals(ce.nodeName())) {
+                    Element el = (Element) ce;
+                    sb.append(el.outerHtml());
+                } else {
+                    Element el = (Element) ce;
+                    sb.append(el.text());
+                }
+            }
+        }
+    }
+
+    private List<ThemisSubjectiveAnswer> getFillBlankAnswer(Question question) {
+        String html = question.getQuesAnswer();
+        if (StringUtils.isBlank(html)) {
+            return null;
+        }
+        StringBuilder sb = new StringBuilder();
+        Document doc = Jsoup.parse(html);
+        Element b = doc.body();
+        for (Node ce : b.childNodes()) {
+            getSectionElement(ce, sb);
+        }
+
+        if (StringUtils.isBlank(sb.toString())) {
+            return null;
+        }
+        List<ThemisSubjectiveAnswer> tas = new ArrayList<>();
+        String[] sbs = sb.toString().split("##");
+        int index = 0;
+        for (String an : sbs) {
+            index++;
+            ThemisSubjectiveAnswer ta = new ThemisSubjectiveAnswer();
+            ta.setIndex(index);
+            List<ThemisSection> sections = new ArrayList<>();
+            ThemisSection sec = new ThemisSection();
+            List<ThemisBlock> blocks = new ArrayList<>();
+            Document subdoc = Jsoup.parse(an);
+            for (Node ce : subdoc.body().childNodes()) {
+                ThemisBlock block = new ThemisBlock();
+                if (ce instanceof TextNode) {
+                    TextNode tn = (TextNode) ce;
+                    String text = tn.text();
+                    block.setType("text");
+                    block.setValue(text);
+                } else if (ce instanceof Element) {
+                    if ("img".equals(ce.nodeName())) {
+                        Element el = (Element) ce;
+                        block.setType("image");
+                        block.setValue(el.attr("src"));
+                        String h = el.attr("height");
+                        String w = el.attr("width");
+                        if (StringUtils.isNotBlank(w) && StringUtils.isNotBlank(h)) {
+                            Map<String, Object> param = new HashMap<String, Object>();
+                            Integer hpx = getIntFromString(h);
+                            if (hpx != null) {
+                                param.put("height", hpx);
+                            }
+                            Integer wpx = getIntFromString(w);
+                            if (wpx != null) {
+                                param.put("width", wpx);
+                            }
+                            block.setParam(param);
+                        }
+                    } else {
+                        Element el = (Element) ce;
+                        block.setType("text");
+                        block.setValue(el.text());
+                    }
+                }
+                blocks.add(block);
+            }
+            sec.setBlocks(blocks);
+            sections.add(sec);
+            ta.setSections(sections);
+            tas.add(ta);
+        }
+        return tas;
+    }
 }

+ 228 - 221
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/impl/QuestionAudioServiceImpl.java

@@ -1,221 +1,228 @@
-package cn.com.qmth.examcloud.core.questions.service.impl;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import cn.com.qmth.examcloud.support.fss.FssFactory;
-import cn.com.qmth.examcloud.support.fss.FssHelper;
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.util.Assert;
-
-import cn.com.qmth.examcloud.api.commons.security.bean.User;
-import cn.com.qmth.examcloud.core.questions.base.Model;
-import cn.com.qmth.examcloud.core.questions.dao.QuestionAudioRepo;
-import cn.com.qmth.examcloud.core.questions.dao.entity.QuesOption;
-import cn.com.qmth.examcloud.core.questions.dao.entity.Question;
-import cn.com.qmth.examcloud.core.questions.dao.entity.QuestionAudio;
-import cn.com.qmth.examcloud.core.questions.service.QuestionAudioService;
-
-/**
- * @author chenken
- * @date 2017年8月1日 上午11:27:33
- * @company QMTH
- * @description QuestionRadioServiceImpl.java
- */
-@Service("questionAudioService")
-public class QuestionAudioServiceImpl implements QuestionAudioService {
-
-    @Autowired
-    private QuestionAudioRepo questionAudioRepo;
-
-    @Override
-    public void saveQuestionAudio(QuestionAudio questionAudio, User user) {
-        QuestionAudio existQuestionAudio = this.findByQuestionIdAndFileName(questionAudio.getQuestionId(), questionAudio.getFileName());
-        if (existQuestionAudio != null) {
-            questionAudio.setId(existQuestionAudio.getId());
-
-            String filePath = FssHelper.fixFilePath(existQuestionAudio.getFileUrl());
-            FssFactory.getInstance().deleteFile(filePath);
-
-            questionAudioRepo.delete(existQuestionAudio);
-        }
-
-        questionAudio.setCreateTime(new Date());
-        questionAudio.setCreateUser(user.getDisplayName());
-        questionAudioRepo.save(questionAudio);
-    }
-
-    @Override
-    public List<QuestionAudio> findQuestionAudiosByQuestionId(String questionId) {
-        Assert.hasLength(questionId, "questionId不能为空");
-        return questionAudioRepo.findByQuestionId(questionId);
-    }
-
-    @Override
-    public QuestionAudio findByQuestionIdAndFileName(String questionId, String fileName) {
-        if (StringUtils.isBlank(questionId) || StringUtils.isBlank(fileName)) {
-            return null;
-        }
-
-        List<QuestionAudio> audioList = questionAudioRepo.findByQuestionIdAndFileName(questionId, fileName);
-        if (CollectionUtils.isNotEmpty(audioList)) {
-
-            Collections.sort(audioList, (target1, target2) -> {
-                if (target1.getCreateTime() == null || target2.getCreateTime() == null) {
-                    return 0;
-                }
-
-                if (target1.getCreateTime().before(target2.getCreateTime())) {
-                    return 1;
-                }
-
-                return -1;
-            });
-
-            //取最新的一个
-            return audioList.get(0);
-        }
-
-        return null;
-    }
-
-    @Override
-    public void deleteAudioNotInQuestion(Question question) {
-        if (question.getHasAudio() != null && question.getHasAudio()) {
-            List<QuestionAudio> questionAudios = questionAudioRepo.findByQuestionId(question.getId());
-            StringBuffer buffer = new StringBuffer();
-            buffer.append(question.getQuesBody());
-            if (question.getQuesOptions() != null && question.getQuesOptions().size() > 0) {
-                for (QuesOption option : question.getQuesOptions()) {
-                    buffer.append(option.getOptionBody());
-                }
-            }
-
-            String questionBodyAndOptionStr = buffer.toString();
-            Iterator<QuestionAudio> audioIterator = questionAudios.iterator();
-            while (audioIterator.hasNext()) {
-                QuestionAudio audio = audioIterator.next();
-                if (!questionBodyAndOptionStr.contains(audio.getFileName())) {
-
-                    String filePath = FssHelper.fixFilePath(audio.getFileUrl());
-                    FssFactory.getInstance().deleteFile(filePath);
-
-                    questionAudioRepo.delete(audio);
-                }
-            }
-        }
-    }
-
-    @Override
-    public QuestionAudio findAudioById(String id) {
-        if (StringUtils.isNotBlank(id)) {
-            return Model.of(questionAudioRepo.findById(id));
-        }
-        return null;
-    }
-
-    @Override
-    public void sortAudio(Question question) {
-        if (question.getHasAudio() != null && question.getHasAudio()) {
-            //音频顺序改变后,更新bodyHtml
-            String newQusBody = getFileNames(question.getQuesBody(), question);
-            question.setQuesBody(newQusBody);
-            //跟新选项中的optionsHtml
-            if (question.getQuesOptions() != null && question.getQuesOptions().size() > 0) {
-                for (QuesOption option : question.getQuesOptions()) {
-                    String newOptionBody = getFileNames(option.getOptionBody(), question);
-                    option.setOptionBody(newOptionBody);
-                }
-            }
-        }
-    }
-
-    private String getFileNames(String str, Question question) {
-        Map<String, String> map = new LinkedHashMap<>();
-        Pattern p = Pattern.compile("<a\\s+[^<>]*\\s+name=\"([^<>\"]*)\"[^<>]*>");
-        Matcher m = p.matcher(str);
-        int i = 1;
-        int y = 1;
-        while (m.find()) {
-            String name = m.group(1);
-            StringBuffer buffer = new StringBuffer();
-            if (name.substring(0, name.indexOf("_") + 1).contains("2")) {
-                buffer.append(name.substring(0, name.lastIndexOf("_") + 1));
-                buffer.append(i);
-                buffer.append("@temp");
-                buffer.append(name.substring(name.lastIndexOf(".")));
-                map.put(name, buffer.toString());
-                i++;
-            } else {
-                buffer.append(name.substring(0, name.lastIndexOf("_") + 1));
-                buffer.append(y);
-                buffer.append("@temp");
-                buffer.append(name.substring(name.lastIndexOf(".")));
-                map.put(name, buffer.toString());
-                y++;
-            }
-        }
-        //循环替换
-        for (String key : map.keySet()) {
-            str = str.replace(key, map.get(key));
-        }
-        //替换并更新数据
-        for (String key : map.keySet()) {
-            String fileName = key;
-            String value = map.get(key).replace("@temp", "");
-            str = str.replace(map.get(key), value);
-            QuestionAudio questionAudio = this.findByQuestionIdAndFileName(question.getId(), fileName);
-            questionAudio.setFileName(value);
-            questionAudioRepo.save(questionAudio);
-        }
-        return str;
-    }
-
-    @Override
-    public void deleteAudio(List<Question> questions) {
-        //筛选有音频的试题
-        List<String> ids = new ArrayList<String>();
-        for (Question question : questions) {
-            if (question.getHasAudio() != null && question.getHasAudio()) {
-                ids.add(question.getId());
-            }
-        }
-        List<QuestionAudio> questionAudios = questionAudioRepo.findByQuestionIdIn(ids);
-        Iterator<QuestionAudio> audioIterator = questionAudios.iterator();
-        while (audioIterator.hasNext()) {
-            QuestionAudio audio = audioIterator.next();
-
-            String filePath = FssHelper.fixFilePath(audio.getFileUrl());
-            FssFactory.getInstance().deleteFile(filePath);
-        }
-        questionAudioRepo.deleteAll(questionAudios);
-    }
-    
-    @Override
-    public void deleteAudioByQuestionId(List<String> questionIds) {
-    	if(CollectionUtils.isEmpty(questionIds)) {
-    		return;
-    	}
-        List<QuestionAudio> questionAudios = questionAudioRepo.findByQuestionIdIn(questionIds);
-        Iterator<QuestionAudio> audioIterator = questionAudios.iterator();
-        while (audioIterator.hasNext()) {
-            QuestionAudio audio = audioIterator.next();
-
-            String filePath = FssHelper.fixFilePath(audio.getFileUrl());
-            FssFactory.getInstance().deleteFile(filePath);
-        }
-        questionAudioRepo.deleteAll(questionAudios);
-    }
-
-}
-
+package cn.com.qmth.examcloud.core.questions.service.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import cn.com.qmth.examcloud.support.fss.FssFactory;
+import cn.com.qmth.examcloud.support.fss.FssHelper;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.Assert;
+
+import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.core.questions.base.Model;
+import cn.com.qmth.examcloud.core.questions.dao.QuestionAudioRepo;
+import cn.com.qmth.examcloud.core.questions.dao.entity.QuesOption;
+import cn.com.qmth.examcloud.core.questions.dao.entity.Question;
+import cn.com.qmth.examcloud.core.questions.dao.entity.QuestionAudio;
+import cn.com.qmth.examcloud.core.questions.service.QuestionAudioService;
+
+/**
+ * @author chenken
+ * @date 2017年8月1日 上午11:27:33
+ * @company QMTH
+ * @description QuestionRadioServiceImpl.java
+ */
+@Service("questionAudioService")
+public class QuestionAudioServiceImpl implements QuestionAudioService {
+
+    @Autowired
+    private QuestionAudioRepo questionAudioRepo;
+
+    @Override
+    public void saveQuestionAudio(QuestionAudio questionAudio, User user) {
+        QuestionAudio existQuestionAudio = this.findByQuestionIdAndFileName(questionAudio.getQuestionId(),
+                questionAudio.getFileName());
+        if (existQuestionAudio != null) {
+            questionAudio.setId(existQuestionAudio.getId());
+
+            String filePath = FssHelper.fixFilePath(existQuestionAudio.getFileUrl());
+            FssFactory.getInstance().deleteFile(filePath);
+
+            questionAudioRepo.delete(existQuestionAudio);
+        }
+
+        questionAudio.setCreateTime(new Date());
+        questionAudio.setCreateUser(user.getDisplayName());
+        questionAudioRepo.save(questionAudio);
+    }
+
+    @Override
+    public List<QuestionAudio> findQuestionAudiosByQuestionId(String questionId) {
+        Assert.hasLength(questionId, "questionId不能为空");
+        return questionAudioRepo.findByQuestionId(questionId);
+    }
+
+    @Override
+    public QuestionAudio findByQuestionIdAndFileName(String questionId, String fileName) {
+        if (StringUtils.isBlank(questionId) || StringUtils.isBlank(fileName)) {
+            return null;
+        }
+
+        List<QuestionAudio> audioList = questionAudioRepo.findByQuestionIdAndFileName(questionId, fileName);
+        if (CollectionUtils.isNotEmpty(audioList)) {
+
+            Collections.sort(audioList, (target1, target2) -> {
+                if (target1.getCreateTime() == null || target2.getCreateTime() == null) {
+                    return 0;
+                }
+
+                if (target1.getCreateTime().before(target2.getCreateTime())) {
+                    return 1;
+                }
+
+                return -1;
+            });
+
+            // 取最新的一个
+            return audioList.get(0);
+        }
+
+        return null;
+    }
+
+    @Override
+    public void deleteAudioNotInQuestion(Question question) {
+        if (question.getHasAudio() != null && question.getHasAudio()) {
+            List<QuestionAudio> questionAudios = questionAudioRepo.findByQuestionId(question.getId());
+            StringBuffer buffer = new StringBuffer();
+            buffer.append(question.getQuesBody());
+            if (question.getQuesOptions() != null && question.getQuesOptions().size() > 0) {
+                for (QuesOption option : question.getQuesOptions()) {
+                    buffer.append(option.getOptionBody());
+                }
+            }
+
+            String questionBodyAndOptionStr = buffer.toString();
+            Iterator<QuestionAudio> audioIterator = questionAudios.iterator();
+            while (audioIterator.hasNext()) {
+                QuestionAudio audio = audioIterator.next();
+                if (!questionBodyAndOptionStr.contains(audio.getFileName())) {
+
+                    String filePath = FssHelper.fixFilePath(audio.getFileUrl());
+                    FssFactory.getInstance().deleteFile(filePath);
+
+                    questionAudioRepo.delete(audio);
+                }
+            }
+        }
+    }
+
+    @Override
+    public QuestionAudio findAudioById(String id) {
+        if (StringUtils.isNotBlank(id)) {
+            return Model.of(questionAudioRepo.findById(id));
+        }
+        return null;
+    }
+
+    @Override
+    public void sortAudio(Question question) {
+        if (question.getHasAudio() != null && question.getHasAudio()) {
+            // 音频顺序改变后,更新bodyHtml
+            String newQusBody = getFileNames(question.getQuesBody(), question);
+            question.setQuesBody(newQusBody);
+            // 跟新选项中的optionsHtml
+            if (question.getQuesOptions() != null && question.getQuesOptions().size() > 0) {
+                for (QuesOption option : question.getQuesOptions()) {
+                    String newOptionBody = getFileNames(option.getOptionBody(), question);
+                    option.setOptionBody(newOptionBody);
+                }
+            }
+        }
+    }
+
+    private String getFileNames(String str, Question question) {
+        Map<String, String> map = new LinkedHashMap<>();
+        Pattern p = Pattern.compile("<a\\s+[^<>]*\\s+name=\"([^<>\"]*)\"[^<>]*>");
+        Matcher m = p.matcher(str);
+        int i = 1;
+        int y = 1;
+        while (m.find()) {
+            String name = m.group(1);
+            if (name.lastIndexOf(".") == -1) {
+                throw new StatusException("音频标签错误");
+            }
+            StringBuffer buffer = new StringBuffer();
+            if (name.substring(0, name.indexOf("_") + 1).contains("2")) {
+                buffer.append(name.substring(0, name.lastIndexOf("_") + 1));
+                buffer.append(i);
+                buffer.append("@temp");
+                buffer.append(name.substring(name.lastIndexOf(".")));
+                map.put(name, buffer.toString());
+                i++;
+            } else {
+                buffer.append(name.substring(0, name.lastIndexOf("_") + 1));
+                buffer.append(y);
+                buffer.append("@temp");
+                buffer.append(name.substring(name.lastIndexOf(".")));
+                map.put(name, buffer.toString());
+                y++;
+            }
+        }
+        // 循环替换
+        for (String key : map.keySet()) {
+            str = str.replace(key, map.get(key));
+        }
+        // 替换并更新数据
+        for (String key : map.keySet()) {
+            String fileName = key;
+            String value = map.get(key).replace("@temp", "");
+            str = str.replace(map.get(key), value);
+            QuestionAudio questionAudio = this.findByQuestionIdAndFileName(question.getId(), fileName);
+            if (questionAudio == null) {
+                throw new StatusException("音频标签错误");
+            }
+            questionAudio.setFileName(value);
+            questionAudioRepo.save(questionAudio);
+        }
+        return str;
+    }
+
+    @Override
+    public void deleteAudio(List<Question> questions) {
+        // 筛选有音频的试题
+        List<String> ids = new ArrayList<String>();
+        for (Question question : questions) {
+            if (question.getHasAudio() != null && question.getHasAudio()) {
+                ids.add(question.getId());
+            }
+        }
+        List<QuestionAudio> questionAudios = questionAudioRepo.findByQuestionIdIn(ids);
+        Iterator<QuestionAudio> audioIterator = questionAudios.iterator();
+        while (audioIterator.hasNext()) {
+            QuestionAudio audio = audioIterator.next();
+
+            String filePath = FssHelper.fixFilePath(audio.getFileUrl());
+            FssFactory.getInstance().deleteFile(filePath);
+        }
+        questionAudioRepo.deleteAll(questionAudios);
+    }
+
+    @Override
+    public void deleteAudioByQuestionId(List<String> questionIds) {
+        if (CollectionUtils.isEmpty(questionIds)) {
+            return;
+        }
+        List<QuestionAudio> questionAudios = questionAudioRepo.findByQuestionIdIn(questionIds);
+        Iterator<QuestionAudio> audioIterator = questionAudios.iterator();
+        while (audioIterator.hasNext()) {
+            QuestionAudio audio = audioIterator.next();
+
+            String filePath = FssHelper.fixFilePath(audio.getFileUrl());
+            FssFactory.getInstance().deleteFile(filePath);
+        }
+        questionAudioRepo.deleteAll(questionAudios);
+    }
+
+}