deason пре 2 месеци
родитељ
комит
1214c51650
15 измењених фајлова са 4980 додато и 4617 уклоњено
  1. 128 98
      examcloud-core-questions-api-provider/src/main/java/cn/com/qmth/examcloud/core/questions/api/controller/PaperController.java
  2. 9 0
      examcloud-core-questions-base/pom.xml
  3. 174 90
      examcloud-core-questions-base/src/main/java/cn/com/qmth/examcloud/core/questions/base/converter/utils/FileUtil.java
  4. 63 55
      examcloud-core-questions-dao/src/main/java/cn/com/qmth/examcloud/core/questions/dao/entity/Paper.java
  5. 103 93
      examcloud-core-questions-dao/src/main/java/cn/com/qmth/examcloud/core/questions/dao/entity/PaperSearchInfo.java
  6. 311 321
      examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/ImportPaperService.java
  7. 380 331
      examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/impl/ExportPaperServiceImpl.java
  8. 814 768
      examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/impl/ExportThemisPaperServiceImpl.java
  9. 234 215
      examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/impl/PaperDetailUnitServiceImpl.java
  10. 2516 2487
      examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/impl/PaperServiceImpl.java
  11. 19 12
      examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/impl/QuestionAudioServiceImpl.java
  12. 34 8
      examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/themispaper/ThemisQuestion.java
  13. 185 137
      examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/util/ExportPaperUtil.java
  14. 1 1
      examcloud-core-questions-starter/src/main/resources/log4j2.xml
  15. 9 1
      pom.xml

+ 128 - 98
examcloud-core-questions-api-provider/src/main/java/cn/com/qmth/examcloud/core/questions/api/controller/PaperController.java

@@ -17,12 +17,17 @@ import javax.validation.constraints.NotNull;
 
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.bson.types.ObjectId;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Example;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageImpl;
+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.data.mongodb.core.query.Update;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Controller;
@@ -84,8 +89,7 @@ import freemarker.template.TemplateException;
 import io.swagger.annotations.ApiOperation;
 
 /**
- * Created by songyue on 16/12/28.
- * updated by weiwenhai on 2018.9.28
+ * Created by songyue on 16/12/28. updated by weiwenhai on 2018.9.28
  *
  * @code 160
  */
@@ -97,6 +101,9 @@ public class PaperController extends ControllerSupport {
 
     private final static String BASE_PAGE = "base_page";
 
+    @Autowired
+    MongoTemplate mongoTemplate;
+
     @Autowired
     PaperService paperService;
 
@@ -120,23 +127,23 @@ public class PaperController extends ControllerSupport {
 
     @Autowired
     PaperDetailUnitRepo paperDetailUnitRepo;
-    
-    
+
     @ResponseBody
     @ApiOperation(value = "试卷审核")
     @GetMapping(value = "/paper/audit/{paperId}")
     public void audit(@PathVariable String paperId) {
-    	User user=getAccessUser();
-    	Paper paper = cn.com.qmth.examcloud.core.questions.base.Model.of(paperRepo.findById(paperId));
-    	validateRootOrgIsolation(Long.valueOf(paper.getOrgId()));
-    	paper.setAuditStatus(true);
-    	paperRepo.save(paper);
-    	StringBuilder paperInfo=new StringBuilder();
-		paperInfo.append(" 课程:"+paper.getCourse().getName()+"("+paper.getCourse().getCode()+")");
-		paperInfo.append(" 试卷名称:"+paper.getName());
-    	ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(), AdminOperateType.TYPE31.getDesc(),paperInfo.toString()));
-    }
-    
+        User user = getAccessUser();
+        Paper paper = cn.com.qmth.examcloud.core.questions.base.Model.of(paperRepo.findById(paperId));
+        validateRootOrgIsolation(Long.valueOf(paper.getOrgId()));
+        paper.setAuditStatus(true);
+        paperRepo.save(paper);
+        StringBuilder paperInfo = new StringBuilder();
+        paperInfo.append(" 课程:" + paper.getCourse().getName() + "(" + paper.getCourse().getCode() + ")");
+        paperInfo.append(" 试卷名称:" + paper.getName());
+        ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
+                AdminOperateType.TYPE31.getDesc(), paperInfo.toString()));
+    }
+
     /**
      * 根据Id获取试卷
      *
@@ -167,9 +174,11 @@ public class PaperController extends ControllerSupport {
         if ("success".equals(msgMap.get("msg"))) {
             if (changeInfo != null) {
                 if (PaperType.IMPORT.equals(paper.getPaperType())) {
-                    ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(), AdminOperateType.TYPE32.getDesc(), changeInfo));
+                    ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
+                            AdminOperateType.TYPE32.getDesc(), changeInfo));
                 } else {
-                    ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(), AdminOperateType.TYPE33.getDesc(), changeInfo));
+                    ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
+                            AdminOperateType.TYPE33.getDesc(), changeInfo));
                 }
             }
             return new ResponseEntity<>(msgMap, HttpStatus.OK);
@@ -208,20 +217,21 @@ public class PaperController extends ControllerSupport {
     @ApiOperation(value = "查询所有导入试卷", notes = "查询所有导入试卷")
     @GetMapping(value = "/importPaper/{curPage}/{pageSize}")
     public ResponseEntity<Object> getImportPapers(@ModelAttribute PaperSearchInfo paperSearchInfo,
-                                                  @PathVariable int curPage,
-                                                  @PathVariable int pageSize) {
+            @PathVariable int curPage, @PathVariable int pageSize) {
         User user = getAccessUser();
         UserDataRule userDataRule = super.getUserDataRule(DataRuleType.COURSE);
 
         paperSearchInfo.setOrgId(user.getRootOrgId().toString());
 
-        return new ResponseEntity<>(paperService.getImportPapers(paperSearchInfo, curPage, pageSize, userDataRule), HttpStatus.OK);
+        return new ResponseEntity<>(paperService.getImportPapers(paperSearchInfo, curPage, pageSize, userDataRule),
+                HttpStatus.OK);
     }
 
     @ResponseBody
     @ApiOperation(value = "查询所有待审核和审核不通过的导入试卷", notes = "查询所有待审核和审核不通过的导入试卷")
     @GetMapping(value = "/importPaperNotSuccess/{curPage}/{pageSize}")
-    public ResponseEntity<Object> getImportPapersNotSuccess(@ModelAttribute PaperSearchInfo paperSearchInfo, @PathVariable int curPage, @PathVariable int pageSize) {
+    public ResponseEntity<Object> getImportPapersNotSuccess(@ModelAttribute PaperSearchInfo paperSearchInfo,
+            @PathVariable int curPage, @PathVariable int pageSize) {
         User user = getAccessUser();
         paperSearchInfo.setOrgId(user.getRootOrgId().toString());
         return new ResponseEntity<>(paperService.getImportPapersNotSuccess(paperSearchInfo, curPage, pageSize),
@@ -259,11 +269,11 @@ public class PaperController extends ControllerSupport {
     @ApiOperation(value = "查询所有已组试卷", notes = "查询所有已组试卷")
     @GetMapping(value = "/genPaper/{curPage}/{pageSize}")
     public ResponseEntity<Object> getGenPapers(@ModelAttribute PaperSearchInfo paperSearchInfo,
-                                               @PathVariable int curPage, @PathVariable int pageSize) {
+            @PathVariable int curPage, @PathVariable int pageSize) {
         User user = getAccessUser();
         UserDataRule ud = getUserDataRule(DataRuleType.COURSE);
         paperSearchInfo.setOrgId(user.getRootOrgId().toString());
-        return new ResponseEntity<>(paperService.getGenPapers(paperSearchInfo, curPage, pageSize,ud), HttpStatus.OK);
+        return new ResponseEntity<>(paperService.getGenPapers(paperSearchInfo, curPage, pageSize, ud), HttpStatus.OK);
     }
 
     /**
@@ -278,28 +288,30 @@ public class PaperController extends ControllerSupport {
     @ApiOperation(value = "查询所有导入试卷(not in paperIds)", notes = "查询所有导入试卷(not in paperIds)")
     @GetMapping(value = "/genPaper/huoge/{curPage}/{pageSize}")
     public ResponseEntity<Object> getGenPapersNotInIds(@ModelAttribute PaperSearchInfo paperSearchInfo,
-            @RequestParam(required = false) String ids,
-            @PathVariable int curPage,
-            @PathVariable int pageSize) {
-    	User user = getAccessUser();
-    	UserDataRule ud = getUserDataRule(DataRuleType.COURSE);
+            @RequestParam(required = false) String ids, @PathVariable int curPage, @PathVariable int pageSize) {
+        User user = getAccessUser();
+        UserDataRule ud = getUserDataRule(DataRuleType.COURSE);
         paperSearchInfo.setOrgId(user.getRootOrgId().toString());
-        Page<Paper> ret=null;
+        Page<Paper> ret = null;
         if (StringUtils.isNotBlank(ids)) {
-        	String[] idArr=ids.split(",");
-            ret = paperService.getPapersNotInIds(paperSearchInfo, idArr, curPage, pageSize, PaperType.GENERATE,ud);
-//            if (ret.getContent().size() == 0 && ret.getTotalElements() > 0 && curPage > 1) {
-//                ret = paperService.getPapersNotInIds(paperSearchInfo, idArr, curPage - 1, pageSize, PaperType.GENERATE,ud);
-//            }
+            String[] idArr = ids.split(",");
+            ret = paperService.getPapersNotInIds(paperSearchInfo, idArr, curPage, pageSize, PaperType.GENERATE, ud);
+            // if (ret.getContent().size() == 0 && ret.getTotalElements() > 0 &&
+            // curPage > 1) {
+            // ret = paperService.getPapersNotInIds(paperSearchInfo, idArr,
+            // curPage - 1, pageSize, PaperType.GENERATE,ud);
+            // }
         } else {
-            ret = paperService.getGenPapers(paperSearchInfo, curPage, pageSize,ud);
-//            if (ret.getContent().size() == 0 && ret.getTotalElements() > 0 && curPage > 1) {
-//                ret = paperService.getGenPapers(paperSearchInfo, curPage - 1, pageSize,ud);
-//            }
+            ret = paperService.getGenPapers(paperSearchInfo, curPage, pageSize, ud);
+            // if (ret.getContent().size() == 0 && ret.getTotalElements() > 0 &&
+            // curPage > 1) {
+            // ret = paperService.getGenPapers(paperSearchInfo, curPage - 1,
+            // pageSize,ud);
+            // }
         }
-        if(ret!=null&&CollectionUtils.isNotEmpty(ret.getContent())
-        		&&paperSearchInfo.getFillCount()!=null&&paperSearchInfo.getFillCount()) {
-        	setPaperQuesCountAndScore(ret.getContent());
+        if (ret != null && CollectionUtils.isNotEmpty(ret.getContent()) && paperSearchInfo.getFillCount() != null
+                && paperSearchInfo.getFillCount()) {
+            setPaperQuesCountAndScore(ret.getContent());
         }
         return new ResponseEntity<>(ret, HttpStatus.OK);
     }
@@ -315,8 +327,8 @@ public class PaperController extends ControllerSupport {
     @PostMapping(value = "/paper")
     public void delPaper(@RequestParam List<String> paperIds) {
         User user = getAccessUser();
-        if(CollectionUtils.isEmpty(paperIds)) {
-        	throw new StatusException("请选择试卷");
+        if (CollectionUtils.isEmpty(paperIds)) {
+            throw new StatusException("请选择试卷");
         }
         paperService.deletePapersPlus(paperIds, user);
     }
@@ -375,7 +387,7 @@ public class PaperController extends ControllerSupport {
     @ApiOperation(value = "获取卷库考试试卷", notes = "获取卷库考试试卷")
     @GetMapping(value = "/paper/list/{examId}/{courseCode}/{groupCode}")
     public List<Paper> listPaperById(@PathVariable String examId, @PathVariable String courseCode,
-                                     @PathVariable String groupCode) {
+            @PathVariable String groupCode) {
         return paperService.listExamPapers(Long.parseLong(examId), courseCode, groupCode);
     }
 
@@ -392,7 +404,7 @@ public class PaperController extends ControllerSupport {
     @ApiOperation(value = "新增考试试卷", notes = "新增考试试卷")
     @PostMapping(value = "/paper/join/{examId}/{courseCode}/{groupCode}/{paperId}")
     public ResponseEntity<Object> joinExamPaper(@PathVariable String examId, @PathVariable String courseCode,
-                                                @PathVariable String groupCode, @PathVariable String paperId) {
+            @PathVariable String groupCode, @PathVariable String paperId) {
         paperService.joinToExamPaper(Long.parseLong(examId), courseCode, groupCode, paperId);
         return new ResponseEntity<>(HttpStatus.OK);
     }
@@ -410,7 +422,7 @@ public class PaperController extends ControllerSupport {
     @ApiOperation(value = "删除考试试卷", notes = "删除考试试卷")
     @DeleteMapping(value = "/paper/release/{examId}/{courseCode}/{groupCode}/{paperId}")
     public ResponseEntity<Object> releaseExamPaper(@PathVariable String examId, @PathVariable String courseCode,
-                                                   @PathVariable String groupCode, @PathVariable String paperId) {
+            @PathVariable String groupCode, @PathVariable String paperId) {
 
         paperService.releaseExamPaper(Long.parseLong(examId), courseCode, groupCode, paperId);
         return new ResponseEntity<>(HttpStatus.OK);
@@ -442,7 +454,7 @@ public class PaperController extends ControllerSupport {
     @ApiOperation(value = "删除考试试卷类型", notes = "删除考试试卷类型")
     @DeleteMapping(value = "/paper/groupCode/{examId}/{courseCode}/{groupCode}")
     public ResponseEntity<Object> deleteGroup(@PathVariable String examId, @PathVariable String courseCode,
-                                              @PathVariable String groupCode) {
+            @PathVariable String groupCode) {
         paperService.deletGroupCode(Long.parseLong(examId), courseCode, groupCode);
         return new ResponseEntity<>(HttpStatus.OK);
     }
@@ -487,7 +499,7 @@ public class PaperController extends ControllerSupport {
     @ApiOperation(value = "向导入试卷中的新增试题", notes = "向导入试卷中的新增试题")
     @PostMapping(value = "/paper/addQuestion/{paperId}/{paperDetailId}")
     public ResponseEntity<Object> insertQuestionToPaper(@PathVariable String paperId,
-                                                        @PathVariable String paperDetailId, @RequestBody Question question) {
+            @PathVariable String paperDetailId, @RequestBody Question question) {
         User user = getAccessUser();
         return new ResponseEntity<>(paperService.insertQuestionToPaper(paperId, paperDetailId, question, user),
                 HttpStatus.OK);
@@ -585,11 +597,9 @@ public class PaperController extends ControllerSupport {
     @ResponseBody
     @ApiOperation(value = "查询用于选题的试题列表", notes = "查询用于选题的试题列表")
     @GetMapping(value = "/paper/listQuestion/{paperId}/{curPage}/{pageSize}")
-    public ResponseEntity<Object> listQuestionforSelect(@PathVariable String paperId,
-                                                        @PathVariable int curPage,
-                                                        @PathVariable int pageSize,
-                                                        @RequestParam(name = "quesType") String quesType,
-                                                        @RequestParam(name = "quesBody") String quesBody) {
+    public ResponseEntity<Object> listQuestionforSelect(@PathVariable String paperId, @PathVariable int curPage,
+            @PathVariable int pageSize, @RequestParam(name = "quesType") String quesType,
+            @RequestParam(name = "quesBody") String quesBody) {
         User user = getAccessUser();
         UserDataRule ud = getUserDataRule(DataRuleType.COURSE);
         if (user == null) {
@@ -599,7 +609,8 @@ public class PaperController extends ControllerSupport {
         if (StringUtils.isNotEmpty(quesType)) {
             quesStructType = QuesStructType.valueOf(quesType);
         }
-        Page<Question> questionPageList = paperService.listQuestionforSelect(paperId, curPage, pageSize, quesStructType, user, quesBody,ud);
+        Page<Question> questionPageList = paperService.listQuestionforSelect(paperId, curPage, pageSize, quesStructType,
+                user, quesBody, ud);
         return new ResponseEntity<>(questionPageList, HttpStatus.OK);
     }
 
@@ -615,7 +626,7 @@ public class PaperController extends ControllerSupport {
     @ApiOperation(value = "向导入试卷中的新增试题", notes = "向导入试卷中的新增试题")
     @PostMapping(value = "/paper/selectQuestions/{paperId}/{paperDetailId}")
     public ResponseEntity<Object> selectQuestionsToPaper(@PathVariable String paperId,
-                                                         @PathVariable String paperDetailId, @RequestBody List<Question> questions) {
+            @PathVariable String paperDetailId, @RequestBody List<Question> questions) {
         User user = getAccessUser();
         return new ResponseEntity<>(paperService.selectQuestionsToPaper(paperId, paperDetailId, questions, user),
                 HttpStatus.OK);
@@ -634,32 +645,34 @@ public class PaperController extends ControllerSupport {
     @ApiOperation(value = "查询所有导入试卷(not in paperIds)", notes = "查询所有导入试卷(not in paperIds)")
     @GetMapping(value = "/importPaper/huoge/{curPage}/{pageSize}")
     public ResponseEntity<Object> getImportPapersNotInIds(@ModelAttribute PaperSearchInfo paperSearchInfo,
-            @RequestParam(required = false) String ids,
-            @PathVariable int curPage,
-            @PathVariable int pageSize) {
-    	User user = getAccessUser();
-    	UserDataRule ud = getUserDataRule(DataRuleType.COURSE);
+            @RequestParam(required = false) String ids, @PathVariable int curPage, @PathVariable int pageSize) {
+        User user = getAccessUser();
+        UserDataRule ud = getUserDataRule(DataRuleType.COURSE);
         paperSearchInfo.setOrgId(user.getRootOrgId().toString());
-        Page<Paper> ret=null;
+        Page<Paper> ret = null;
         if (StringUtils.isNotBlank(ids)) {
-        	String[] idArr=ids.split(",");
-            ret = paperService.getPapersNotInIds(paperSearchInfo, idArr, curPage, pageSize, PaperType.IMPORT,ud);
-//            if (ret.getContent().size() == 0 && ret.getTotalElements() > 0 && curPage > 1) {
-//                ret = paperService.getPapersNotInIds(paperSearchInfo, idArr, curPage - 1, pageSize, PaperType.IMPORT,ud);
-//            }
+            String[] idArr = ids.split(",");
+            ret = paperService.getPapersNotInIds(paperSearchInfo, idArr, curPage, pageSize, PaperType.IMPORT, ud);
+            // if (ret.getContent().size() == 0 && ret.getTotalElements() > 0 &&
+            // curPage > 1) {
+            // ret = paperService.getPapersNotInIds(paperSearchInfo, idArr,
+            // curPage - 1, pageSize, PaperType.IMPORT,ud);
+            // }
         } else {
-            ret = paperService.getImportPapers(paperSearchInfo, curPage, pageSize,ud);
-//            if (ret.getContent().size() == 0 && ret.getTotalElements() > 0 && curPage > 1) {
-//                ret = paperService.getImportPapers(paperSearchInfo, curPage - 1, pageSize,ud);
-//            }
+            ret = paperService.getImportPapers(paperSearchInfo, curPage, pageSize, ud);
+            // if (ret.getContent().size() == 0 && ret.getTotalElements() > 0 &&
+            // curPage > 1) {
+            // ret = paperService.getImportPapers(paperSearchInfo, curPage - 1,
+            // pageSize,ud);
+            // }
         }
-        if(ret!=null&&CollectionUtils.isNotEmpty(ret.getContent())
-        		&&paperSearchInfo.getFillCount()!=null&&paperSearchInfo.getFillCount()) {
-        	setPaperQuesCountAndScore(ret.getContent());
+        if (ret != null && CollectionUtils.isNotEmpty(ret.getContent()) && paperSearchInfo.getFillCount() != null
+                && paperSearchInfo.getFillCount()) {
+            setPaperQuesCountAndScore(ret.getContent());
         }
         return new ResponseEntity<>(ret, HttpStatus.OK);
     }
-    
+
     private void setPaperQuesCountAndScore(List<Paper> paperList) {
         if (paperList == null || paperList.size() == 0) {
             return;
@@ -679,7 +692,8 @@ public class PaperController extends ControllerSupport {
                     }
                     String key = getKey(unit.getQuestion().getPublicity(), unit.getQuestion().getDifficulty());
                     quesCount.put(key, quesCount.get(key) + 1);
-                    quesScore.put(key, BigDecimal.valueOf(quesScore.get(key)).add(BigDecimal.valueOf(unit.getScore())).doubleValue());
+                    quesScore.put(key, BigDecimal.valueOf(quesScore.get(key)).add(BigDecimal.valueOf(unit.getScore()))
+                            .doubleValue());
                 }
             }
         }
@@ -752,16 +766,20 @@ public class PaperController extends ControllerSupport {
             String[] paperIdArray = paperIds.split(",");
             StringBuilder paperInfo = new StringBuilder();
             for (int i = 0; i < paperIdArray.length; i++) {
-                Paper oldpaper = cn.com.qmth.examcloud.core.questions.base.Model.of(paperRepo.findById(paperIdArray[i]));
-                boolean result = paperService.checkPaperName(oldpaper.getName(), PaperType.GENERATE, user.getRootOrgId() + "");
+                Paper oldpaper = cn.com.qmth.examcloud.core.questions.base.Model
+                        .of(paperRepo.findById(paperIdArray[i]));
+                boolean result = paperService.checkPaperName(oldpaper.getName(), PaperType.GENERATE,
+                        user.getRootOrgId() + "");
                 if (!result) {
                     throw new StatusException("160565", "考试试卷:" + oldpaper.getName() + "已经存在");
                 }
-                paperInfo.append(" 课程:" + oldpaper.getCourse().getName() + "(" + oldpaper.getCourse().getCode() + ") 试卷名称:" + oldpaper.getName());
+                paperInfo.append(" 课程:" + oldpaper.getCourse().getName() + "(" + oldpaper.getCourse().getCode()
+                        + ") 试卷名称:" + oldpaper.getName());
             }
             paperService.useBasePaper(paperIds, user.getDisplayName());
 
-            ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(), AdminOperateType.TYPE34.getDesc(), paperInfo.toString()));
+            ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
+                    AdminOperateType.TYPE34.getDesc(), paperInfo.toString()));
             return new ResponseEntity<>(HttpStatus.OK);
         } catch (Exception e) {
             throw new StatusException("160537", e.getMessage());
@@ -795,7 +813,8 @@ public class PaperController extends ControllerSupport {
     @Naked
     @ApiOperation(value = "预览试卷页面")
     @GetMapping(value = "/paper/pdf/{paperId}")
-    public String viewPaper(Model model, @PathVariable String paperId, @RequestParam(required = false) String examName) {
+    public String viewPaper(Model model, @PathVariable String paperId,
+            @RequestParam(required = false) String examName) {
         Paper paper = cn.com.qmth.examcloud.core.questions.base.Model.of(paperRepo.findById(paperId));
         if (paper == null) {
             throw new StatusException("500", "试卷信息不存在!");
@@ -812,7 +831,8 @@ public class PaperController extends ControllerSupport {
             map.put("courseNo", previewPaper.getCourseNo());
             map.put("courseName", previewPaper.getCourseName());
             map.put("courseLevel", previewPaper.getCourseLevel());
-            ExportTemplateUtil.getTemplate(Long.valueOf(paper.getOrgId()), ExportTemplateType.PAPER_VIEW).process(map, result);
+            ExportTemplateUtil.getTemplate(Long.valueOf(paper.getOrgId()), ExportTemplateType.PAPER_VIEW).process(map,
+                    result);
             String content = result.toString();
             model.addAttribute("pageContent", content);
             return BASE_PAGE;
@@ -829,7 +849,8 @@ public class PaperController extends ControllerSupport {
     @Naked
     @ApiOperation(value = "预览试卷答案页面")
     @GetMapping(value = "/paper/answer/pdf/{paperId}")
-    public String viewPaperAnswer(Model model, @PathVariable String paperId, @RequestParam(required = false) String examName) {
+    public String viewPaperAnswer(Model model, @PathVariable String paperId,
+            @RequestParam(required = false) String examName) {
         Paper paper = cn.com.qmth.examcloud.core.questions.base.Model.of(paperRepo.findById(paperId));
         if (paper == null) {
             throw new StatusException("500", "试卷答案信息不存在!");
@@ -838,7 +859,6 @@ public class PaperController extends ControllerSupport {
         ExportPaperAbstractService exportPaperService = PaperUtil.getByRootOrgId(paper.getOrgId());
         PaperExp previewPaper = exportPaperService.previewPaperForPDF(paper);
 
-
         StringWriter result = new StringWriter();
         try {
             Map<String, Object> map = new HashMap<String, Object>();
@@ -848,7 +868,8 @@ public class PaperController extends ControllerSupport {
             map.put("courseNo", previewPaper.getCourseNo());
             map.put("courseName", previewPaper.getCourseName());
             map.put("courseLevel", previewPaper.getCourseLevel());
-            ExportTemplateUtil.getTemplate(Long.valueOf(paper.getOrgId()), ExportTemplateType.ANWSER_VIEW).process(map, result);
+            ExportTemplateUtil.getTemplate(Long.valueOf(paper.getOrgId()), ExportTemplateType.ANWSER_VIEW).process(map,
+                    result);
             String content = result.toString();
             model.addAttribute("pageContent", content);
             return BASE_PAGE;
@@ -864,9 +885,8 @@ public class PaperController extends ControllerSupport {
 
     @ApiOperation(value = "传送到印刷平台", notes = "传送到印刷平台")
     @GetMapping(value = "/sendPrint/{paperId}/{examId}/{orgId}")
-    public ResponseEntity<Object> sendPrint(@PathVariable String paperId,
-                                            @PathVariable String orgId,
-                                            @PathVariable String examId) {
+    public ResponseEntity<Object> sendPrint(@PathVariable String paperId, @PathVariable String orgId,
+            @PathVariable String examId) {
         paperService.sendPrint(paperId, orgId, examId);
         return new ResponseEntity<>(HttpStatus.OK);
     }
@@ -874,9 +894,8 @@ public class PaperController extends ControllerSupport {
     @ResponseBody
     @ApiOperation(value = "根绝试卷id查询不同类型,题的数量")
     @GetMapping(value = "/paper/questionNumbers/{paperId}/{publicityType}/{difficultyType}")
-    public ResponseEntity<Object> questionNumbers(@PathVariable String paperId,
-                                                  @PathVariable Integer publicityType,
-                                                  @PathVariable Integer difficultyType) {
+    public ResponseEntity<Object> questionNumbers(@PathVariable String paperId, @PathVariable Integer publicityType,
+            @PathVariable Integer difficultyType) {
         int total = paperService.getQuestionTypeNumbers(paperId, publicityType, difficultyType);
         return new ResponseEntity<>(total, HttpStatus.OK);
     }
@@ -884,9 +903,8 @@ public class PaperController extends ControllerSupport {
     @ResponseBody
     @ApiOperation(value = "根绝试卷id查询不同类型,题的数量")
     @GetMapping(value = "/paper/questionScores/{paperId}/{publicityType}/{difficultyType}")
-    public ResponseEntity<Object> questionScores(@PathVariable String paperId,
-                                                 @PathVariable Integer publicityType,
-                                                 @PathVariable Integer difficultyType) {
+    public ResponseEntity<Object> questionScores(@PathVariable String paperId, @PathVariable Integer publicityType,
+            @PathVariable Integer difficultyType) {
         double total = paperService.getQuestionTypeScore(paperId, publicityType, difficultyType);
         return new ResponseEntity<>(total, HttpStatus.OK);
     }
@@ -910,11 +928,12 @@ public class PaperController extends ControllerSupport {
     @ApiOperation(value = "试卷答案导入")
     @RequestMapping(value = "/paper/answer/import/{paperId}", method = RequestMethod.POST)
     @ResponseBody
-    public void answerImport(@PathVariable String paperId, @RequestPart @NotNull(message = "上传文件不能为空!") MultipartFile dataFile) {
+    public void answerImport(@PathVariable String paperId,
+            @RequestPart @NotNull(message = "上传文件不能为空!") MultipartFile dataFile) {
         User user = getAccessUser();
         UserDataRule ud = getUserDataRule(DataRuleType.COURSE);
         if (ud.assertEmptyQueryResult()) {
-        	throw new StatusException("500", "没有数据权限");
+            throw new StatusException("500", "没有数据权限");
         }
         Paper paper = cn.com.qmth.examcloud.core.questions.base.Model.of(paperRepo.findById(paperId));
         if (paper == null) {
@@ -923,14 +942,15 @@ public class PaperController extends ControllerSupport {
         if (!isSuperAdmin() && !paper.getOrgId().equals(String.valueOf(user.getRootOrgId()))) {
             throw new StatusException("500", "非法请求");
         }
-        if(ud.assertNeedQueryRefIds()&&!ud.stringRefIds().contains(paper.getCourse().getId())) {
-        	throw new StatusException("500", "没有数据权限");
+        if (ud.assertNeedQueryRefIds() && !ud.stringRefIds().contains(paper.getCourse().getId())) {
+            throw new StatusException("500", "没有数据权限");
         }
         paperService.answerImport(paper, dataFile);
         StringBuilder paperInfo = new StringBuilder();
         paperInfo.append("课程:" + paper.getCourse().getName() + "(" + paper.getCourse().getCode() + ")");
         paperInfo.append(" 试卷名称:" + paper.getName());
-        ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(), AdminOperateType.TYPE35.getDesc(), paperInfo.toString()));
+        ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
+                AdminOperateType.TYPE35.getDesc(), paperInfo.toString()));
     }
 
     @ApiOperation(value = "下载答案模板", notes = "下载答案模板")
@@ -940,4 +960,14 @@ public class PaperController extends ControllerSupport {
         exportFile("答案导入模板.xlsx", new File(resoucePath));
     }
 
+    @ApiOperation(value = "标记小程序作答")
+    @PostMapping("paper/mark/app-answer")
+    @ResponseBody
+    public void markAppAnswer(@RequestParam String paperId, @RequestParam Boolean appAnswer) {
+        Query query = Query.query(Criteria.where("_id").is(new ObjectId(paperId)));
+        Update update = new Update();
+        update.set("appAnswer", appAnswer);
+        mongoTemplate.updateFirst(query, update, "paper");
+    }
+
 }

+ 9 - 0
examcloud-core-questions-base/pom.xml

@@ -12,6 +12,11 @@
     </parent>
 
     <dependencies>
+	    <dependency>
+			<groupId>org.w3c</groupId>
+			<artifactId>dom</artifactId>
+			<version>2.3.0-jaxb-1.0.6</version>
+		</dependency>
         <dependency>
             <groupId>cn.com.qmth.examcloud</groupId>
             <artifactId>examcloud-support</artifactId>
@@ -105,5 +110,9 @@
             <groupId>com.esotericsoftware</groupId>
             <artifactId>reflectasm</artifactId>
         </dependency>
+        <dependency>
+			<groupId>org.apache.tika</groupId>
+			<artifactId>tika-core</artifactId>
+		</dependency>
     </dependencies>
 </project>

+ 174 - 90
examcloud-core-questions-base/src/main/java/cn/com/qmth/examcloud/core/questions/base/converter/utils/FileUtil.java

@@ -1,50 +1,137 @@
 /*
- * *************************************************
- * Copyright (c) 2018 QMTH. All Rights Reserved.
- * Created by Deason on 2018-07-12 15:31:10.
+ * ************************************************* Copyright (c) 2018 QMTH.
+ * All Rights Reserved. Created by Deason on 2018-07-12 15:31:10.
  * *************************************************
  */
 
 package cn.com.qmth.examcloud.core.questions.base.converter.utils;
 
-import cn.com.qmth.examcloud.core.questions.base.IoUtils;
-import org.apache.commons.io.IOUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.*;
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.net.URL;
 import java.nio.charset.Charset;
 import java.text.SimpleDateFormat;
-import java.util.*;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 import java.util.zip.ZipOutputStream;
 
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.tika.Tika;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import cn.com.qmth.examcloud.commons.util.UUID;
+import cn.com.qmth.examcloud.core.questions.base.IoUtils;
+
 public class FileUtil {
+
     private static final Logger log = LoggerFactory.getLogger(FileUtil.class);
 
+    public static String imageUrlToBase64(String src) {
+        File temFile = null;
+        File image = null;
+        try {
+            URL url = new URL(src);
+            InputStream is = url.openStream();
+            String newFileName = UUID.randomUUID();
+            temFile = new File("temp/" + newFileName);
+            if (!temFile.getParentFile().exists()) {
+                temFile.mkdirs();
+            }
+            FileUtils.copyInputStreamToFile(is, temFile);
+            String imageType = checkImageType(temFile);
+            image = new File("temp/" + newFileName + "." + imageType);
+            temFile.renameTo(image);
+            return fileToBase64(image);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        } finally {
+            if (temFile != null) {
+                image.delete();
+            }
+            if (image != null) {
+                image.delete();
+            }
+        }
+    }
+
+    public static String fileToBase64(File imgFile) {
+        String fileName = imgFile.getName();
+        String suff = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
+        InputStream is = null;
+        byte[] base64Byte;
+        try {
+            base64Byte = new byte[0];
+            byte[] imgByte;
+            is = new FileInputStream(imgFile);
+            imgByte = IOUtils.toByteArray(is);
+            base64Byte = Base64.encodeBase64(imgByte);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        } finally {
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+        return "data:image/" + suff + ";base64," + new String(base64Byte);
+    }
+
+    public static String checkImageType(File file) {
+        Tika tika = new Tika();
+        String mimeType = null;
+        try {
+            mimeType = tika.detect(file);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        String type = mimeType.substring(mimeType.indexOf("/") + 1);
+        return type;
+    }
+
     /**
      * 分隔文件
      *
-     * @param sourcePath 原文件
-     * @param targetPath 目标文件
-     * @param n          跳过的字节数
+     * @param sourcePath
+     *            原文件
+     * @param targetPath
+     *            目标文件
+     * @param n
+     *            跳过的字节数
      * @return
      */
     public static File cutFile(String sourcePath, String targetPath, int n) {
         File file = new File(sourcePath);
         File newFile = new File(targetPath);
 
-        try (
-                FileInputStream fis = new FileInputStream(file);
+        try (FileInputStream fis = new FileInputStream(file);
                 InputStream is = new BufferedInputStream(fis);
-                OutputStream os = new FileOutputStream(newFile);
-        ) {
+                OutputStream os = new FileOutputStream(newFile);) {
 
-            //从n个字节开始读,注意中文是两个字节
+            // 从n个字节开始读,注意中文是两个字节
             fis.skip(n);
 
-            //指定文件位置读取的文件流,存入新文件
+            // 指定文件位置读取的文件流,存入新文件
             byte buffer[] = new byte[4 * 1024];
             int len;
             while ((len = is.read(buffer)) != -1) {
@@ -64,9 +151,12 @@ public class FileUtil {
     /**
      * 读取文件前面部分N个字节
      *
-     * @param path       文件路径
-     * @param headerSize 头信息字节数(必须2的倍数)
-     * @param signSize   签名信息字节数
+     * @param path
+     *            文件路径
+     * @param headerSize
+     *            头信息字节数(必须2的倍数)
+     * @param signSize
+     *            签名信息字节数
      * @return
      */
     public static String[] readFileHeader(String path, int headerSize, int signSize) {
@@ -74,11 +164,8 @@ public class FileUtil {
         String[] codes = new String[n + 1];
 
         File file = new File(path);
-        try (
-                FileInputStream fis = new FileInputStream(file);
-                DataInputStream ois = new DataInputStream(fis);
-        ) {
-            //分n次读取文件(n * 2)个字节
+        try (FileInputStream fis = new FileInputStream(file); DataInputStream ois = new DataInputStream(fis);) {
+            // 分n次读取文件(n * 2)个字节
             for (int i = 0; i < n; i++) {
                 codes[i] = String.valueOf(ois.readShort());
             }
@@ -145,23 +232,23 @@ public class FileUtil {
         FileOutputStream fos = null;
         DataOutputStream dos = null;
         try {
-            //创建临时文件
+            // 创建临时文件
             String baseFilePath = file.getAbsolutePath();
             String targetFilePath = getFilePathName(baseFilePath) + ".tk";
             File newFile = new File(targetFilePath);
             fos = new FileOutputStream(newFile);
             dos = new DataOutputStream(fos);
 
-            //写入头信息
+            // 写入头信息
             for (short s : headers) {
                 dos.writeShort(s);
             }
             if (sign != null && !"".equals(sign)) {
-                //写入签名信息
+                // 写入签名信息
                 dos.write(sign.getBytes("ISO-8859-1"));
             }
 
-            //在临时文件中追加原始文件内容
+            // 在临时文件中追加原始文件内容
             fis = new FileInputStream(file);
             is = new BufferedInputStream(fis);
 
@@ -192,10 +279,6 @@ public class FileUtil {
         return "/" + new SimpleDateFormat("yyyy-MM-dd").format(new Date()) + "/";
     }
 
-    public static String generateFileName() {
-        return UUID.randomUUID().toString().replaceAll("-", "");
-    }
-
     public static String generateDateName() {
         return new SimpleDateFormat("yyMMddHHmmss").format(new Date());
     }
@@ -217,7 +300,8 @@ public class FileUtil {
     /**
      * 获取无后缀的文件名
      *
-     * @param fileName 示例:../xxx/abc.xx
+     * @param fileName
+     *            示例:../xxx/abc.xx
      * @return 示例:../xxx/abc
      */
     public static String getFilePathName(String fileName) {
@@ -270,11 +354,9 @@ public class FileUtil {
             }
         }
 
-        try (
-                FileOutputStream fos = new FileOutputStream(file);
+        try (FileOutputStream fos = new FileOutputStream(file);
                 OutputStreamWriter write = new OutputStreamWriter(fos, encoding);
-                BufferedWriter bw = new BufferedWriter(write);
-        ) {
+                BufferedWriter bw = new BufferedWriter(write);) {
             bw.write(content);
             bw.flush();
             log.info("save as file success. " + path);
@@ -286,8 +368,10 @@ public class FileUtil {
     /**
      * 解压文件
      *
-     * @param targetDir 解压目录
-     * @param zipFile   待解压的ZIP文件
+     * @param targetDir
+     *            解压目录
+     * @param zipFile
+     *            待解压的ZIP文件
      */
     public static List<File> unZip(File targetDir, File zipFile) {
         if (targetDir == null) {
@@ -323,7 +407,7 @@ public class FileUtil {
             while (entries.hasMoreElements()) {
                 ZipEntry entry = (ZipEntry) entries.nextElement();
 
-                //Linux中需要替换掉路径的反斜杠
+                // Linux中需要替换掉路径的反斜杠
                 String entryName = (File.separator + entry.getName()).replaceAll("\\\\", "/");
 
                 String filePath = targetDir.getAbsolutePath() + entryName;
@@ -336,8 +420,7 @@ public class FileUtil {
                         dir.mkdirs();
                     }
 
-                    try (OutputStream os = new FileOutputStream(target);
-                         InputStream is = zip.getInputStream(entry);) {
+                    try (OutputStream os = new FileOutputStream(target); InputStream is = zip.getInputStream(entry);) {
                         IOUtils.copy(is, os);
                         os.flush();
                     } catch (IOException e) {
@@ -357,8 +440,10 @@ public class FileUtil {
     /**
      * 文件压缩
      *
-     * @param target  目录或文件
-     * @param zipFile 压缩后的ZIP文件
+     * @param target
+     *            目录或文件
+     * @param zipFile
+     *            压缩后的ZIP文件
      */
     public static boolean doZip(File target, File zipFile) {
         if (target == null || !target.exists()) {
@@ -371,10 +456,8 @@ public class FileUtil {
             return false;
         }
 
-        try (
-                OutputStream outStream = new FileOutputStream(zipFile);
-                ZipOutputStream zipOutStream = new ZipOutputStream(outStream, Charset.forName("UTF-8"));
-        ) {
+        try (OutputStream outStream = new FileOutputStream(zipFile);
+                ZipOutputStream zipOutStream = new ZipOutputStream(outStream, Charset.forName("UTF-8"));) {
             if (!zipFile.exists()) {
                 boolean ok = zipFile.createNewFile();
                 if (!ok) {
@@ -404,7 +487,7 @@ public class FileUtil {
     }
 
     private static void doZip(ZipOutputStream zipOutStream, File target, String parentDir) throws IOException {
-        //log.info("Zip:" + parentDir);
+        // log.info("Zip:" + parentDir);
         if (parentDir == null) {
             parentDir = "";
         }
@@ -437,44 +520,45 @@ public class FileUtil {
             zipOutStream.closeEntry();
         }
     }
+
     public static void deleteFolder(String path) {
 
-		File file = new File(path);
-		if (file.exists()) {
-			if (file.isFile()) {
-				deleteFile(path);
-			} else {
-				deleteDirectory(path);
-			}
-		}
-	}
-
-	public static void deleteFile(String path) {
-		File file = new File(path);
-		if (file.isFile() && file.exists()) {
-			file.delete();
-		}
-	}
-
-	public static void deleteDirectory(String path) {
-		if (!path.endsWith(File.separator)) {
-			path = path + File.separator;
-		}
-		File dirFile = new File(path);
-		if (!dirFile.exists() || !dirFile.isDirectory()) {
-			return;
-		}
-		File[] files = dirFile.listFiles();
-		if (files != null) {
-			for (int i = 0; i < files.length; i++) {
-				if (files[i].isFile()) {
-					deleteFile(files[i].getAbsolutePath());
-				} else {
-					deleteDirectory(files[i].getAbsolutePath());
-				}
-			}
-		}
-
-		dirFile.delete();
-	}
+        File file = new File(path);
+        if (file.exists()) {
+            if (file.isFile()) {
+                deleteFile(path);
+            } else {
+                deleteDirectory(path);
+            }
+        }
+    }
+
+    public static void deleteFile(String path) {
+        File file = new File(path);
+        if (file.isFile() && file.exists()) {
+            file.delete();
+        }
+    }
+
+    public static void deleteDirectory(String path) {
+        if (!path.endsWith(File.separator)) {
+            path = path + File.separator;
+        }
+        File dirFile = new File(path);
+        if (!dirFile.exists() || !dirFile.isDirectory()) {
+            return;
+        }
+        File[] files = dirFile.listFiles();
+        if (files != null) {
+            for (int i = 0; i < files.length; i++) {
+                if (files[i].isFile()) {
+                    deleteFile(files[i].getAbsolutePath());
+                } else {
+                    deleteDirectory(files[i].getAbsolutePath());
+                }
+            }
+        }
+
+        dirFile.delete();
+    }
 }

+ 63 - 55
examcloud-core-questions-dao/src/main/java/cn/com/qmth/examcloud/core/questions/dao/entity/Paper.java

@@ -15,12 +15,13 @@ import cn.com.qmth.examcloud.core.questions.dao.entity.base.MongoBaseEntity;
  * @author songyue
  */
 public class Paper extends MongoBaseEntity {
+
     /**
-	 * 
-	 */
-	private static final long serialVersionUID = -8681575737341326402L;
+     * 
+     */
+    private static final long serialVersionUID = -8681575737341326402L;
 
-	@Indexed(unique = true)
+    @Indexed(unique = true)
     private String name;// 试卷名称
 
     private String title;// 试卷标题
@@ -61,40 +62,42 @@ public class Paper extends MongoBaseEntity {
 
     private Specialty specialty;
 
-    private Double difficultyDegree; //难度系数
+    private Double difficultyDegree; // 难度系数
+
+    private String sameName; // 相同大题名 0:不合并,1:合并
 
-    private String sameName; //相同大题名 0:不合并,1:合并
+    private String examRemark;// 考试说明
 
-    private String examRemark;//考试说明
-    
     /**
      * 公开\非公开小题数量
      */
     @Transient
-    private Map<String,Integer> quesCount;
-    
+    private Map<String, Integer> quesCount;
+
     /**
      * 公开\非公开小题分数
      */
     @Transient
-    private Map<String,Double> quesScore;
-    
-    
+    private Map<String, Double> quesScore;
+
     /**
      * 是否在仓库:1-在 ,空或者0不在
      */
     private Integer storage;
-    
+
     /**
      * 是否已调用:1-已调用,空或者0未调用
      */
     private Integer inUse;
-    
+
     private Boolean auditStatus;
-    
-    //复制数据来源id(平台内复制)
+
+    // 复制数据来源id(平台内复制)
     private String sourceId;
 
+    // 是否app作答
+    private Boolean appAnswer;
+
     public String getName() {
         return name;
     }
@@ -275,55 +278,60 @@ public class Paper extends MongoBaseEntity {
         this.examRemark = examRemark;
     }
 
+    public Map<String, Integer> getQuesCount() {
+        return quesCount;
+    }
+
+    public void setQuesCount(Map<String, Integer> quesCount) {
+        this.quesCount = quesCount;
+    }
 
-	public Map<String, Integer> getQuesCount() {
-		return quesCount;
-	}
+    public Map<String, Double> getQuesScore() {
+        return quesScore;
+    }
 
-	public void setQuesCount(Map<String, Integer> quesCount) {
-		this.quesCount = quesCount;
-	}
+    public void setQuesScore(Map<String, Double> quesScore) {
+        this.quesScore = quesScore;
+    }
 
-	public Map<String, Double> getQuesScore() {
-		return quesScore;
-	}
+    public Integer getStorage() {
+        return storage;
+    }
 
-	public void setQuesScore(Map<String, Double> quesScore) {
-		this.quesScore = quesScore;
-	}
+    public void setStorage(Integer storage) {
+        this.storage = storage;
+    }
 
-	public Integer getStorage() {
-		return storage;
-	}
+    public Integer getInUse() {
+        return inUse;
+    }
 
-	public void setStorage(Integer storage) {
-		this.storage = storage;
-	}
+    public void setInUse(Integer inUse) {
+        this.inUse = inUse;
+    }
 
-	public Integer getInUse() {
-		return inUse;
-	}
+    public Boolean getAuditStatus() {
+        return auditStatus;
+    }
 
-	public void setInUse(Integer inUse) {
-		this.inUse = inUse;
-	}
+    public void setAuditStatus(Boolean auditStatus) {
+        this.auditStatus = auditStatus;
+    }
 
-	public Boolean getAuditStatus() {
-		return auditStatus;
-	}
+    public String getSourceId() {
+        return sourceId;
+    }
 
-	public void setAuditStatus(Boolean auditStatus) {
-		this.auditStatus = auditStatus;
-	}
+    public void setSourceId(String sourceId) {
+        this.sourceId = sourceId;
+    }
 
-	public String getSourceId() {
-		return sourceId;
-	}
+    public Boolean getAppAnswer() {
+        return appAnswer;
+    }
 
-	public void setSourceId(String sourceId) {
-		this.sourceId = sourceId;
-	}
+    public void setAppAnswer(Boolean appAnswer) {
+        this.appAnswer = appAnswer;
+    }
 
-	
-	
 }

+ 103 - 93
examcloud-core-questions-dao/src/main/java/cn/com/qmth/examcloud/core/questions/dao/entity/PaperSearchInfo.java

@@ -6,136 +6,146 @@ import java.io.Serializable;
 
 public class PaperSearchInfo implements Serializable {
 
-	private static final long serialVersionUID = 1L;
+    private static final long serialVersionUID = 1L;
 
-	private String name;// 试卷名称
+    private String name;// 试卷名称
 
-	private String createTime;// 创建时间
+    private String createTime;// 创建时间
 
-	private String creator;// 录入员
+    private String creator;// 录入员
 
-	private String lastModifyName;// 修改人
+    private String lastModifyName;// 修改人
 
-	private String courseNo;// 课程代码
+    private String courseNo;// 课程代码
 
-	private String specialtyNo;// 专业代码
+    private String specialtyNo;// 专业代码
 
-	private String level;// 层次
+    private String level;// 层次
 
-	private String orgId;// 机构Id
+    private String orgId;// 机构Id
 
-	private PaperStatus paperStatus; // 试卷审核状态
+    private PaperStatus paperStatus; // 试卷审核状态
 
-	private String[] paperIds;
+    private String[] paperIds;
 
-	private Integer inUse;
+    private Integer inUse;
 
-	private Boolean auditStatus;
-	
-	private Boolean fillCount;
+    private Boolean auditStatus;
 
-	public String getName() {
-		return name;
-	}
+    private Boolean fillCount;
 
-	public void setName(String name) {
-		this.name = name;
-	}
+    private Boolean appAnswer;
 
-	public String getCreateTime() {
-		return createTime;
-	}
+    public String getName() {
+        return name;
+    }
 
-	public void setCreateTime(String createTime) {
-		this.createTime = createTime;
-	}
+    public void setName(String name) {
+        this.name = name;
+    }
 
-	public String getCreator() {
-		return creator;
-	}
+    public String getCreateTime() {
+        return createTime;
+    }
 
-	public void setCreator(String creator) {
-		this.creator = creator;
-	}
+    public void setCreateTime(String createTime) {
+        this.createTime = createTime;
+    }
 
-	public String getCourseNo() {
-		return courseNo;
-	}
+    public String getCreator() {
+        return creator;
+    }
 
-	public void setCourseNo(String courseNo) {
-		this.courseNo = courseNo;
-	}
+    public void setCreator(String creator) {
+        this.creator = creator;
+    }
 
-	public String[] getPaperIds() {
-		return paperIds;
-	}
+    public String getCourseNo() {
+        return courseNo;
+    }
 
-	public void setPaperIds(String[] paperIds) {
-		this.paperIds = paperIds;
-	}
+    public void setCourseNo(String courseNo) {
+        this.courseNo = courseNo;
+    }
 
-	public String getOrgId() {
-		return orgId;
-	}
+    public String[] getPaperIds() {
+        return paperIds;
+    }
 
-	public void setOrgId(String orgId) {
-		this.orgId = orgId;
-	}
+    public void setPaperIds(String[] paperIds) {
+        this.paperIds = paperIds;
+    }
 
-	public PaperStatus getPaperStatus() {
-		return paperStatus;
-	}
+    public String getOrgId() {
+        return orgId;
+    }
 
-	public void setPaperStatus(PaperStatus paperStatus) {
-		this.paperStatus = paperStatus;
-	}
+    public void setOrgId(String orgId) {
+        this.orgId = orgId;
+    }
 
-	public String getSpecialtyNo() {
-		return specialtyNo;
-	}
+    public PaperStatus getPaperStatus() {
+        return paperStatus;
+    }
 
-	public void setSpecialtyNo(String specialtyNo) {
-		this.specialtyNo = specialtyNo;
-	}
+    public void setPaperStatus(PaperStatus paperStatus) {
+        this.paperStatus = paperStatus;
+    }
 
-	public String getLevel() {
-		return level;
-	}
+    public String getSpecialtyNo() {
+        return specialtyNo;
+    }
 
-	public void setLevel(String level) {
-		this.level = level;
-	}
+    public void setSpecialtyNo(String specialtyNo) {
+        this.specialtyNo = specialtyNo;
+    }
 
-	public String getLastModifyName() {
-		return lastModifyName;
-	}
+    public String getLevel() {
+        return level;
+    }
 
-	public void setLastModifyName(String lastModifyName) {
-		this.lastModifyName = lastModifyName;
-	}
+    public void setLevel(String level) {
+        this.level = level;
+    }
 
-	public Integer getInUse() {
-		return inUse;
-	}
+    public String getLastModifyName() {
+        return lastModifyName;
+    }
 
-	public void setInUse(Integer inUse) {
-		this.inUse = inUse;
-	}
+    public void setLastModifyName(String lastModifyName) {
+        this.lastModifyName = lastModifyName;
+    }
 
-	public Boolean getAuditStatus() {
-		return auditStatus;
-	}
+    public Integer getInUse() {
+        return inUse;
+    }
 
-	public void setAuditStatus(Boolean auditStatus) {
-		this.auditStatus = auditStatus;
-	}
+    public void setInUse(Integer inUse) {
+        this.inUse = inUse;
+    }
 
-	public Boolean getFillCount() {
-		return fillCount;
-	}
+    public Boolean getAuditStatus() {
+        return auditStatus;
+    }
 
-	public void setFillCount(Boolean fillCount) {
-		this.fillCount = fillCount;
-	}
+    public void setAuditStatus(Boolean auditStatus) {
+        this.auditStatus = auditStatus;
+    }
+
+    public Boolean getFillCount() {
+        return fillCount;
+    }
+
+    public void setFillCount(Boolean fillCount) {
+        this.fillCount = fillCount;
+    }
+
+    public Boolean getAppAnswer() {
+        return appAnswer;
+    }
+
+    public void setAppAnswer(Boolean appAnswer) {
+        this.appAnswer = appAnswer;
+    }
 
 }

+ 311 - 321
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/ImportPaperService.java

@@ -162,13 +162,12 @@ public class ImportPaperService {
      * @throws Exception
      */
 
-    public Paper importPaper(Paper paper, User user, File file,UserDataRule ud) throws Exception {
+    public Paper importPaper(Paper paper, User user, File file, UserDataRule ud) throws Exception {
         paperService.checkPaperNameNew(paper.getName(), user.getRootOrgId().toString());
         if (file.getName().endsWith(DOC_SUFFIX)) {
-            return processImportPaper(paper, user, file,ud);
+            return processImportPaper(paper, user, file, ud);
         } else if (file.getName().endsWith(JSON_SUFFIX)) {
-             return importPaperFromJsonService.processImportPaper(paper, user,
-             file);
+            return importPaperFromJsonService.processImportPaper(paper, user, file);
         } else {
             throw new PaperException("导入文件只支持.docx和.json类型");
         }
@@ -265,169 +264,171 @@ public class ImportPaperService {
      * @throws Exception
      */
 
-    public Paper processImportPaper(Paper paper, User user, File file,UserDataRule ud) throws Exception {
+    public Paper processImportPaper(Paper paper, User user, File file, UserDataRule ud) throws Exception {
         try {
-        	if (ud.assertEmptyQueryResult()) {
-    			throw new StatusException("没有数据权限");
-    		}
+            if (ud.assertEmptyQueryResult()) {
+                throw new StatusException("没有数据权限");
+            }
 
             // 得到前台的课程代码
             String courseNo = paper.getCourseNo();
 
-    		Course course = courseService.getCourse(user.getRootOrgId(), courseNo);
-    		if(ud.assertNeedQueryRefIds()&&!ud.stringRefIds().contains(course.getId())) {
-    			throw new StatusException("没有数据权限");
-    		}
-
-			WordprocessingMLPackage wordMLPackage;
-			WordprocessingMLPackage tmpWordMlPackage;
-			// WordprocessingMLPackage writePkg;
-			ImportPaperCheck importPaperCheck = new ImportPaperCheck();
-			wordMLPackage = WordprocessingMLPackage.load(file);
-			// 初始化图片路径
-			DocxProcessUtil.initPkgImage(wordMLPackage);
-			// 深拷贝临时pkg与最终写入数据库pkg
-			tmpWordMlPackage = DocxProcessUtil.getTmpPackage(wordMLPackage);
-			// 获取word文档中所有段落
-			List<Object> pList = DocxProcessUtil.getAllElementFromObject(wordMLPackage.getMainDocumentPart(), P.class);
-			// 设置试卷
-			initPaper(paper, paper.getName(), user);
-			// 创建空大题类
-			PaperDetail paperDetail = null;
-			// 创建大题集合
-			List<PaperDetail> paperDetails = new ArrayList<>();
-			// 创建小题集合
-			List<PaperDetailUnit> paperDetailUnits = new ArrayList<>();
-			// 创建试题集合
-			List<Question> questions = new ArrayList<>();
-			// 大题号
-			int mainQuesNum = 0;
-			// 小题号
-			int subQuesNum = 0;
-			// 大题下的小题序号
-			int errorQuesNum = 0;
-			for (int i = 0; i < pList.size(); i++) {
-				P p = (P) pList.get(i);
-				String pText = DocxProcessUtil.getPText(p);
-				if (StringUtils.isEmpty(pText)) {
-					// 跳过空白段落
-					continue;
-				} else if (isMainQuesHeader(pText)) {
-					// 处理大题头信息
-					processMainQuesHeader(pList, importPaperCheck.getIndex(), importPaperCheck, courseNo);
-					// 校验大题头信息
-					if (!checkQuesHeader(importPaperCheck)) {
-						throw new PaperException(importPaperCheck.getErrorInfo());
-					}
-					// 创建大题类
-					paperDetail = new PaperDetail();
-					// 设置大题类
-					initQuesHeader(paper, paperDetail, paperDetails, ++mainQuesNum, importPaperCheck);
-					// 设置当前索引,防止多余循环
-					i = importPaperCheck.getIndex() - 1;
-					errorQuesNum = 0;
-				} else if (DocxProcessUtil.isNumPr(p)) {
-					// 检测到序列
-					importPaperCheck.setErrorInfo(importPaperCheck.getQuesName() + ImportPaperMsg.errMsg_10);
-					throw new PaperException(importPaperCheck.getErrorInfo());
-
-				} else if ((pText.matches("^\\d{1,}\\.[\\s\\S]*") && !pText.startsWith(ImportPaperMsg.left_bracket))
-						|| (isNested(importPaperCheck) && pText.startsWith(ImportPaperMsg.nestedQuestion_start))) {
-					if (paperDetail == null) {
-						throw new PaperException("导入文件格式有误,必须有大题头信息,且以 [ 开头!");
-					}
-					++errorQuesNum;
-					++subQuesNum;
-					// 处理试题
-					// 创建小题类和试题类
-					PaperDetailUnit paperDetailUnit = new PaperDetailUnit();
-					Question question = new Question();
-					// 初始化小题类和试题类
-					initPaperDetail(paper, paperDetail, paperDetailUnit, question, subQuesNum, importPaperCheck);
-					// 处理客观题
-					if (importPaperCheck.getQuesType().equals(ImportPaperMsg.singleSelection)
-							|| importPaperCheck.getQuesType().equals(ImportPaperMsg.multipleSelection)) {
-						// 处理题干
-						processQuesBody(pList, importPaperCheck.getIndex(), subQuesNum, question, importPaperCheck,
-								tmpWordMlPackage, errorQuesNum);
-						// 处理选项
-						processQuesOption(pList, importPaperCheck.getIndex(), subQuesNum, question, importPaperCheck,
-								tmpWordMlPackage, errorQuesNum);
-						// 处理尾信息
-						processQuesTail(pList, importPaperCheck.getIndex(), subQuesNum, question, paperDetailUnit,
-								importPaperCheck, tmpWordMlPackage, false, paper, errorQuesNum);
-						// 处理选择题的option--chenken 20170425
-						processSelectOption(question);
-					} else if (importPaperCheck.getQuesType().equals(ImportPaperMsg.nestedQuestion_word)) {
-						// 处理套题
-						processNestedQues(pList, importPaperCheck.getIndex(), question, paperDetailUnit,
-								importPaperCheck, tmpWordMlPackage, paper);
-					} else {
-						// 处理其他题型
-						processQuesBody(pList, importPaperCheck.getIndex(), subQuesNum, question, importPaperCheck,
-								tmpWordMlPackage, errorQuesNum);
-						processQuesTail(pList, importPaperCheck.getIndex(), subQuesNum, question, paperDetailUnit,
-								importPaperCheck, tmpWordMlPackage, false, paper, errorQuesNum);
-						// 填空题空格校验
-						if (question.getQuestionType().getName().equals(QuesStructType.FILL_BLANK_QUESTION.getName())) {
-							if (!StringUtils.isBlank(question.getQuesAnswer())) {
-								processFill(question, paperDetailUnit, importPaperCheck, subQuesNum, errorQuesNum);
-							}
-						}
-					}
-					// 设置WordMlPackage二进制数据
-					//                byte[] pkgByte = getZipResource(wordMLPackage, question);
-					//                QuestionPkgPath quesPkgPath = quesPkgPathRepo.save(new QuestionPkgPath(pkgByte));
-					//                question.setQuesPkgPathId(quesPkgPath.getId());
-					//                pkgByte = null;
-					//                quesPkgPath.setQuesPkg(null);
-					// 设置question与Unit集合数据
-					question.setCourse(paper.getCourse());
-					question.setOrgId(user.getRootOrgId().toString());
-					questions.add(question);
-					paperDetailUnits.add(paperDetailUnit);
-					// 设置当前索引,防止多余循环
-					i = importPaperCheck.getIndex() - 1;
-				} else if (paperDetail == null) {
-					throw new PaperException("导入文件格式有误,必须有大题头信息,且以[试题分类]开头!");
-				} else {
-					String errorMsg = pText.length() > 10 ? pText.substring(0, 10) : pText;
-					if (pText.startsWith(ImportPaperMsg.left_bracket)) {
-						throw new PaperException(
-								errorMsg + ",标签格式不正确!正确标签格式:[套题]、[套题数量]、[小题分数]、[答案]、[难度]、[一级属性]、[二级属性]、[公开度]、[小题型]");
-					}
-					throw new PaperException(
-							importPaperCheck.getQuesName() + ":“" + errorMsg + "”" + ImportPaperMsg.errMsg_12);
-				}
-				if (!StringUtils.isEmpty(importPaperCheck.getErrorInfo())) {
-					throw new PaperException(importPaperCheck.getErrorInfo());
-				}
-			}
-			if (paperDetails.size() == 0 || paperDetailUnits.size() == 0) {
-				throw new PaperException("导入文件格式有误!");
-			}
-			paper.setPaperDetailCount(mainQuesNum);
-			// 保存导入试卷信息
-			paper = savePaper(paper, paperDetails, paperDetailUnits, questions, importPaperCheck);
-			clearPaper(paperDetails, paperDetailUnits, questions);
-			wordMLPackage = null;
-			tmpWordMlPackage = null;
-		} finally {
-			FileUtils.deleteQuietly(file);
-		}
+            Course course = courseService.getCourse(user.getRootOrgId(), courseNo);
+            if (ud.assertNeedQueryRefIds() && !ud.stringRefIds().contains(course.getId())) {
+                throw new StatusException("没有数据权限");
+            }
+
+            WordprocessingMLPackage wordMLPackage;
+            WordprocessingMLPackage tmpWordMlPackage;
+            // WordprocessingMLPackage writePkg;
+            ImportPaperCheck importPaperCheck = new ImportPaperCheck();
+            wordMLPackage = WordprocessingMLPackage.load(file);
+            // 初始化图片路径
+            DocxProcessUtil.initPkgImage(wordMLPackage);
+            // 深拷贝临时pkg与最终写入数据库pkg
+            tmpWordMlPackage = DocxProcessUtil.getTmpPackage(wordMLPackage);
+            // 获取word文档中所有段落
+            List<Object> pList = DocxProcessUtil.getAllElementFromObject(wordMLPackage.getMainDocumentPart(), P.class);
+            // 设置试卷
+            initPaper(paper, paper.getName(), user);
+            // 创建空大题类
+            PaperDetail paperDetail = null;
+            // 创建大题集合
+            List<PaperDetail> paperDetails = new ArrayList<>();
+            // 创建小题集合
+            List<PaperDetailUnit> paperDetailUnits = new ArrayList<>();
+            // 创建试题集合
+            List<Question> questions = new ArrayList<>();
+            // 大题号
+            int mainQuesNum = 0;
+            // 小题号
+            int subQuesNum = 0;
+            // 大题下的小题序号
+            int errorQuesNum = 0;
+            for (int i = 0; i < pList.size(); i++) {
+                P p = (P) pList.get(i);
+                String pText = DocxProcessUtil.getPText(p);
+                if (StringUtils.isEmpty(pText)) {
+                    // 跳过空白段落
+                    continue;
+                } else if (isMainQuesHeader(pText)) {
+                    // 处理大题头信息
+                    processMainQuesHeader(pList, importPaperCheck.getIndex(), importPaperCheck, courseNo);
+                    // 校验大题头信息
+                    if (!checkQuesHeader(importPaperCheck)) {
+                        throw new PaperException(importPaperCheck.getErrorInfo());
+                    }
+                    // 创建大题类
+                    paperDetail = new PaperDetail();
+                    // 设置大题类
+                    initQuesHeader(paper, paperDetail, paperDetails, ++mainQuesNum, importPaperCheck);
+                    // 设置当前索引,防止多余循环
+                    i = importPaperCheck.getIndex() - 1;
+                    errorQuesNum = 0;
+                } else if (DocxProcessUtil.isNumPr(p)) {
+                    // 检测到序列
+                    importPaperCheck.setErrorInfo(importPaperCheck.getQuesName() + ImportPaperMsg.errMsg_10);
+                    throw new PaperException(importPaperCheck.getErrorInfo());
+
+                } else if ((pText.matches("^\\d{1,}\\.[\\s\\S]*") && !pText.startsWith(ImportPaperMsg.left_bracket))
+                        || (isNested(importPaperCheck) && pText.startsWith(ImportPaperMsg.nestedQuestion_start))) {
+                    if (paperDetail == null) {
+                        throw new PaperException("导入文件格式有误,必须有大题头信息,且以 [ 开头!");
+                    }
+                    ++errorQuesNum;
+                    ++subQuesNum;
+                    // 处理试题
+                    // 创建小题类和试题类
+                    PaperDetailUnit paperDetailUnit = new PaperDetailUnit();
+                    Question question = new Question();
+                    // 初始化小题类和试题类
+                    initPaperDetail(paper, paperDetail, paperDetailUnit, question, subQuesNum, importPaperCheck);
+                    // 处理客观题
+                    if (importPaperCheck.getQuesType().equals(ImportPaperMsg.singleSelection)
+                            || importPaperCheck.getQuesType().equals(ImportPaperMsg.multipleSelection)) {
+                        // 处理题干
+                        processQuesBody(pList, importPaperCheck.getIndex(), subQuesNum, question, importPaperCheck,
+                                tmpWordMlPackage, errorQuesNum);
+                        // 处理选项
+                        processQuesOption(pList, importPaperCheck.getIndex(), subQuesNum, question, importPaperCheck,
+                                tmpWordMlPackage, errorQuesNum);
+                        // 处理尾信息
+                        processQuesTail(pList, importPaperCheck.getIndex(), subQuesNum, question, paperDetailUnit,
+                                importPaperCheck, tmpWordMlPackage, false, paper, errorQuesNum);
+                        // 处理选择题的option--chenken 20170425
+                        processSelectOption(question);
+                    } else if (importPaperCheck.getQuesType().equals(ImportPaperMsg.nestedQuestion_word)) {
+                        // 处理套题
+                        processNestedQues(pList, importPaperCheck.getIndex(), question, paperDetailUnit,
+                                importPaperCheck, tmpWordMlPackage, paper);
+                    } else {
+                        // 处理其他题型
+                        processQuesBody(pList, importPaperCheck.getIndex(), subQuesNum, question, importPaperCheck,
+                                tmpWordMlPackage, errorQuesNum);
+                        processQuesTail(pList, importPaperCheck.getIndex(), subQuesNum, question, paperDetailUnit,
+                                importPaperCheck, tmpWordMlPackage, false, paper, errorQuesNum);
+                        // 填空题空格校验
+                        if (question.getQuestionType().getName().equals(QuesStructType.FILL_BLANK_QUESTION.getName())) {
+                            if (!StringUtils.isBlank(question.getQuesAnswer())) {
+                                processFill(question, paperDetailUnit, importPaperCheck, subQuesNum, errorQuesNum);
+                            }
+                        }
+                    }
+                    // 设置WordMlPackage二进制数据
+                    // byte[] pkgByte = getZipResource(wordMLPackage, question);
+                    // QuestionPkgPath quesPkgPath = quesPkgPathRepo.save(new
+                    // QuestionPkgPath(pkgByte));
+                    // question.setQuesPkgPathId(quesPkgPath.getId());
+                    // pkgByte = null;
+                    // quesPkgPath.setQuesPkg(null);
+                    // 设置question与Unit集合数据
+                    question.setCourse(paper.getCourse());
+                    question.setOrgId(user.getRootOrgId().toString());
+                    questions.add(question);
+                    paperDetailUnits.add(paperDetailUnit);
+                    // 设置当前索引,防止多余循环
+                    i = importPaperCheck.getIndex() - 1;
+                } else if (paperDetail == null) {
+                    throw new PaperException("导入文件格式有误,必须有大题头信息,且以[试题分类]开头!");
+                } else {
+                    String errorMsg = pText.length() > 10 ? pText.substring(0, 10) : pText;
+                    if (pText.startsWith(ImportPaperMsg.left_bracket)) {
+                        throw new PaperException(
+                                errorMsg + ",标签格式不正确!正确标签格式:[套题]、[套题数量]、[小题分数]、[答案]、[难度]、[一级属性]、[二级属性]、[公开度]、[小题型]");
+                    }
+                    throw new PaperException(
+                            importPaperCheck.getQuesName() + ":“" + errorMsg + "”" + ImportPaperMsg.errMsg_12);
+                }
+                if (!StringUtils.isEmpty(importPaperCheck.getErrorInfo())) {
+                    throw new PaperException(importPaperCheck.getErrorInfo());
+                }
+            }
+            if (paperDetails.size() == 0 || paperDetailUnits.size() == 0) {
+                throw new PaperException("导入文件格式有误!");
+            }
+            paper.setPaperDetailCount(mainQuesNum);
+            // 保存导入试卷信息
+            paper = savePaper(paper, paperDetails, paperDetailUnits, questions, importPaperCheck);
+            clearPaper(paperDetails, paperDetailUnits, questions);
+            wordMLPackage = null;
+            tmpWordMlPackage = null;
+        } finally {
+            FileUtils.deleteQuietly(file);
+        }
         return paper;
     }
 
-//    private byte[] getZipResource(WordprocessingMLPackage wordMLPackage, Question question) throws Exception {
-//        List<String> wordXmls = getWordXmlByQuestion(question);
-//        List<Question> subQuestions = question.getSubQuestions();
-//        if (subQuestions != null && subQuestions.size() > 0) {
-//            for (Question subQuestion : subQuestions) {
-//                wordXmls.addAll(getWordXmlByQuestion(subQuestion));
-//            }
-//        }
-//        return DocxProcessUtil.getWordBytesByQuestion(wordMLPackage, wordXmls);
-//    }
+    // private byte[] getZipResource(WordprocessingMLPackage wordMLPackage,
+    // Question question) throws Exception {
+    // List<String> wordXmls = getWordXmlByQuestion(question);
+    // List<Question> subQuestions = question.getSubQuestions();
+    // if (subQuestions != null && subQuestions.size() > 0) {
+    // for (Question subQuestion : subQuestions) {
+    // wordXmls.addAll(getWordXmlByQuestion(subQuestion));
+    // }
+    // }
+    // return DocxProcessUtil.getWordBytesByQuestion(wordMLPackage, wordXmls);
+    // }
 
     public List<String> getWordXmlByQuestion(Question question) {
         List<String> wordXmls = new ArrayList<>();
@@ -742,7 +743,7 @@ public class ImportPaperService {
         // 定义题干wordml和html
         StringBuilder quesBodyWordMl = new StringBuilder();
         StringBuilder quesBodyHtml = new StringBuilder();
-        boolean hasSeq=false;
+        boolean hasSeq = false;
         int i = 0;
         for (i = index; i < pList.size(); i++) {
             P pBody = (P) pList.get(i);
@@ -756,9 +757,9 @@ public class ImportPaperService {
                 throw new PaperException(importPaperCheck.getErrorInfo());
 
             } else if (tmpText.matches("^\\d{1,}\\.[\\s\\S]*")) {
-            	if(hasSeq) {
-            		// 检测到序列
-            		if (subQuesNum == 0) {
+                if (hasSeq) {
+                    // 检测到序列
+                    if (subQuesNum == 0) {
                         if (importPaperCheck.getNestedHeadNumber() != 0) {
                             importPaperCheck.setErrorInfo(importPaperCheck.getQuesName() + "第"
                                     + importPaperCheck.getNestedHeadNumber() + "个题" + ImportPaperMsg.errMsg_14);
@@ -768,17 +769,18 @@ public class ImportPaperService {
                         }
                     } else {
                         if (importPaperCheck.getNestedHeadNumber() != 0) {
-                            importPaperCheck.setErrorInfo(importPaperCheck.getQuesName() + "第"
-                                    + importPaperCheck.getNestedHeadNumber() + "个题" + errorQuesNum + ImportPaperMsg.errMsg_14);
+                            importPaperCheck.setErrorInfo(
+                                    importPaperCheck.getQuesName() + "第" + importPaperCheck.getNestedHeadNumber() + "个题"
+                                            + errorQuesNum + ImportPaperMsg.errMsg_14);
                         } else {
                             importPaperCheck.setErrorInfo(
                                     getQuesNumInfo(importPaperCheck, errorQuesNum) + ImportPaperMsg.errMsg_14);
                         }
                     }
                     throw new PaperException(importPaperCheck.getErrorInfo());
-            	}else {
-            		hasSeq=true;
-            	}
+                } else {
+                    hasSeq = true;
+                }
                 // 题干第一段
                 // 过滤题干标题
                 pBody = DocxProcessUtil.formatP(pBody, QuesUnit.QUES_BODY);
@@ -803,16 +805,16 @@ public class ImportPaperService {
                     importPaperCheck.setErrorInfo(importPaperCheck.getQuesName() + "第"
                             + importPaperCheck.getNestedHeadNumber() + "个题" + ImportPaperMsg.errMsg_01);
                 } else {
-                    importPaperCheck.setErrorInfo(
-                            getQuesNumInfo(importPaperCheck, errorQuesNum) + ImportPaperMsg.errMsg_01);
+                    importPaperCheck
+                            .setErrorInfo(getQuesNumInfo(importPaperCheck, errorQuesNum) + ImportPaperMsg.errMsg_01);
                 }
             } else {
                 if (importPaperCheck.getNestedHeadNumber() != 0) {
                     importPaperCheck.setErrorInfo(importPaperCheck.getQuesName() + "第"
                             + importPaperCheck.getNestedHeadNumber() + "个题" + errorQuesNum + ImportPaperMsg.errMsg_01);
                 } else {
-                    importPaperCheck.setErrorInfo(
-                            getQuesNumInfo(importPaperCheck, errorQuesNum) + ImportPaperMsg.errMsg_01);
+                    importPaperCheck
+                            .setErrorInfo(getQuesNumInfo(importPaperCheck, errorQuesNum) + ImportPaperMsg.errMsg_01);
                 }
             }
             throw new PaperException(importPaperCheck.getErrorInfo());
@@ -858,8 +860,8 @@ public class ImportPaperService {
                     importPaperCheck.setErrorInfo(importPaperCheck.getQuesName() + "第"
                             + importPaperCheck.getNestedHeadNumber() + "个题" + errorQuesNum + ImportPaperMsg.errMsg_11);
                 } else {
-                    importPaperCheck.setErrorInfo(
-                            getQuesNumInfo(importPaperCheck, errorQuesNum) + ImportPaperMsg.errMsg_11);
+                    importPaperCheck
+                            .setErrorInfo(getQuesNumInfo(importPaperCheck, errorQuesNum) + ImportPaperMsg.errMsg_11);
                 }
                 throw new PaperException(importPaperCheck.getErrorInfo());
             } else if (tmpText.matches("^[a-zA-Z]\\.[\\s\\S]*")) {
@@ -875,8 +877,8 @@ public class ImportPaperService {
                                 importPaperCheck.getQuesName() + "第" + importPaperCheck.getNestedHeadNumber() + "个题"
                                         + errorQuesNum + ":“" + errorMsg + "”" + ImportPaperMsg.errMsg_13);
                     } else {
-                        importPaperCheck.setErrorInfo(getQuesNumInfo(importPaperCheck, errorQuesNum)
-                                + ":“" + errorMsg + "”" + ImportPaperMsg.errMsg_13);
+                        importPaperCheck.setErrorInfo(getQuesNumInfo(importPaperCheck, errorQuesNum) + ":“" + errorMsg
+                                + "”" + ImportPaperMsg.errMsg_13);
                     }
                     throw new PaperException(importPaperCheck.getErrorInfo());
                 }
@@ -908,8 +910,7 @@ public class ImportPaperService {
                 importPaperCheck.setErrorInfo(importPaperCheck.getQuesName() + "第"
                         + importPaperCheck.getNestedHeadNumber() + "个题" + errorQuesNum + "中选项格式不正确或有缺失\n");
             } else {
-                importPaperCheck
-                        .setErrorInfo(getQuesNumInfo(importPaperCheck, errorQuesNum) + "中选项格式不正确或有缺失\n");
+                importPaperCheck.setErrorInfo(getQuesNumInfo(importPaperCheck, errorQuesNum) + "中选项格式不正确或有缺失\n");
             }
             throw new PaperException(importPaperCheck.getErrorInfo());
         } else {
@@ -1039,9 +1040,8 @@ public class ImportPaperService {
                     importPaperCheck.setErrorInfo(
                             getQuesNumInfo(importPaperCheck, subQuesNum) + "中,答案格式不正确,答案为:" + pList.get(i).toString());
                     throw new PaperException(importPaperCheck.getErrorInfo());
-                }else if(question.getQuestionType() == QuesStructType.BOOL_ANSWER_QUESTION){
-                    importPaperCheck.setErrorInfo(
-                            getQuesNumInfo(importPaperCheck, subQuesNum) + "中,答案格式不正确,应为:正确或错误");
+                } else if (question.getQuestionType() == QuesStructType.BOOL_ANSWER_QUESTION) {
+                    importPaperCheck.setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,答案格式不正确,应为:正确或错误");
                 }
             } else {
                 break;
@@ -1054,8 +1054,7 @@ public class ImportPaperService {
                 importPaperCheck.setErrorInfo(paperDetailUnit.getPaperDetail().getName() + "中,第"
                         + paperDetailUnit.getNumber() + "个套题的" + errorQuesNum + "小题中,缺失“[答案]”");
             } else {
-                importPaperCheck
-                        .setErrorInfo(getQuesNumInfo(importPaperCheck, errorQuesNum) + "中,缺失“[答案]”");
+                importPaperCheck.setErrorInfo(getQuesNumInfo(importPaperCheck, errorQuesNum) + "中,缺失“[答案]”");
             }
             throw new PaperException(importPaperCheck.getErrorInfo());
         }
@@ -1063,18 +1062,18 @@ public class ImportPaperService {
         if (StringUtils.isNotEmpty(answerHTML)) {
             if (question.getQuestionType() == QuesStructType.SINGLE_ANSWER_QUESTION
                     || question.getQuestionType() == QuesStructType.MULTIPLE_ANSWER_QUESTION
-                    ||question.getQuestionType() == QuesStructType.BOOL_ANSWER_QUESTION) {
+                    || question.getQuestionType() == QuesStructType.BOOL_ANSWER_QUESTION) {
                 question.setQuesAnswer(answerHTML.toString().replaceAll(" ", ""));
-            }else {
+            } else {
                 question.setQuesAnswer(answerHTML.toString());
             }
             question.setQuesAnswerWord(answerWordML.toString());
         } else {
             if (question.getQuestionType() == QuesStructType.SINGLE_ANSWER_QUESTION
                     || question.getQuestionType() == QuesStructType.MULTIPLE_ANSWER_QUESTION
-                    ||question.getQuestionType() == QuesStructType.BOOL_ANSWER_QUESTION) {
+                    || question.getQuestionType() == QuesStructType.BOOL_ANSWER_QUESTION) {
                 question.setQuesAnswer("");
-            }else {
+            } else {
                 question.setQuesAnswer("<p></p>");
             }
             question.setQuesAnswerWord(answerWordML.toString());
@@ -1117,8 +1116,7 @@ public class ImportPaperService {
             int subQuesNum, Paper paper, List<QuesProperty> quesProperties) throws Exception {
         // 一级属性为空,二级属性有值
         if (StringUtils.isBlank(firstProperty) && StringUtils.isNotBlank(secondProperty)) {
-                importPaperCheck
-                        .setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,小题一级属性值为空,请检查");
+            importPaperCheck.setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,小题一级属性值为空,请检查");
             throw new PaperException(importPaperCheck.getErrorInfo());
         }
         // 一级属性,二级属性都有值
@@ -1129,15 +1127,14 @@ public class ImportPaperService {
             List<CourseProperty> courseProperties = coursePropertyRepo
                     .findByCourseCodeAndEnable(paper.getCourse().getCode(), true);
             if (courseProperties == null || courseProperties.size() < 1) {
-                    importPaperCheck.setErrorInfo(
-                            getQuesNumInfo(importPaperCheck, subQuesNum) + "中,没有设置课程属性结构,请先设置课程属性结构");
+                importPaperCheck.setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,没有设置课程属性结构,请先设置课程属性结构");
                 throw new PaperException(importPaperCheck.getErrorInfo());
             }
 
             for (CourseProperty courseProperty : courseProperties) {
                 // 查询一级属性是否存在
                 Property proParent = propertyRepo.findByOrgIdAndCoursePropertyIdAndParentIdAndCode(
-                		Long.valueOf(paper.getOrgId()), courseProperty.getId(), Property.ROOT_PARENT_ID, firstProperty);
+                        Long.valueOf(paper.getOrgId()), courseProperty.getId(), Property.ROOT_PARENT_ID, firstProperty);
 
                 // 存在一级属性
                 if (proParent != null) {
@@ -1145,7 +1142,7 @@ public class ImportPaperService {
 
                     // 查询二级属性
                     Property proSon = propertyRepo.findByOrgIdAndCoursePropertyIdAndParentIdAndCode(
-                    		Long.valueOf(paper.getOrgId()), courseProperty.getId(), proParent.getId(), secondProperty);
+                            Long.valueOf(paper.getOrgId()), courseProperty.getId(), proParent.getId(), secondProperty);
 
                     // 存在二级属性
                     if (proSon != null) {
@@ -1162,14 +1159,14 @@ public class ImportPaperService {
             }
 
             if (isFirstEmpty) {
-                    importPaperCheck.setErrorInfo(
-                            getQuesNumInfo(importPaperCheck, subQuesNum) + "中,小题一级属性值与课程属性中一级属性不匹配,请检查");
+                importPaperCheck
+                        .setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,小题一级属性值与课程属性中一级属性不匹配,请检查");
                 throw new PaperException(importPaperCheck.getErrorInfo());
             }
 
             if (isSecondEmpty) {
-                    importPaperCheck.setErrorInfo(
-                            getQuesNumInfo(importPaperCheck, subQuesNum) + "中,小题二级属性值与课程属性中二级属性不匹配,请检查");
+                importPaperCheck
+                        .setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,小题二级属性值与课程属性中二级属性不匹配,请检查");
                 throw new PaperException(importPaperCheck.getErrorInfo());
             }
         } else if (StringUtils.isNotBlank(firstProperty) && StringUtils.isBlank(secondProperty)) {
@@ -1182,20 +1179,19 @@ public class ImportPaperService {
             List<CourseProperty> courseProperties = coursePropertyRepo
                     .findByCourseCodeAndEnable(paper.getCourse().getCode(), true);
             if (courseProperties == null || courseProperties.size() < 1) {
-                    importPaperCheck.setErrorInfo(
-                            getQuesNumInfo(importPaperCheck, subQuesNum) + "中,没有设置课程属性结构,请先设置课程属性结构");
+                importPaperCheck.setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,没有设置课程属性结构,请先设置课程属性结构");
                 throw new PaperException(importPaperCheck.getErrorInfo());
             }
 
             for (CourseProperty courseProperty : courseProperties) {
                 // 查询一级属性
                 Property proParent = propertyRepo.findByOrgIdAndCoursePropertyIdAndParentIdAndCode(
-                		Long.valueOf(paper.getOrgId()), courseProperty.getId(), Property.ROOT_PARENT_ID, firstProperty);
+                        Long.valueOf(paper.getOrgId()), courseProperty.getId(), Property.ROOT_PARENT_ID, firstProperty);
 
                 // 存在一级属性
                 if (proParent != null) {
                     isFirstEmpty = false;
-                        // 根据一级属性查询二级属性
+                    // 根据一级属性查询二级属性
                     List<Property> sonProperties = propertyRepo.findByParentIdOrderByNumber(proParent.getId());
 
                     // 存在二级属性,跳过
@@ -1213,14 +1209,14 @@ public class ImportPaperService {
                 }
             }
             if (isFirstEmpty) {
-                    importPaperCheck.setErrorInfo(
-                            getQuesNumInfo(importPaperCheck, subQuesNum) + "中,小题一级属性值与课程属性中一级属性不匹配,请检查");
+                importPaperCheck
+                        .setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,小题一级属性值与课程属性中一级属性不匹配,请检查");
                 throw new PaperException(importPaperCheck.getErrorInfo());
             }
 
             if (isSecondEmpty) {
-                    importPaperCheck.setErrorInfo(
-                            getQuesNumInfo(importPaperCheck, subQuesNum) + "中,小题二级属性值与课程属性中二级属性不匹配,请检查");
+                importPaperCheck
+                        .setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,小题二级属性值与课程属性中二级属性不匹配,请检查");
                 throw new PaperException(importPaperCheck.getErrorInfo());
             }
         } else {
@@ -1239,26 +1235,22 @@ public class ImportPaperService {
     private void checkAttributeIsFull(String firstProperty, String secondProperty, Double difficulty, Boolean publicity,
             ImportPaperCheck importPaperCheck, int subQuesNum) throws Exception {
         if (firstProperty == null) {
-                importPaperCheck
-                        .setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,小题一级属性缺失,请检查");
+            importPaperCheck.setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,小题一级属性缺失,请检查");
             throw new PaperException(importPaperCheck.getErrorInfo());
         }
 
         if (secondProperty == null) {
-                importPaperCheck
-                        .setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,小题二级属性缺失,请检查");
+            importPaperCheck.setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,小题二级属性缺失,请检查");
             throw new PaperException(importPaperCheck.getErrorInfo());
         }
 
         if (difficulty == null) {
-                importPaperCheck
-                        .setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,小题难度缺失,请检查");
+            importPaperCheck.setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,小题难度缺失,请检查");
             throw new PaperException(importPaperCheck.getErrorInfo());
         }
 
         if (publicity == null) {
-                importPaperCheck
-                        .setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,小题公开性缺失,请检查");
+            importPaperCheck.setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,小题公开性缺失,请检查");
             throw new PaperException(importPaperCheck.getErrorInfo());
         }
     }
@@ -1375,11 +1367,11 @@ public class ImportPaperService {
                 hasQuesType = false;
             } else if (subQuesNum != quesTypeNum) {
                 if (StringUtils.isEmpty(nestedQuesType)) {
-                    importPaperCheck.setErrorInfo(
-                            getQuesNumInfo(importPaperCheck, quesTypeNum) + ImportPaperMsg.errMsg_02);
+                    importPaperCheck
+                            .setErrorInfo(getQuesNumInfo(importPaperCheck, quesTypeNum) + ImportPaperMsg.errMsg_02);
                 } else {
-                    importPaperCheck.setErrorInfo(
-                            getQuesNumInfo(importPaperCheck, quesTypeNum) + ImportPaperMsg.errMsg_03);
+                    importPaperCheck
+                            .setErrorInfo(getQuesNumInfo(importPaperCheck, quesTypeNum) + ImportPaperMsg.errMsg_03);
                 }
                 throw new PaperException(importPaperCheck.getErrorInfo());
             } else if (isHeader(tmpText)) {
@@ -1497,11 +1489,10 @@ public class ImportPaperService {
      */
     public static String getQuesNumInfo(ImportPaperCheck importPaperCheck, int subQuesNum) {
         if (importPaperCheck.getNestedHeadNumber() == 0) {
-        	return "[大题名称]:" + importPaperCheck.getQuesName() + "第" + subQuesNum + "小题";
+            return "[大题名称]:" + importPaperCheck.getQuesName() + "第" + subQuesNum + "小题";
         } else {
-        	return "[大题名称]:" + importPaperCheck.getQuesName() + "第"
-                    + importPaperCheck.getNestedHeadNumber() + "小题,第" + subQuesNum
-                    + "子题";
+            return "[大题名称]:" + importPaperCheck.getQuesName() + "第" + importPaperCheck.getNestedHeadNumber() + "小题,第"
+                    + subQuesNum + "子题";
         }
     }
 
@@ -1654,9 +1645,9 @@ public class ImportPaperService {
     private void checkSelectAnswer(Question question, String answerWord, ImportPaperCheck importPaperCheck,
             int subQuesNum) throws PaperException {
         if (!StringUtils.isBlank(answerWord)) {
-            if (question.getQuestionType() == QuesStructType.SINGLE_ANSWER_QUESTION&&answerWord.contains(",")) {
-                importPaperCheck.setErrorInfo(
-                        getQuesNumInfo(importPaperCheck, subQuesNum) + "中,答案格式不正确,答案为:" + answerWord);
+            if (question.getQuestionType() == QuesStructType.SINGLE_ANSWER_QUESTION && answerWord.contains(",")) {
+                importPaperCheck
+                        .setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,答案格式不正确,答案为:" + answerWord);
                 throw new PaperException(importPaperCheck.getErrorInfo());
             }
             String[] pAnswerArray = answerWord.split(",");
@@ -1671,8 +1662,8 @@ public class ImportPaperService {
                 answer = answer.trim();
                 String pattern = "[A-Z]|[a-z]";
                 if (!Pattern.matches(pattern, answer)) {
-                    importPaperCheck.setErrorInfo(
-                            getQuesNumInfo(importPaperCheck, subQuesNum) + "中,答案格式不正确,答案为:" + answerWord);
+                    importPaperCheck
+                            .setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,答案格式不正确,答案为:" + answerWord);
                     throw new PaperException(importPaperCheck.getErrorInfo());
                 }
                 if (!optionNumList.contains(answer)) {
@@ -1698,8 +1689,7 @@ public class ImportPaperService {
             if (tmpText.equals("正确") || tmpText.equals("错误")) {
                 return;
             } else {
-                importPaperCheck.setErrorInfo(
-                        getQuesNumInfo(importPaperCheck, subQuesNum) + "中,答案格式不正确,应为:正确或错误");
+                importPaperCheck.setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,答案格式不正确,应为:正确或错误");
                 throw new PaperException(importPaperCheck.getErrorInfo());
             }
         }
@@ -1717,8 +1707,7 @@ public class ImportPaperService {
             question.setDifficulty("中");
         } else if (!isInteger(tmpText) || (Double.parseDouble(tmpText) < 1) || (Double.parseDouble(tmpText) > 10)) {
             // 如果不是整数,或者在1到10之间,就报错
-            importPaperCheck
-                    .setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,试题难度只能是1到10之间整数");
+            importPaperCheck.setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,试题难度只能是1到10之间整数");
             throw new PaperException(importPaperCheck.getErrorInfo());
         } else {
             tempDifficulty = Double.parseDouble(tmpText) / 10;
@@ -1748,8 +1737,7 @@ public class ImportPaperService {
             publicity = true;
         } else if (!tmpText.equals("公开") && !tmpText.equals("非公开")) {
             // 如果不是公开和非公开,就报错
-            importPaperCheck
-                    .setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,试题公开度只能是公开和非公开");
+            importPaperCheck.setErrorInfo(getQuesNumInfo(importPaperCheck, subQuesNum) + "中,试题公开度只能是公开和非公开");
             throw new PaperException(importPaperCheck.getErrorInfo());
         } else {
             if (tmpText.equals("非公开")) {
@@ -1835,7 +1823,7 @@ public class ImportPaperService {
      */
     private static String getContent(String pText, String replaceContent) {
         String word = replaceContent.replace("[", "").replace("]", "");
-        return pText.replaceAll("\\[" + word + "\\]", "").replaceAll("[::]", "").trim();
+        return pText.replaceFirst("\\[" + word + "\\]", "").replaceFirst("[::]", "").trim();
     }
 
     /**
@@ -1919,11 +1907,13 @@ public class ImportPaperService {
             User user) {
         Question oldQuestion = oldPaperDetailUnit.getQuestion();
         Question newQuestion = BeanCopierUtil.copyProperties(oldQuestion, Question.class);
-//        QuestionPkgPath oldQuesPkgPath = quesPkgPathRepo.findFirstById(oldQuestion.getQuesPkgPathId());
-//        QuestionPkgPath newQuestionPkgPath = BeanCopierUtil.copyProperties(oldQuesPkgPath, QuestionPkgPath.class);
-//        newQuestionPkgPath.setId(null);
-//        newQuestionPkgPath = quesPkgPathRepo.save(newQuestionPkgPath);
-//        newQuestion.setQuesPkgPathId(newQuestionPkgPath.getId());
+        // QuestionPkgPath oldQuesPkgPath =
+        // quesPkgPathRepo.findFirstById(oldQuestion.getQuesPkgPathId());
+        // QuestionPkgPath newQuestionPkgPath =
+        // BeanCopierUtil.copyProperties(oldQuesPkgPath, QuestionPkgPath.class);
+        // newQuestionPkgPath.setId(null);
+        // newQuestionPkgPath = quesPkgPathRepo.save(newQuestionPkgPath);
+        // newQuestion.setQuesPkgPathId(newQuestionPkgPath.getId());
         newQuestion.setCourse(course);
         newQuestion.setId(null);
         newQuestion.setQuesProperties(null);
@@ -1931,86 +1921,87 @@ public class ImportPaperService {
         newQuestion = quesRepo.save(newQuestion);
         // 复制音频
         if (oldQuestion.getHasAudio() != null && oldQuestion.getHasAudio()) {
-//            try {
-                // 查询旧音频
-                List<QuestionAudio> oldQuestionAudios = questionAudioService
-                        .findQuestionAudiosByQuestionId(oldQuestion.getId());
-                // 复制文件下载路径
-                String copyAudioPath = TEMP_FILE_EXP + File.separator + user.getDisplayName() + "_copyAudioPath";
-                // 新建文件夹
-                File copyAudioDir = new File(copyAudioPath);
-                if (!copyAudioDir.exists()) {
-                    copyAudioDir.mkdirs();
+            // try {
+            // 查询旧音频
+            List<QuestionAudio> oldQuestionAudios = questionAudioService
+                    .findQuestionAudiosByQuestionId(oldQuestion.getId());
+            // 复制文件下载路径
+            String copyAudioPath = TEMP_FILE_EXP + File.separator + user.getDisplayName() + "_copyAudioPath";
+            // 新建文件夹
+            File copyAudioDir = new File(copyAudioPath);
+            if (!copyAudioDir.exists()) {
+                copyAudioDir.mkdirs();
+            }
+            for (QuestionAudio oldAudio : oldQuestionAudios) {
+                // 生成随机数,防止文件重名
+                int randomNumber = random.nextInt(1000);
+                // 定义文件下载名称,下载音频文件
+                String newAudioFileName = newQuestion.getId() + "_" + randomNumber + "_" + oldAudio.getFileName();
+
+                // 下载音频
+                File audioFile = new File(copyAudioPath + File.separator + newAudioFileName);
+                try {
+                    String filePath = FssHelper.fixFilePath(oldAudio.getFileUrl());
+                    FssFactory.getInstance().readFile(filePath, audioFile);
+                } catch (Exception e) {
+                    log.error(e.getMessage(), e);
+                    throw new RuntimeException("下载音频失败");
                 }
-                for (QuestionAudio oldAudio : oldQuestionAudios) {
-                    // 生成随机数,防止文件重名
-                    int randomNumber = random.nextInt(1000);
-                    // 定义文件下载名称,下载音频文件
-                    String newAudioFileName = newQuestion.getId() + "_" + randomNumber + "_" + oldAudio.getFileName();
-
-                    // 下载音频
-                    File audioFile = new File(copyAudioPath + File.separator + newAudioFileName);
-                    try {
-                        String filePath = FssHelper.fixFilePath(oldAudio.getFileUrl());
-                        FssFactory.getInstance().readFile(filePath, audioFile);
-                    } catch (Exception e) {
-                        log.error(e.getMessage(), e);
-                        throw new RuntimeException("下载音频失败");
+                // 重新上传新的音频文件
+                String newPath = String.format(FileConstants.RADIO_UPLOAD_PATH, newAudioFileName);
+                FssFileInfo result = FssFactory.getInstance().writeFile(newPath, audioFile, null);
+
+                IoUtils.removeFile(audioFile);
+
+                // 拷贝旧对象
+                QuestionAudio newAudio = new QuestionAudio(newQuestion.getId(), oldAudio.getFileName(),
+                        result.getFileUrl());
+                newAudio.setCreateTime(new Date());
+                newAudio.setCreateUser(user.getDisplayName());
+                questionAudioService.saveQuestionAudio(newAudio, user);
+            }
+            // 删除文件夹
+            IoUtils.removeFile(copyAudioDir);
+
+            // 查询新音频
+            List<QuestionAudio> newQuestionAudios = questionAudioService
+                    .findQuestionAudiosByQuestionId(newQuestion.getId());
+            Map<String, String> newMap = new HashMap<>();
+            for (QuestionAudio audio : newQuestionAudios) {
+                newMap.put(audio.getFileName(), audio.getId());
+            }
+            // 在题干html片段中替换音频存储id
+            String body = newQuestion.getQuesBody();
+            List<String> ids = CommonUtils.getTagANames(body);
+            List<String> names = CommonUtils.getTagANames2(body);
+            Map<String, String> oldBodyMap = new HashMap<>();
+            for (int i = 0; i < ids.size(); i++) {
+                oldBodyMap.put(names.get(i), ids.get(i));
+            }
+            for (String key : oldBodyMap.keySet()) {
+                body = body.replace(oldBodyMap.get(key), newMap.get(key));
+            }
+            newQuestion.setQuesBody(body);
+            // 替换选项中的音频存储id
+            if (newQuestion.getQuesOptions() != null && newQuestion.getQuesOptions().size() > 0) {
+                for (QuesOption option : newQuestion.getQuesOptions()) {
+                    String newOptionBody = option.getOptionBody();
+                    List<String> optionIds = CommonUtils.getTagANames(newOptionBody);
+                    List<String> optionNames = CommonUtils.getTagANames2(newOptionBody);
+                    Map<String, String> oldOptionMap = new HashMap<>();
+                    for (int i = 0; i < optionIds.size(); i++) {
+                        oldOptionMap.put(optionNames.get(i), optionIds.get(i));
                     }
-                    // 重新上传新的音频文件
-                    String newPath = String.format(FileConstants.RADIO_UPLOAD_PATH, newAudioFileName);
-                    FssFileInfo result = FssFactory.getInstance().writeFile(newPath, audioFile, null);
-
-                    IoUtils.removeFile(audioFile);
-
-                    // 拷贝旧对象
-                    QuestionAudio newAudio = new QuestionAudio(newQuestion.getId(), oldAudio.getFileName(),result.getFileUrl());
-                    newAudio.setCreateTime(new Date());
-                    newAudio.setCreateUser(user.getDisplayName());
-                    questionAudioService.saveQuestionAudio(newAudio, user);
-                }
-                // 删除文件夹
-                IoUtils.removeFile(copyAudioDir);
-
-                // 查询新音频
-                List<QuestionAudio> newQuestionAudios = questionAudioService
-                        .findQuestionAudiosByQuestionId(newQuestion.getId());
-                Map<String, String> newMap = new HashMap<>();
-                for (QuestionAudio audio : newQuestionAudios) {
-                    newMap.put(audio.getFileName(), audio.getId());
-                }
-                // 在题干html片段中替换音频存储id
-                String body = newQuestion.getQuesBody();
-                List<String> ids = CommonUtils.getTagANames(body);
-                List<String> names = CommonUtils.getTagANames2(body);
-                Map<String, String> oldBodyMap = new HashMap<>();
-                for (int i = 0; i < ids.size(); i++) {
-                    oldBodyMap.put(names.get(i), ids.get(i));
-                }
-                for (String key : oldBodyMap.keySet()) {
-                    body = body.replace(oldBodyMap.get(key), newMap.get(key));
-                }
-                newQuestion.setQuesBody(body);
-                // 替换选项中的音频存储id
-                if (newQuestion.getQuesOptions() != null && newQuestion.getQuesOptions().size() > 0) {
-                    for (QuesOption option : newQuestion.getQuesOptions()) {
-                        String newOptionBody = option.getOptionBody();
-                        List<String> optionIds = CommonUtils.getTagANames(newOptionBody);
-                        List<String> optionNames = CommonUtils.getTagANames2(newOptionBody);
-                        Map<String, String> oldOptionMap = new HashMap<>();
-                        for (int i = 0; i < optionIds.size(); i++) {
-                            oldOptionMap.put(optionNames.get(i), optionIds.get(i));
-                        }
-                        for (String key : oldOptionMap.keySet()) {
-                            newOptionBody = newOptionBody.replace(oldOptionMap.get(key), newMap.get(key));
-                        }
-                        option.setOptionBody(newOptionBody);
+                    for (String key : oldOptionMap.keySet()) {
+                        newOptionBody = newOptionBody.replace(oldOptionMap.get(key), newMap.get(key));
                     }
+                    option.setOptionBody(newOptionBody);
                 }
-                newQuestion = quesRepo.save(newQuestion);
-//            } catch (IOException e) {
-//                log.error(e.getMessage(), e);
-//            }
+            }
+            newQuestion = quesRepo.save(newQuestion);
+            // } catch (IOException e) {
+            // log.error(e.getMessage(), e);
+            // }
         }
         paperDetailUnit.setQuestion(newQuestion);
     }
@@ -2040,17 +2031,16 @@ public class ImportPaperService {
      */
     public void processFill(Question question, PaperDetailUnit paperDetailUnit, ImportPaperCheck importPaperCheck,
             int subQuesNum, int errorQuesNum) throws PaperException {
-    	if(!question.getQuesBody().contains("###")) {
-    		if (importPaperCheck.getNestedHeadNumber() == 0) {
-                importPaperCheck.setErrorInfo(
-                        "[大题名称]:" + importPaperCheck.getQuesName() + "第" + errorQuesNum + "题中,题干中没有空格");
+        if (!question.getQuesBody().contains("###")) {
+            if (importPaperCheck.getNestedHeadNumber() == 0) {
+                importPaperCheck
+                        .setErrorInfo("[大题名称]:" + importPaperCheck.getQuesName() + "第" + errorQuesNum + "题中,题干中没有空格");
             } else {
                 importPaperCheck.setErrorInfo("[大题名称]:" + importPaperCheck.getQuesName() + "第"
-                        + importPaperCheck.getNestedHeadNumber() + "个套题中,第" + errorQuesNum
-                        + "题中,题干中没有空格");
+                        + importPaperCheck.getNestedHeadNumber() + "个套题中,第" + errorQuesNum + "题中,题干中没有空格");
             }
             throw new PaperException(importPaperCheck.getErrorInfo());
-    	}
+        }
         // 按3个#号截取题干
         String[] quesBody = question.getQuesBody().split("###");
         String[] quesAnwser = question.getQuesAnswer().split("##");

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

@@ -125,23 +125,24 @@ public class ExportPaperServiceImpl implements ExportPaperService {
 
     @Autowired
     private PaperDetailUnitRepo paperDetailUnitRepo;
-    
+
     @Autowired
     private ExportThemisPaperService exportThemisPaperService;
 
-//    @Autowired
-//    protected QuesPkgPathRepo quesPkgPathRepo;
+    // @Autowired
+    // protected QuesPkgPathRepo quesPkgPathRepo;
 
-//    @Autowired
-//    private SysProperty sysProperty;
+    // @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());
+    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();
+        String zipFileName = IdUtils.uuid();
         long startTime;
         try {
             File directory = new File(TEMP_FILE_EXP + File.separator + zipFileName);
@@ -155,12 +156,13 @@ public class ExportPaperServiceImpl implements ExportPaperService {
                 downJson(paper, zipFileName);
             }
             if (exportContentList.indexOf(ExamFileType.THEMIS_PACKAGE.name()) > -1) {
-            	List<Paper> papers=new ArrayList<>();
-            	papers.add(paper);
+                List<Paper> papers = new ArrayList<>();
+                papers.add(paper);
                 downThemisPackage(papers, zipFileName);
             }
             try {
-            	DownloadPaperDto dto=new DownloadPaperDto(user.getRootOrgId(), paperId, zipFileName, examType,seqMode);
+                DownloadPaperDto dto = new DownloadPaperDto(user.getRootOrgId(), paperId, zipFileName, examType,
+                        seqMode);
                 if (exportContentList.indexOf(ExamFileType.PAPER.name()) > -1) {
                     exportPaperAbstractService.downloadPaper(dto);
                 }
@@ -190,106 +192,121 @@ public class ExportPaperServiceImpl implements ExportPaperService {
             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);
+            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()));
+        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();
+        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);
-//        }
-//    }
+    // @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";
+        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);
-		}
+            // 新建文件夹
+            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";
+        String zipDirectory = TEMP_FILE_EXP + File.separator + zipFileName + File.separator + "themis_package";
         // 新建文件夹
         File dirFile = new File(zipDirectory);
         if (!dirFile.exists()) {
-        	dirFile.mkdirs();
+            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);
-		}
+            for (Paper paper : papers) {
+                ThemisPaperAndAnswer pa = null;
+                try {
+                    pa = exportThemisPaperService.buildPaperAndAnswer(paper);
+                } catch (StatusException e) {
+                    throw new StatusException("500", "试卷 " + paper.getName() + " " + e.getDesc(), e);
+                }
+                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) {
@@ -348,7 +365,8 @@ public class ExportPaperServiceImpl implements ExportPaperService {
                                                             + computerTestOption.getNumber() + "_" + optionNum + "."
                                                             + questionAudio.getFileSuffixes();
 
-                                                    File file = new File(jsonDirectory + File.separator + audioFileName);
+                                                    File file = new File(
+                                                            jsonDirectory + File.separator + audioFileName);
 
                                                     String filePath = FssHelper.fixFilePath(questionAudio.getFileUrl());
                                                     FssFactory.getInstance().readFile(filePath, file);
@@ -565,7 +583,7 @@ public class ExportPaperServiceImpl implements ExportPaperService {
      * @param jsonDirectoryPath
      */
     @SuppressWarnings("deprecation")
-	private void makeComputerTestPaperToJsonFile(String courseCode, ComputerTestPaper computerTestPaper,
+    private void makeComputerTestPaperToJsonFile(String courseCode, ComputerTestPaper computerTestPaper,
             String jsonDirectoryPath) {
         // 创建新的JSON文件
         File file = new File(jsonDirectoryPath + File.separator + courseCode + ".json");
@@ -591,53 +609,57 @@ public class ExportPaperServiceImpl implements ExportPaperService {
     }
 
     @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());
+    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()));
-    
+            // 创建压缩文件夹
+            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
@@ -932,26 +954,33 @@ public class ExportPaperServiceImpl implements ExportPaperService {
 
     @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);
-//        }
+        // 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);
+        // }
     }
 
     /**
@@ -960,24 +989,25 @@ public class ExportPaperServiceImpl implements ExportPaperService {
      * @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);
-//    }
+    // 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 {
@@ -1099,41 +1129,48 @@ public class ExportPaperServiceImpl implements ExportPaperService {
     }
 
     @Override
-    public void downOriginalPaperPlus(String paperId, Long rootOrgId, HttpServletResponse response) throws IOException{
+    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();
+        // File docxDir = new File(JsonExportUtil.getDocxBasePath());
+        // // 将要生成的doc源文件目录
+        // File docxTargetDir = new File(directory.getAbsolutePath() +
+        // "/docx/");
+        // docxTargetDir.mkdir();
         try {
             // 复制docx基础文件
-//            FileUtils.copyDirectory(docxDir, docxTargetDir);
+            // 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源文件
+            // 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.fileToZip(docfile.getParentFile().getAbsolutePath(), directory.getAbsolutePath(),
+                    zipFileName);
             // 下载文件
             FileDisposeUtil.downloadFile(paperExp.getName() + "_" + paperExp.getCourse().getCode() + ".zip",
                     directory.getAbsolutePath() + File.separator + zipFileName + ".zip", response);
@@ -1143,141 +1180,153 @@ public class ExportPaperServiceImpl implements ExportPaperService {
 
     }
 
-//    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;
-//    }
+    // 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;
+    // }
 }

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

@@ -11,8 +11,6 @@ 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;
@@ -28,6 +26,7 @@ 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;
@@ -46,7 +45,6 @@ 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;
@@ -54,782 +52,830 @@ import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisPaperDetai
 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;
+import cn.com.qmth.examcloud.core.questions.service.themispaper.ThemisSubjectiveAnswer;
+import cn.com.qmth.examcloud.support.fss.FssFactory;
+import cn.com.qmth.examcloud.support.fss.FssHelper;
 
 @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();
+    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();
+                        if (body != null) {
+                            List<ThemisSection> sections = body.getSections();
+                            if (sections != null && sections.size() > 0) {
+                                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();
+                                if (optionBody != null) {
+                                    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("500",
+                            "第" + paperDetail.getNumber() + "大题,第" + paperDetailUnit.getNumber() + "小题 " + e.getDesc(),
+                            e);
+                }
+            }
+            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)+"__");
+            matcher.appendReplacement(buffer, "__" + matcher.group(1) + "__");
         }
-        //fixbug
+        // 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;
-	}
+    }
+
+    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);
+                disposeIamgeUrlToBase64(block);
+                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("音频标签错误");
+                    }
+                    if (!questionAudio.getFileSuffixes().trim().equals("mp3")) {
+                        throw new StatusException("音频文件格式只能是MP3");
+                    }
+                    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 void disposeIamgeUrlToBase64(ThemisBlock block) {
+        if (!"image".equals(block.getType())) {
+            return;
+        }
+        String src = block.getValue().toString().trim().toLowerCase();
+        if (!src.startsWith("http://") && !src.startsWith("https://")) {
+            return;
+        }
+        block.setValue(FileUtil.imageUrlToBase64(src));
+    }
+
+    /**
+     * 获取图片里面的路径,长度,宽度
+     */
+    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;
+    }
 }

+ 234 - 215
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/impl/PaperDetailUnitServiceImpl.java

@@ -2,6 +2,8 @@ package cn.com.qmth.examcloud.core.questions.service.impl;
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 
 import org.apache.commons.collections4.CollectionUtils;
@@ -52,18 +54,22 @@ import cn.com.qmth.examcloud.reports.commons.util.ReportsUtil;
  */
 @Service("paperDetailUnitService")
 public class PaperDetailUnitServiceImpl implements PaperDetailUnitService {
+
     @Autowired
     PaperRepo paperRepo;
+
     @Autowired
     private ExtractConfigPaperCache extractConfigPaperCache;
+
     @Autowired
     private BasePaperCache basePaperCache;
+
     @Autowired
     private QuestionCache questionCache;
+
     @Autowired
     private QuestionAnswerCache questionAnswerCache;
-    
-    
+
     @Autowired
     PaperDetailUnitRepo paperDetailUnitRepo;
 
@@ -78,9 +84,10 @@ public class PaperDetailUnitServiceImpl implements PaperDetailUnitService {
 
     @Autowired
     RedisTemplate<String, Object> redisTemplate;
+
     @Autowired
     private RandomPaperQuestionService randomPaperQuestionService;
-    
+
     /**
      * 根据Id获得对应的试题对象
      *
@@ -100,86 +107,89 @@ public class PaperDetailUnitServiceImpl implements PaperDetailUnitService {
     public PaperDetailUnit findById(String id) {
         return Model.of(paperDetailUnitRepo.findById(id));
     }
+
     private void checkFillBlankQuestion(Question question) {
-    	if(question.getQuestionType() == QuesStructType.FILL_BLANK_QUESTION) {
-    		String body=question.getQuesBody();
-    		Document bodyDoc = Jsoup.parse(body);
-    		if(bodyDoc.body().childrenSize()==0) {
-    			throw new StatusException("1000", "题干不能为空");
-    		}
-	        String bodyText=bodyDoc.body().html();
-	        if(StringUtils.isBlank(bodyText)) {
-	        	throw new StatusException("1001", "题干不能为空");
-	        }
-	        if(bodyText.indexOf("###")==-1) {
-	        	throw new StatusException("1002", "题干不能没有空格(###)");
-	        }
-	        String answer=question.getQuesAnswer();
-	        Document answerDoc = Jsoup.parse(answer);
-	        if(answerDoc.body().childrenSize()!=0) {
-		        String answerText=answerDoc.body().html();
-		        if(StringUtils.isNotBlank(answerText)) {
-		        	if(getSubStringCount(bodyText, "###")!=answerText.split("##").length) {
-		        		throw new StatusException("1003", "题干空格(###)数量和答案数量不一致");
-		        	}
-		        }
-	        }
-    	}
+        if (question.getQuestionType() == QuesStructType.FILL_BLANK_QUESTION) {
+            String body = question.getQuesBody();
+            Document bodyDoc = Jsoup.parse(body);
+            if (bodyDoc.body().childrenSize() == 0) {
+                throw new StatusException("1000", "题干不能为空");
+            }
+            String bodyText = bodyDoc.body().html();
+            if (StringUtils.isBlank(bodyText)) {
+                throw new StatusException("1001", "题干不能为空");
+            }
+            if (bodyText.indexOf("###") == -1) {
+                throw new StatusException("1002", "题干不能没有空格(###)");
+            }
+            String answer = question.getQuesAnswer();
+            Document answerDoc = Jsoup.parse(answer);
+            if (answerDoc.body().childrenSize() != 0) {
+                String answerText = answerDoc.body().html();
+                if (StringUtils.isNotBlank(answerText)) {
+                    if (getSubStringCount(bodyText, "###") != answerText.split("##").length) {
+                        throw new StatusException("1003", "题干空格(###)数量和答案数量不一致");
+                    }
+                }
+            }
+        }
+    }
+
+    private int getSubStringCount(String src, String find) {
+        int o = 0;
+        int index = -1;
+        while ((index = src.indexOf(find, index)) > -1) {
+            ++index;
+            ++o;
+        }
+        return o;
     }
-    private int getSubStringCount(String src,String find){
-    	int o = 0;
-    	int index=-1;
-    	while((index=src.indexOf(find,index))>-1){
-	    	++index;
-	    	++o;
-    	}
-		return o;
-	}
-    
+
     @Override
     public boolean paperInUse(String questionId) {
-    	 Query query = new Query();
-         query.addCriteria(Criteria.where("question.$id").is(new ObjectId(questionId)));
-         query.addCriteria(Criteria.where("paperType").is(PaperType.GENERATE.name()));
-         List<PaperDetailUnitDto> units=this.mongoTemplate.find(query, PaperDetailUnitDto.class,"paperDetailUnit");
-         if(CollectionUtils.isEmpty(units)) {
-        	 return false;
-         }
-         for(PaperDetailUnitDto dto:units) {
-        	 if(dto.getPaper().getInUse()!=null&&dto.getPaper().getInUse()==1) {
-        		 return true;
-        	 }
-         }
-         return false;
+        Query query = new Query();
+        query.addCriteria(Criteria.where("question.$id").is(new ObjectId(questionId)));
+        query.addCriteria(Criteria.where("paperType").is(PaperType.GENERATE.name()));
+        List<PaperDetailUnitDto> units = this.mongoTemplate.find(query, PaperDetailUnitDto.class, "paperDetailUnit");
+        if (CollectionUtils.isEmpty(units)) {
+            return false;
+        }
+        for (PaperDetailUnitDto dto : units) {
+            if (dto.getPaper().getInUse() != null && dto.getPaper().getInUse() == 1) {
+                return true;
+            }
+        }
+        return false;
     }
+
     /**
      * 保存小题
      */
     public PaperDetailUnit savePaperDetailUnit(PaperDetailUnitExp updateUnit, User user) {
-    	StringBuilder sb=new StringBuilder();
+        StringBuilder sb = new StringBuilder();
         PaperDetailUnit baseUnit = Model.of(paperDetailUnitRepo.findById(updateUnit.getId()));
-        if(paperInUse(baseUnit.getQuestion().getId())) {
-        	PaperUtil.checkUpdate(updateUnit, baseUnit,"试卷已调用,");
+        if (paperInUse(baseUnit.getQuestion().getId())) {
+            PaperUtil.checkUpdate(updateUnit, baseUnit, "试卷已调用,");
         }
-        if(randomPaperQuestionService.existQuestion(baseUnit.getQuestion().getId())) {
-        	PaperUtil.checkUpdateOption(updateUnit, baseUnit,"小题已被抽题模板使用,");
+        if (randomPaperQuestionService.existQuestion(baseUnit.getQuestion().getId())) {
+            PaperUtil.checkUpdateOption(updateUnit, baseUnit, "小题已被抽题模板使用,");
         }
         Question baseQuestion = baseUnit.getQuestion();
         Question updateQuestion = updateUnit.getQuestion();
         checkFillBlankQuestion(updateQuestion);
         if (baseUnit.getQuestionType() == QuesStructType.NESTED_ANSWER_QUESTION) {
             if (updateQuestion.getId().equals(baseQuestion.getId())) {
-            	
-            	if(!StringUtils.equals(baseQuestion.getQuesBody(), updateQuestion.getQuesBody())) {
-            		sb.append(" 第"+baseUnit.getNumber()+"小题(套题)题干变动");
-            	}
+
+                if (!StringUtils.equals(baseQuestion.getQuesBody(), updateQuestion.getQuesBody())) {
+                    sb.append(" 第" + baseUnit.getNumber() + "小题(套题)题干变动");
+                }
                 // 更新对象为套题本身
                 quesService.saveQues(updateQuestion);
                 baseUnit.setQuestion(updateQuestion);
             } else {
-            	if(updateQuestion.getQuesOptions()!=null&&updateQuestion.getQuesOptions().size()>26) {
-            		throw new StatusException("选项数量不能超过26");
-            	}
+                if (updateQuestion.getQuesOptions() != null && updateQuestion.getQuesOptions().size() > 26) {
+                    throw new StatusException("选项数量不能超过26");
+                }
                 List<Double> subScoreList = baseUnit.getSubScoreList();
                 int size = baseQuestion.getSubQuestions().size();
                 boolean match = false;
@@ -193,21 +203,21 @@ public class PaperDetailUnitServiceImpl implements PaperDetailUnitService {
 
                     Question sub = baseQuestion.getSubQuestions().get(index - 1);
                     if (updateQuestion.getId().equals(sub.getId())) {
-                    	String changInfo=getQuestionChangeInfo(sub, updateQuestion);
-                    	if(changInfo!=null) {
-                    		sb.append("第"+baseUnit.getNumber()+"小题第"+index+"子题变动:"+changInfo);
-                    	}
+                        String changInfo = getQuestionChangeInfo(sub, updateQuestion);
+                        if (changInfo != null) {
+                            sb.append("第" + baseUnit.getNumber() + "小题第" + index + "子题变动:" + changInfo);
+                        }
                         // 匹配到子题
                         subScoreList.set(index - 1, updateUnit.getScore());
                         baseQuestion.getSubQuestions().set(index - 1, updateQuestion);
 
-                        //重新计算套题的难度,公开度
+                        // 重新计算套题的难度,公开度
                         boolean publicity = false;
                         double totalSum = 0d;
                         double totalDou = 0d;
                         for (int i = 0; i < baseQuestion.getSubQuestions().size(); i++) {
                             Question subQuestion = baseQuestion.getSubQuestions().get(i);
-                            //设置公开度
+                            // 设置公开度
                             if (subQuestion.getPublicity()) {
                                 publicity = true;
                             }
@@ -243,13 +253,13 @@ public class PaperDetailUnitServiceImpl implements PaperDetailUnitService {
                 baseUnit.setSubScoreList(subScoreList);
             }
         } else {
-        	if(updateQuestion.getQuesOptions()!=null&&updateQuestion.getQuesOptions().size()>26) {
-        		throw new StatusException("选项数量不能超过26");
-        	}
-        	String changInfo=getQuestionChangeInfo(baseQuestion, updateQuestion);
-        	if(changInfo!=null) {
-        		sb.append("第"+baseUnit.getNumber()+"小题变动:"+changInfo);
-        	}
+            if (updateQuestion.getQuesOptions() != null && updateQuestion.getQuesOptions().size() > 26) {
+                throw new StatusException("选项数量不能超过26");
+            }
+            String changInfo = getQuestionChangeInfo(baseQuestion, updateQuestion);
+            if (changInfo != null) {
+                sb.append("第" + baseUnit.getNumber() + "小题变动:" + changInfo);
+            }
             quesService.saveQues(updateQuestion);
             baseUnit.setQuestion(updateQuestion);
             baseUnit.setScore(updateUnit.getScore());
@@ -259,73 +269,75 @@ public class PaperDetailUnitServiceImpl implements PaperDetailUnitService {
         paperDetailUnitRepo.save(baseUnit);
 
         Paper paper = baseUnit.getPaper();
-        Double total=paper.getTotalScore();
-        Integer dc=paper.getPaperDetailCount();
-        Integer uc=paper.getUnitCount();
-        if(PaperType.GENERATE.equals(paper.getPaperType())) {
-        	paper.setAuditStatus(false);
+        Double total = paper.getTotalScore();
+        Integer dc = paper.getPaperDetailCount();
+        Integer uc = paper.getUnitCount();
+        if (PaperType.GENERATE.equals(paper.getPaperType())) {
+            paper.setAuditStatus(false);
         }
         paperService.formatPaper(paper, user);
 
-        String changInfo=PaperUtil.getPaperChangeInfo(total, dc, uc, paper);
-    	if(changInfo!=null) {
-    		sb.append(changInfo);
-    	}
-    	if(sb.length()!=0) {
-    		StringBuilder paperInfo=new StringBuilder();
-    		paperInfo.append(" 课程:"+paper.getCourse().getName()+"("+paper.getCourse().getCode()+")");
-    		paperInfo.append(" 试卷名称:"+paper.getName());
-    		sb.append(paperInfo);
-    		if(PaperType.IMPORT.equals(paper.getPaperType())) {
-    			ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(), AdminOperateType.TYPE43.getDesc(),sb.toString()));
-    		}else {
-    			ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(), AdminOperateType.TYPE44.getDesc(),sb.toString()));
-    		}
-    	}
+        String changInfo = PaperUtil.getPaperChangeInfo(total, dc, uc, paper);
+        if (changInfo != null) {
+            sb.append(changInfo);
+        }
+        if (sb.length() != 0) {
+            StringBuilder paperInfo = new StringBuilder();
+            paperInfo.append(" 课程:" + paper.getCourse().getName() + "(" + paper.getCourse().getCode() + ")");
+            paperInfo.append(" 试卷名称:" + paper.getName());
+            sb.append(paperInfo);
+            if (PaperType.IMPORT.equals(paper.getPaperType())) {
+                ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
+                        AdminOperateType.TYPE43.getDesc(), sb.toString()));
+            } else {
+                ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
+                        AdminOperateType.TYPE44.getDesc(), sb.toString()));
+            }
+        }
         if (baseUnit.getQuestion() != null) {
-            //清除缓存
+            // 清除缓存
             this.clearQuestionCache(baseUnit.getQuestion().getId());
         }
 
         return baseUnit;
     }
-    
-    
-    
-    private String getQuestionChangeInfo(Question old,Question now) {
-    	StringBuilder sb=new StringBuilder();
-    	if(old.getScore().doubleValue() !=now.getScore().doubleValue()) {
-    		sb.append(" 分数变动("+old.getScore()+"变为"+now.getScore()+")");
-    	}
-    	if(!StringUtils.equals(old.getQuesBody(), now.getQuesBody())) {
-    		sb.append(" 题干变动");
-    	}
-    	if(optionChange(old, now)) {
-    		sb.append(" 选项变动");
-    	}
-    	if(!StringUtils.equals(old.getQuesAnswer(), now.getQuesAnswer())) {
-    		sb.append(" 答案变动");
-    	}
-    	if(sb.length()==0) {
-    		return null;
-    	}
-    	return sb.toString();
+
+    private String getQuestionChangeInfo(Question old, Question now) {
+        StringBuilder sb = new StringBuilder();
+        if (old.getScore().doubleValue() != now.getScore().doubleValue()) {
+            sb.append(" 分数变动(" + old.getScore() + "变为" + now.getScore() + ")");
+        }
+        if (!StringUtils.equals(old.getQuesBody(), now.getQuesBody())) {
+            sb.append(" 题干变动");
+        }
+        if (optionChange(old, now)) {
+            sb.append(" 选项变动");
+        }
+        if (!StringUtils.equals(old.getQuesAnswer(), now.getQuesAnswer())) {
+            sb.append(" 答案变动");
+        }
+        if (sb.length() == 0) {
+            return null;
+        }
+        return sb.toString();
     }
-    
-    private boolean optionChange(Question old,Question now) {
-    	if(now.getQuesOptions()==null) {
-    		return false;
-    	}
-    	if(old.getQuesOptions().size()!=now.getQuesOptions().size()) {
-    		return true;
-    	}
-    	for(int i=0;i<now.getQuesOptions().size();i++) {
-    		if(!StringUtils.equals(old.getQuesOptions().get(i).getOptionBody(), now.getQuesOptions().get(i).getOptionBody())) {
-    			return true;
-        	}
-    	}
-    	return false;
+
+    private boolean optionChange(Question old, Question now) {
+        if (now.getQuesOptions() == null) {
+            return false;
+        }
+        if (old.getQuesOptions().size() != now.getQuesOptions().size()) {
+            return true;
+        }
+        for (int i = 0; i < now.getQuesOptions().size(); i++) {
+            if (!StringUtils.equals(old.getQuesOptions().get(i).getOptionBody(),
+                    now.getQuesOptions().get(i).getOptionBody())) {
+                return true;
+            }
+        }
+        return false;
     }
+
     /**
      * 删除小题
      *
@@ -333,31 +345,33 @@ public class PaperDetailUnitServiceImpl implements PaperDetailUnitService {
      * @return
      */
     public void deletePaperDetailUnit(String id, User user) {
-    	String changInfo=null;
+        String changInfo = null;
         PaperDetailUnit detailUnit = Model.of(paperDetailUnitRepo.findById(id));
         Paper paper = detailUnit.getPaper();
-        if(paper.getInUse()!=null&&paper.getInUse()==1) {
-			throw new StatusException("500", "试卷已调用");
-		}
+        if (paper.getInUse() != null && paper.getInUse() == 1) {
+            throw new StatusException("500", "试卷已调用");
+        }
         paperDetailUnitRepo.deleteById(id);
 
         if (detailUnit.getQuestion() != null) {
-            //清除缓存
+            // 清除缓存
             this.clearQuestionCache(detailUnit.getQuestion().getId());
         }
-        Double total=paper.getTotalScore();
-        Integer dc=paper.getPaperDetailCount();
-        Integer uc=paper.getUnitCount();
+        Double total = paper.getTotalScore();
+        Integer dc = paper.getPaperDetailCount();
+        Integer uc = paper.getUnitCount();
         paper.setAuditStatus(false);
         paperService.formatPaper(paper, user);
-        changInfo=PaperUtil.getPaperChangeInfo(total, dc, uc, paper);
-        if(detailUnit!=null) {
-        	StringBuilder sb=new StringBuilder();
-			sb.append("课程:"+detailUnit.getPaper().getCourse().getName()+"("+detailUnit.getPaper().getCourse().getCode()+")");
-			sb.append(" 试卷名称:"+detailUnit.getPaper().getName()); 
-			sb.append(" 第"+detailUnit.getNumber()+"小题 ");
-			sb.append(changInfo);
-        	ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(), AdminOperateType.TYPE45.getDesc(),sb.toString()));
+        changInfo = PaperUtil.getPaperChangeInfo(total, dc, uc, paper);
+        if (detailUnit != null) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("课程:" + detailUnit.getPaper().getCourse().getName() + "("
+                    + detailUnit.getPaper().getCourse().getCode() + ")");
+            sb.append(" 试卷名称:" + detailUnit.getPaper().getName());
+            sb.append(" 第" + detailUnit.getNumber() + "小题 ");
+            sb.append(changInfo);
+            ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
+                    AdminOperateType.TYPE45.getDesc(), sb.toString()));
         }
     }
 
@@ -392,8 +406,7 @@ public class PaperDetailUnitServiceImpl implements PaperDetailUnitService {
     }
 
     /**
-     * 查询大题下的小题
-     * 按number升序或降序排列,取第一个
+     * 查询大题下的小题 按number升序或降序排列,取第一个
      *
      * @return
      */
@@ -415,11 +428,31 @@ public class PaperDetailUnitServiceImpl implements PaperDetailUnitService {
     public List<PaperDetailUnit> findByPaperAndSort(Paper paper) {
         Query query = new Query();
         query.addCriteria(Criteria.where("paper").is(paper));
-        query.with(Sort.by(new Order(Direction.ASC, "number")));
-        query.with(Sort.by(new Order(Direction.ASC, "createTime")));
-        return this.mongoTemplate.find(query, PaperDetailUnit.class);
-    }
+        // query.with(Sort.by(new Order(Direction.ASC, "number")));
+        // query.with(Sort.by(new Order(Direction.ASC, "createTime")));
+        List<PaperDetailUnit> list = this.mongoTemplate.find(query, PaperDetailUnit.class);
+        Collections.sort(list, new Comparator<PaperDetailUnit>() {
+
+            @Override
+            public int compare(PaperDetailUnit o1, PaperDetailUnit o2) {
+                if (o1.getPaperDetail().getNumber() > o2.getPaperDetail().getNumber()) {
+                    return 1;
+                } else if (o1.getPaperDetail().getNumber() < o2.getPaperDetail().getNumber()) {
+                    return -1;
+                } else {
+                    if (o1.getNumber() > o2.getNumber()) {
+                        return 1;
+                    } else if (o1.getNumber() < o2.getNumber()) {
+                        return -1;
+                    } else {
+                        return 0;
+                    }
+                }
+            }
 
+        });
+        return list;
+    }
 
     public List<PaperDetailUnit> findByQuestionsAndPaperTypeOnline(List<String> ids, PaperType paperType) {
         Query query = new Query();
@@ -443,7 +476,8 @@ public class PaperDetailUnitServiceImpl implements PaperDetailUnitService {
     }
 
     @Override
-    public List<PaperDetailUnit> findByDDQuestionsAndPaperType(List<String> ids, PaperType paperType, List<Question> questionList) {
+    public List<PaperDetailUnit> findByDDQuestionsAndPaperType(List<String> ids, PaperType paperType,
+            List<Question> questionList) {
         List<ObjectId> objectIds = new ArrayList<>();
         for (String id : ids) {
             objectIds.add(new ObjectId(id));
@@ -455,48 +489,32 @@ public class PaperDetailUnitServiceImpl implements PaperDetailUnitService {
         return paperDetailUnits;
     }
 
-	/*@Override
-	public List<PaperDetailUnit> testFind(List<String> ids,PaperType paperType, List<Question> questionList) {
-		//第一种查询,quesion.id  id
-		DBObject query1 = new BasicDBObject();
-		BasicDBList values = new BasicDBList();
-		for(String id:ids){
-			values.add(id);
-		}
-		query1.put("quesion.id", new BasicDBObject("$in", values));
-		DBCursor dbCursor = mongoTemplate.getCollection("paperDetailUnit").find(query1);
-		while (dbCursor.hasNext()){
-			DBObject object=dbCursor.next();
-			log.debug("打印游标---------------"+object);
-		}
-
-		//第二种查询,quesion.$id  id
-		//DBObject query2 = new BasicDBObject();
-		BasicDBList values2 = new BasicDBList();
-		for(String id:ids){
-			values2.add(id);
-		}
-		query1.put("quesion.$id", new BasicDBObject("$in", values2));
-		DBCursor dbCursor2 = mongoTemplate.getCollection("paperDetailUnit").find(query1);
-		while (dbCursor2.hasNext()){
-			DBObject object=dbCursor2.next();
-			log.debug("打印游标2---------------"+object);
-		}
-
-		//第三种查询,quesion.$id  ObjectId
-		//DBObject query3 = new BasicDBObject();
-		BasicDBList values3 = new BasicDBList();
-		for(String id:ids){
-			values3.add(new ObjectId(id));
-		}
-		query1.put("quesion.$id", new BasicDBObject("$in", values3));
-		DBCursor dbCursor3 = mongoTemplate.getCollection("paperDetailUnit").find(query1);
-		while (dbCursor3.hasNext()){
-			DBObject object=dbCursor3.next();
-			log.debug("打印游标3---------------"+object);
-		}
-		return null;
-	}*/
+    /*
+     * @Override public List<PaperDetailUnit> testFind(List<String>
+     * ids,PaperType paperType, List<Question> questionList) {
+     * //第一种查询,quesion.id id DBObject query1 = new BasicDBObject(); BasicDBList
+     * values = new BasicDBList(); for(String id:ids){ values.add(id); }
+     * query1.put("quesion.id", new BasicDBObject("$in", values)); DBCursor
+     * dbCursor = mongoTemplate.getCollection("paperDetailUnit").find(query1);
+     * while (dbCursor.hasNext()){ DBObject object=dbCursor.next();
+     * log.debug("打印游标---------------"+object); }
+     * 
+     * //第二种查询,quesion.$id id //DBObject query2 = new BasicDBObject();
+     * BasicDBList values2 = new BasicDBList(); for(String id:ids){
+     * values2.add(id); } query1.put("quesion.$id", new BasicDBObject("$in",
+     * values2)); DBCursor dbCursor2 =
+     * mongoTemplate.getCollection("paperDetailUnit").find(query1); while
+     * (dbCursor2.hasNext()){ DBObject object=dbCursor2.next();
+     * log.debug("打印游标2---------------"+object); }
+     * 
+     * //第三种查询,quesion.$id ObjectId //DBObject query3 = new BasicDBObject();
+     * BasicDBList values3 = new BasicDBList(); for(String id:ids){
+     * values3.add(new ObjectId(id)); } query1.put("quesion.$id", new
+     * BasicDBObject("$in", values3)); DBCursor dbCursor3 =
+     * mongoTemplate.getCollection("paperDetailUnit").find(query1); while
+     * (dbCursor3.hasNext()){ DBObject object=dbCursor3.next();
+     * log.debug("打印游标3---------------"+object); } return null; }
+     */
 
     @Override
     public List<PaperDetailUnit> findByPaperIds(List<String> ids) {
@@ -512,29 +530,30 @@ public class PaperDetailUnitServiceImpl implements PaperDetailUnitService {
 
     @Override
     public void clearQuestionCache(String questionId) {
-        //清理与当前试题相关的缓存
-//        final String patternKey = CACHE_KEY_QUESTION + "*" + questionId;
-//        Set<String> keys = redisTemplate.keys(patternKey);
-//        if (CollectionUtils.isNotEmpty(keys)) {
-//            redisTemplate.delete(keys);
-//        }
+        // 清理与当前试题相关的缓存
+        // final String patternKey = CACHE_KEY_QUESTION + "*" + questionId;
+        // Set<String> keys = redisTemplate.keys(patternKey);
+        // if (CollectionUtils.isNotEmpty(keys)) {
+        // redisTemplate.delete(keys);
+        // }
         questionCache.remove(questionId);
         questionAnswerCache.remove(questionId);
-        //根据questionId清空相关联的paper缓存
-        List<PaperDetailUnit> list=findByQuestionId(questionId);
-        if(list!=null&&list.size()>0) {
-        	for(PaperDetailUnit pd:list) {
-//        		String paperKey = CACHE_KEY_PAPER + "*" + pd.getPaper().getId();
-//                Set<String> paperKeys = redisTemplate.keys(paperKey);
-//                if (CollectionUtils.isNotEmpty(paperKeys)) {
-//                    redisTemplate.delete(paperKeys);
-//                }
-        	    extractConfigPaperCache.remove(pd.getPaper().getId());
-        	    basePaperCache.remove(pd.getPaper().getId());
-        	}
+        // 根据questionId清空相关联的paper缓存
+        List<PaperDetailUnit> list = findByQuestionId(questionId);
+        if (list != null && list.size() > 0) {
+            for (PaperDetailUnit pd : list) {
+                // String paperKey = CACHE_KEY_PAPER + "*" +
+                // pd.getPaper().getId();
+                // Set<String> paperKeys = redisTemplate.keys(paperKey);
+                // if (CollectionUtils.isNotEmpty(paperKeys)) {
+                // redisTemplate.delete(paperKeys);
+                // }
+                extractConfigPaperCache.remove(pd.getPaper().getId());
+                basePaperCache.remove(pd.getPaper().getId());
+            }
         }
     }
-    
+
     private List<PaperDetailUnit> findByQuestionId(String questionId) {
         Query query = new Query();
         query.addCriteria(Criteria.where("question.id").is(questionId));

+ 2516 - 2487
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/impl/PaperServiceImpl.java

@@ -127,2506 +127,2535 @@ import cn.com.qmth.examcloud.web.support.SpringContextHolder;
 @Service("paperService")
 public class PaperServiceImpl implements PaperService {
 
-	private static final Logger LOG = LoggerFactory.getLogger(PaperServiceImpl.class);
-	
-	@Autowired
-	private PropertyRepo propertyRepo;
-	@Autowired
-	PaperRepo paperRepo;
+    private static final Logger LOG = LoggerFactory.getLogger(PaperServiceImpl.class);
 
-	@Autowired
-	PaperDetailService paperDetailService;
+    @Autowired
+    private PropertyRepo propertyRepo;
 
-	@Autowired
-	ExamPaperRepo examPaperRepo;
+    @Autowired
+    PaperRepo paperRepo;
 
-	@Autowired
-	PaperDetailRepo paperDetailRepo;
+    @Autowired
+    PaperDetailService paperDetailService;
 
-	@Autowired
-	PaperDetailUnitRepo paperDetailUnitRepo;
+    @Autowired
+    ExamPaperRepo examPaperRepo;
 
-	@Autowired
-	QuesRepo quesRepo;
+    @Autowired
+    PaperDetailRepo paperDetailRepo;
 
-	@Autowired
-	QuesBakRepo quesBakRepo;
+    @Autowired
+    PaperDetailUnitRepo paperDetailUnitRepo;
 
-	@Autowired
-	Gson gson;
+    @Autowired
+    QuesRepo quesRepo;
 
-	@Autowired
-	PaperDetailUnitService paperDetailUnitService;
+    @Autowired
+    QuesBakRepo quesBakRepo;
 
-	@Autowired
-	QuesService quesService;
+    @Autowired
+    Gson gson;
 
-	@Autowired
-	ExtractConfigService extractConfigService;
+    @Autowired
+    PaperDetailUnitService paperDetailUnitService;
 
-	@Autowired
-	private MongoTemplate mongoTemplate;
-	@Resource(name="mongoTemplate2")
-	private MongoTemplate mongoTemplate2;
-	@Autowired
-	private QuestionAudioServiceImpl questionAudioService;
+    @Autowired
+    QuesService quesService;
 
-	@Autowired
-	private SysProperty sysProperty;
+    @Autowired
+    ExtractConfigService extractConfigService;
 
-	@Autowired
-	private CoursePaperCloudService coursePaperCloudService;
+    @Autowired
+    private MongoTemplate mongoTemplate;
 
-	@Autowired
-	private CourseService courseService;
-
-	@Autowired
-	private ExtractConfigPaperCache extractConfigPaperCache;
-
-	@Autowired
-	private BasePaperCache basePaperCache;
-	@Autowired
-	private RandomPaperQuestionService randomPaperQuestionService;
-	@Autowired
-	private RandomPaperService randomPaperService;
-	
-	@Autowired
-	private QuestionCache questionCache;
-
-	@Autowired
-	private QuestionAnswerCache questionAnswerCache;
-
-	@Autowired
-	private SystemProperties systemProperties;
-
-	private Random random = new Random();
-
-	public static final String TEMP_FILE_EXP = "docxExport/";
-
-	/**
-	 * 查询所有已导入试卷
-	 */
-	@Override
-	public Page<Paper> getImportPapers(PaperSearchInfo paperSearchInfo, int curPage, int pageSize, UserDataRule ud) {
-
-		if (ud.assertEmptyQueryResult()) {
-			return Page.empty();
-		}
-		Query query = new Query();
-
-		query.addCriteria(Criteria.where("orgId").is(paperSearchInfo.getOrgId()));
-
-		if (ud.assertNeedQueryRefIds()) {
-			query.addCriteria(Criteria.where("course.id").in(ud.stringRefIds()));
-		}
-
-		query.addCriteria(Criteria.where("paperType").is(PaperType.IMPORT));
-
-		query.addCriteria(Criteria.where("course.enable").is("true"));
-
-		if (StringUtils.isNotBlank(paperSearchInfo.getCourseNo())) {
-			query.addCriteria(Criteria.where("course.code").is(paperSearchInfo.getCourseNo()));
-		}
-
-		if (StringUtils.isNotBlank(paperSearchInfo.getLevel())) {
-			query.addCriteria(Criteria.where("course.level").is(paperSearchInfo.getLevel()));
-		}
-
-		if (StringUtils.isNoneBlank(paperSearchInfo.getName())) {
-			String paperName = CommonUtils.escapeExprSpecialWord(paperSearchInfo.getName());
-			query.addCriteria(Criteria.where("name").regex(".*?\\.*" + paperName + ".*"));
-		}
-
-		if (StringUtils.isNoneBlank(paperSearchInfo.getCreator())) {
-			String creator = CommonUtils.escapeExprSpecialWord(paperSearchInfo.getCreator());
-			query.addCriteria(Criteria.where("creator").regex(".*?\\.*" + creator + ".*"));
-		}
-
-		if (StringUtils.isNoneBlank(paperSearchInfo.getLastModifyName())) {
-			String lastModifyName = CommonUtils.escapeExprSpecialWord(paperSearchInfo.getLastModifyName());
-			query.addCriteria(Criteria.where("lastModifyName").regex(".*?\\.*" + lastModifyName + ".*"));
-		}
-
-		if (StringUtils.isNotBlank(paperSearchInfo.getSpecialtyNo())) {
-			query.addCriteria(Criteria.where("specialty.code").is(paperSearchInfo.getSpecialtyNo()));
-		}
-
-		long total = this.mongoTemplate.count(query, Paper.class);
-		if (total == 0) {
-			return Page.empty();
-		}
-
-		PageRequest pageable = PageRequest.of(curPage - 1, pageSize);
-		query.with(Sort.by(Sort.Order.desc("createTime")));
-		query.skip(pageable.getOffset());
-		query.limit(pageable.getPageSize());
-
-		List<Paper> paperList = this.mongoTemplate.find(query, Paper.class);
-		if (CollectionUtils.isEmpty(paperList)) {
-			return Page.empty();
-		}
-
-		return new PageImpl<>(paperList, pageable, total);
-	}
-
-	/**
-	 * 查询所有待审核和审核不通过的导入试卷
-	 *
-	 * @param paperSearchInfo
-	 * @param curPage
-	 * @param pageSize
-	 * @return
-	 */
-	public Page<Paper> getImportPapersNotSuccess(PaperSearchInfo paperSearchInfo, int curPage, int pageSize) {
-		Query query = new Query();
-		query.addCriteria(Criteria.where("orgId").is(paperSearchInfo.getOrgId()));
-		query.addCriteria(Criteria.where("paperType").is(PaperType.IMPORT));
-		query.addCriteria(Criteria.where("course.enable").is("true"));
-		if (paperSearchInfo.getPaperStatus() != null) {
-			query.addCriteria(Criteria.where("paperStatus").is(paperSearchInfo.getPaperStatus()));
-		} else {
-			query.addCriteria(Criteria.where("paperStatus").ne(PaperStatus.PASS));
-		}
-		if (StringUtil.isNotBlank(paperSearchInfo.getCourseNo())) {
-			query.addCriteria(Criteria.where("course.code").is(paperSearchInfo.getCourseNo()));
-		}
-		long total = this.mongoTemplate.count(query, Paper.class);
-		if (total == 0) {
-			return Page.empty();
-		}
-
-		query.limit(pageSize);
-		query.skip((curPage - 1L) * pageSize);
-		List<Paper> paperList = this.mongoTemplate.find(query, Paper.class);
-		return new PageImpl<Paper>(paperList, PageRequest.of(curPage - 1, pageSize), total);
-	}
-
-	/**
-	 * 根据条件查询
-	 *
-	 * @param paperSearchInfo
-	 * @return
-	 */
-	public List<Paper> getImportPapersBySearch(PaperSearchInfo paperSearchInfo) {
-		Query query = new Query();
-		query.addCriteria(Criteria.where("orgId").is(paperSearchInfo.getOrgId()));
-		query.addCriteria(Criteria.where("paperType").is(PaperType.IMPORT.name()));
-		query.addCriteria(Criteria.where("course.enable").is("true"));
-		if (StringUtils.isNotBlank(paperSearchInfo.getCourseNo())) {
-			query.addCriteria(Criteria.where("course.code").is(paperSearchInfo.getCourseNo()));
-		}
-		if (StringUtils.isNotBlank(paperSearchInfo.getLevel())) {
-			query.addCriteria(Criteria.where("course.level").is(paperSearchInfo.getLevel()));
-		}
-		List<Paper> paperList = this.mongoTemplate.find(query, Paper.class);
-		return paperList;
-	}
-	
-	@Override
-	public List<Paper> getPapersByCourse(Long ordId,String courseCode,PaperType paperType) {
-		Query query = new Query();
-		query.addCriteria(Criteria.where("orgId").is(ordId.toString()));
-		query.addCriteria(Criteria.where("paperType").is(paperType.name()));
-		query.addCriteria(Criteria.where("course.code").is(courseCode));
-		List<Paper> paperList = this.mongoTemplate.find(query, Paper.class);
-		return paperList;
-	}
-	
-	@Override
-	public boolean existsPaperBySourceId(Long ordId,String courseCode,PaperType paperType,String sourceId) {
-		Query query = new Query();
-		query.addCriteria(Criteria.where("orgId").is(ordId.toString()));
-		query.addCriteria(Criteria.where("paperType").is(paperType.name()));
-		query.addCriteria(Criteria.where("course.code").is(courseCode));
-		query.addCriteria(Criteria.where("sourceId").is(sourceId));
-		List<Paper> paperList = this.mongoTemplate.find(query, Paper.class);
-		return CollectionUtils.isNotEmpty(paperList);
-	}
-	/**
-	 * 根据条件查询
-	 *
-	 * @param paperSearchInfo
-	 * @return
-	 */
-	public List<Paper> getGenPapersBySearch(PaperSearchInfo paperSearchInfo) {
-		Query query = new Query();
-		query.addCriteria(Criteria.where("orgId").is(paperSearchInfo.getOrgId()));
-		query.addCriteria(Criteria.where("paperType").is(PaperType.GENERATE.name()));
-		query.addCriteria(Criteria.where("course.enable").is("true"));
-		query.addCriteria(Criteria.where("storage").ne(1));
-		if (StringUtils.isNotBlank(paperSearchInfo.getCourseNo())) {
-			query.addCriteria(Criteria.where("course.code").is(paperSearchInfo.getCourseNo()));
-		}
-
-		if (StringUtils.isNotBlank(paperSearchInfo.getLevel())) {
-			query.addCriteria(Criteria.where("course.level").is(paperSearchInfo.getLevel()));
-		}
-
-		query.with(Sort.by(Sort.Direction.DESC, "createTime"));
-
-		List<Paper> paperList = this.mongoTemplate.find(query, Paper.class);
-		return paperList;
-	}
-
-	/**
-	 * 保存试卷
-	 *
-	 * @param paperExp
-	 * @return
-	 */
-	public Map<String, Object> savePaper(PaperExp paperExp, User user) {
-		Map<String, Object> msgMap = new HashMap<>();
-
-		Paper oldPaper = Model.of(paperRepo.findById(paperExp.getId()));
-		if (oldPaper != null) {
-			if (PaperType.GENERATE.equals(oldPaper.getPaperType())) {
-				oldPaper.setAuditStatus(false);
-			}
-			String oldName = oldPaper.getName().trim();
-			oldPaper.setTitle(paperExp.getTitle());
-			oldPaper.setName(paperExp.getName().trim());
-			oldPaper.setLastModifyName(user.getDisplayName());
-			oldPaper.setExamRemark(paperExp.getExamRemark());
-			if (!oldName.equals(paperExp.getName().trim())) {// 假如改变了试卷名称
-				// 则要效验试卷名称唯一性
-				boolean existName = this.checkPaperName(paperExp.getName().trim(), user.getRootOrgId().toString());
-				if (existName) {
-					msgMap.put("msg", "试卷名称重复,请重新命名!");
-				} else {
-					formatPaper(oldPaper, user);
-					paperRepo.save(oldPaper);
-					msgMap.put("msg", "success");
-				}
-			} else {
-				formatPaper(oldPaper, user);
-				paperRepo.save(oldPaper);
-				msgMap.put("msg", "success");
-			}
-		}
-
-		// 清除缓存
-		this.clearPaperCache(paperExp.getId());
-
-		return msgMap;
-	}
-
-	/**
-	 * 查询所有已组试卷
-	 *
-	 * @param paperSearchInfo
-	 * @param curPage
-	 * @param pageSize
-	 * @return
-	 */
-	public Page<Paper> getGenPapers(PaperSearchInfo paperSearchInfo, int curPage, int pageSize, UserDataRule ud) {
-		if (ud.assertEmptyQueryResult()) {
-			return Page.empty();
-		}
-		Query query = new Query();
-		query.addCriteria(Criteria.where("orgId").is(paperSearchInfo.getOrgId()));
-		if (ud.assertNeedQueryRefIds()) {
-			query.addCriteria(Criteria.where("course.id").in(ud.stringRefIds()));
-		}
-		if (paperSearchInfo.getAuditStatus() != null) {
-			if (paperSearchInfo.getAuditStatus()) {
-				query.addCriteria(Criteria.where("auditStatus").ne(false));
-			} else {
-				query.addCriteria(Criteria.where("auditStatus").is(false));
-			}
-		}
-		query.addCriteria(Criteria.where("paperType").is(PaperType.GENERATE.name()));
-		query.addCriteria(Criteria.where("storage").ne(1));
-		query.addCriteria(Criteria.where("course.enable").is("true"));
-		if (paperSearchInfo.getInUse() != null) {
-			if (paperSearchInfo.getInUse() == 0) {
-				query.addCriteria(Criteria.where("inUse").ne(1));
-			} else if (paperSearchInfo.getInUse() == 1) {
-				query.addCriteria(Criteria.where("inUse").is(1));
-			}
-		}
-		if (StringUtils.isNotBlank(paperSearchInfo.getCourseNo())) {
-			query.addCriteria(Criteria.where("course.code").is(paperSearchInfo.getCourseNo()));
-		}
-		if (StringUtils.isNotBlank(paperSearchInfo.getName())) {
-			String paperName = CommonUtils.escapeExprSpecialWord(paperSearchInfo.getName());
-			query.addCriteria(Criteria.where("name").regex(".*?\\.*" + paperName + ".*"));
-		}
-		if (StringUtils.isNotBlank(paperSearchInfo.getLevel())) {
-			query.addCriteria(Criteria.where("course.level").is(paperSearchInfo.getLevel()));
-		}
-		if (StringUtils.isNotBlank(paperSearchInfo.getCreator())) {
-			String creator = CommonUtils.escapeExprSpecialWord(paperSearchInfo.getCreator());
-			query.addCriteria(Criteria.where("creator").regex(".*?\\.*" + creator + ".*"));
-		}
-		if (StringUtils.isNotBlank(paperSearchInfo.getLastModifyName())) {
-			String lastModifyName = CommonUtils.escapeExprSpecialWord(paperSearchInfo.getLastModifyName());
-			query.addCriteria(Criteria.where("lastModifyName").regex(".*?\\.*" + lastModifyName + ".*"));
-		}
-
-		long total = this.mongoTemplate.count(query, Paper.class);
-		if (total == 0) {
-			return Page.empty();
-		}
-
-		query.with(Sort.by(new Order(Direction.DESC, "createTime")));
-		query.limit(pageSize);
-		query.skip((curPage - 1L) * pageSize);
-		List<Paper> paperList = this.mongoTemplate.find(query, Paper.class);
-		return new PageImpl<Paper>(paperList, PageRequest.of(curPage - 1, pageSize), total);
-	}
-
-	@Override
-	public Page<Paper> getStoragePaperPage(PaperSearchInfo paperSearchInfo, int curPage, int pageSize,
-			UserDataRule ud) {
-		if (ud.assertEmptyQueryResult()) {
-			return Page.empty();
-		}
-		Query query = new Query();
-		query.addCriteria(Criteria.where("orgId").is(paperSearchInfo.getOrgId()));
-		if (ud.assertNeedQueryRefIds()) {
-			query.addCriteria(Criteria.where("course.id").in(ud.stringRefIds()));
-		}
-		query.addCriteria(Criteria.where("paperType").is(PaperType.GENERATE.name()));
-		query.addCriteria(Criteria.where("storage").is(1));
-		query.addCriteria(Criteria.where("course.enable").is("true"));
-		if (StringUtils.isNotBlank(paperSearchInfo.getCourseNo())) {
-			query.addCriteria(Criteria.where("course.code").is(paperSearchInfo.getCourseNo()));
-		}
-		if (StringUtils.isNoneBlank(paperSearchInfo.getName())) {
-			String paperName = CommonUtils.escapeExprSpecialWord(paperSearchInfo.getName());
-			query.addCriteria(Criteria.where("name").regex(".*?\\.*" + paperName + ".*"));
-		}
-		if (StringUtils.isNotBlank(paperSearchInfo.getLevel())) {
-			query.addCriteria(Criteria.where("course.level").is(paperSearchInfo.getLevel()));
-		}
-		if (StringUtils.isNoneBlank(paperSearchInfo.getCreator())) {
-			String creator = CommonUtils.escapeExprSpecialWord(paperSearchInfo.getCreator());
-			query.addCriteria(Criteria.where("creator").regex(".*?\\.*" + creator + ".*"));
-		}
-		if (StringUtils.isNoneBlank(paperSearchInfo.getLastModifyName())) {
-			String lastModifyName = CommonUtils.escapeExprSpecialWord(paperSearchInfo.getLastModifyName());
-			query.addCriteria(Criteria.where("lastModifyName").regex(".*?\\.*" + lastModifyName + ".*"));
-		}
-
-		long total = this.mongoTemplate.count(query, Paper.class);
-		if (total == 0) {
-			return Page.empty();
-		}
-
-		query.with(Sort.by(new Order(Direction.DESC, "createTime")));
-		query.limit(pageSize);
-		query.skip((curPage - 1L) * pageSize);
-		List<Paper> paperList = this.mongoTemplate.find(query, Paper.class);
-		return new PageImpl<Paper>(paperList, PageRequest.of(curPage - 1, pageSize), total);
-	}
-
-	/**
-	 * 查询考试试卷
-	 *
-	 * @param id
-	 * @param courseCode
-	 * @param groupCode
-	 * @return
-	 */
-	public List<Paper> listExamPapers(long id, String courseCode, String groupCode) {
-		List<Paper> papers = new ArrayList<>();
-		ExamPaper examPaper = new ExamPaper();
-		examPaper.setExamId(id);
-		examPaper.setCourseCode(courseCode);
-		examPaper.setGroupCode(groupCode);
-		Example<ExamPaper> example = Example.of(examPaper);
-		List<ExamPaper> examPapers = examPaperRepo.findAll(example);
-		for (ExamPaper ePaper : examPapers) {
-			Paper paper = Model.of(paperRepo.findById(ePaper.getPaper().getId()));
-			papers.add(paper);
-		}
-		return papers;
-	}
-
-	/**
-	 * 设置考试试卷
-	 *
-	 * @param examId
-	 * @param courseCode
-	 * @param groupCode
-	 * @param paperId
-	 * @return
-	 */
-	public void joinToExamPaper(long examId, String courseCode, String groupCode, String paperId) {
-		ExamPaper examPaper = new ExamPaper();
-		examPaper.setExamId(examId);
-		examPaper.setGroupCode(groupCode);
-		examPaper.setCourseCode(courseCode);
-		// examPaper.setPaperId(paperId);
-		examPaperRepo.save(examPaper);
-	}
-
-	public void releaseExamPaper(long examId, String courseCode, String groupCode, String paperId) {
-		ExamPaper examPaper = new ExamPaper();
-		examPaper.setExamId(examId);
-		examPaper.setGroupCode(groupCode);
-		examPaper.setCourseCode(courseCode);
-		// examPaper.setPaperId(paperId);
-		examPaperRepo.delete(examPaper);
-	}
-
-	public Set<String> listGroupCodes(long examId, String courseCode) {
-		Set<String> groupSet = new HashSet<>();
-		ExamPaper examPaper = new ExamPaper();
-		examPaper.setExamId(examId);
-		examPaper.setCourseCode(courseCode);
-		List<ExamPaper> examPapers = examPaperRepo.findAll(Example.of(examPaper));
-		for (ExamPaper expaper : examPapers) {
-			groupSet.add(expaper.getGroupCode());
-		}
-		return groupSet;
-	}
-
-	public void deletGroupCode(long examId, String courseCode, String groupCode) {
-		ExamPaper examPaper = new ExamPaper();
-		examPaper.setExamId(examId);
-		examPaper.setCourseCode(courseCode);
-		examPaper.setCourseCode(courseCode);
-		examPaperRepo.delete(examPaper);
-	}
-
-	/**
-	 * 根据试卷ID获取试卷下面的大题
-	 *
-	 * @param id
-	 * @return
-	 */
-	public List<PaperDetail> findPaperDetailsById(String id) {
-		return paperDetailService.getPaperDetailsByPaper(Model.of(paperRepo.findById(id)));
-	}
-
-	/**
-	 * 批量删除试卷
-	 *
-	 * @param paperIds
-	 */
-	@Override
-	public void deletePapers(List<String> paperIds, User user) {
-		List<Paper> papers = CommonUtils.toList(paperRepo.findByIdIn(paperIds));
-		if (papers.get(0).getPaperType() == PaperType.IMPORT) {
-			List<Question> quesList = new ArrayList<>();
-			for (Paper paper : papers) {
-				List<PaperDetailUnit> paperUnits = paperDetailUnitRepo.findByPaperOrderByNumber(paper);
-				List<String> questionIds=paperUnits.stream().map(e->e.getQuestion().getId()).collect(Collectors.toList());
-				if(randomPaperQuestionService.existQuestion(questionIds)) {
-					throw new StatusException("试卷[" + paper.getName() + "]中有试题被抽题模板使用,不能删除");
-				}
-				for (PaperDetailUnit pdu : paperUnits) {
-					if (pdu.getQuestion() != null) {
-						quesList.add(pdu.getQuestion());
-					}
-				}
-			}
-			List<PaperDetailUnit> allUnits = paperDetailUnitRepo.findByQuestionIn(quesList);
-			for (PaperDetailUnit pdu : allUnits) {
-				if (pdu.getPaper() != null && pdu.getPaper().getPaperType() == PaperType.GENERATE) {
-//                    msg = "待删除试卷中有试题被组卷使用,不能删除!";
-//                    msgMap.put("msg", msg);
-//                    msgMap.put("paperName", pdu.getPaper().getName());
-//                    return msgMap;
-					throw new StatusException("试卷[" + pdu.getPaper().getName() + "]中有试题被组卷使用,不能删除");
-				}
-			}
-			// 删除音频
-			questionAudioService.deleteAudio(quesList);
-			quesRepo.deleteAll(quesList);
-		} else if (papers.get(0).getPaperType() == PaperType.GENERATE) {
-			for (Paper paper : papers) {
-//                List<String> examPaperIds = extractConfigService.getExamPaperId(paper.getCourseNo(), paper.getOrgId());
-//                if (examPaperIds != null && examPaperIds.contains(paper.getId())) {
-//                    msg = "待删除试卷有被调卷规则使用,不能删除!";
-//                    msgMap.put("msg", msg);
-//                    msgMap.put("paperName", paper.getName());
-//                    return msgMap;
-//                }
-				if (paper.getInUse() != null && paper.getInUse() == 1) {
-					throw new StatusException("试卷[" + paper.getName() + "]已调用,不能删除");
-				}
-				if(randomPaperService.existPaper(Long.valueOf(paper.getCourse().getId()),paper.getId())) {
-					throw new StatusException("试卷[" + paper.getName() + "]被抽题模板使用,不能删除");
-				}
-			}
-		}
-		paperDetailService.deletePaperDetailsByPapers(papers);
-		paperRepo.deleteAll(papers);
-
-		for (String paperId : paperIds) {
-			// 清除缓存
-			this.clearPaperCache(paperId);
-		}
-
-		for (Paper paper : papers) {
-			StringBuilder paperInfo = new StringBuilder();
-			paperInfo.append("课程:" + paper.getCourse().getName() + "(" + paper.getCourse().getCode() + ")");
-			paperInfo.append(" 试卷名称:" + paper.getName());
-			if (PaperType.IMPORT.equals(paper.getPaperType())) {
-				ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
-						AdminOperateType.TYPE46.getDesc(), paperInfo.toString()));
-			} else {
-				ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
-						AdminOperateType.TYPE47.getDesc(), paperInfo.toString()));
-
-			}
-		}
-	}
-	private List<PaperDetailUnitDto> findUnitByPaperId(String paperId) {
-		Object id ;
-		if (paperId.length() > 24) {
-			id=paperId;
-		} else {
-			id=new ObjectId(paperId);
-		}
-		Query query = new Query();
-		query.addCriteria(Criteria.where("paper.$id").is(id));
-		List<PaperDetailUnitDto> units = this.mongoTemplate2.find(query, PaperDetailUnitDto.class, "paperDetailUnit");
-		return units;
-	}
-	private boolean existGenerateQuestion(List<String> questionIds) {
-		List<Object> ids = new ArrayList<>();
-		for (String pid : questionIds) {
-			if (pid.length() > 24) {
-				ids.add(pid);
-			} else {
-				ids.add(new ObjectId(pid));
-			}
-		}
-		Query query = new Query();
-		query.addCriteria(Criteria.where("question.$id").in(ids));
-		query.addCriteria(Criteria.where("paperType").is(PaperType.GENERATE.name()));
-		long count=mongoTemplate.count(query,"paperDetailUnit");
-		return count>0;
-	}
-	private void removeByIds(List<String> stringIds,String collectionName) {
-		List<Object> ids = new ArrayList<>();
-		for (String pid : stringIds) {
-			if (pid.length() > 24) {
-				ids.add(pid);
-			} else {
-				ids.add(new ObjectId(pid));
-			}
-		}
-		Query query = new Query();
-		query.addCriteria(Criteria.where("_id").in(ids));
-		mongoTemplate.remove(query,collectionName);
-	}
-	private void removeDetailByPaperIds(List<String> paperIds) {
-		List<Object> ids = new ArrayList<>();
-		for (String pid : paperIds) {
-			if (pid.length() > 24) {
-				ids.add(pid);
-			} else {
-				ids.add(new ObjectId(pid));
-			}
-		}
-		Query query = new Query();
-		query.addCriteria(Criteria.where("paper.$id").in(ids));
-		mongoTemplate.remove(query,"paperDetail");
-	}
-	@Override
-	public void deletePapersPlus(List<String> paperIds, User user) {
-		List<Paper> papers = paperRepo.findByIdIn(paperIds);
-		List<PaperDetailUnitDto> unitList=new ArrayList<>();
-		if (papers.get(0).getPaperType() == PaperType.IMPORT) {
-			List<String> quesList = new ArrayList<>();
-			for (Paper paper : papers) {
-				List<PaperDetailUnitDto> paperUnits = findUnitByPaperId(paper.getId());
-				if(CollectionUtils.isEmpty(paperUnits)) {
-					continue;
-				}
-				List<String> questionIds=paperUnits.stream().map(e->e.getQuestion().getId()).collect(Collectors.toList());
-				if(existGenerateQuestion(questionIds)) {
-					throw new StatusException("试卷[" + paper.getName() + "]中有试题被组卷使用,不能删除");
-				}
-				if(randomPaperQuestionService.existQuestion(questionIds)) {
-					throw new StatusException("试卷[" + paper.getName() + "]中有试题被抽题模板使用,不能删除");
-				}
-				unitList.addAll(paperUnits);
-				quesList.addAll(questionIds);
-			}
-			if(CollectionUtils.isNotEmpty(quesList)) {
-				questionAudioService.deleteAudioByQuestionId(quesList);
-				removeByIds(quesList, "question");
-			}
-		} else if (papers.get(0).getPaperType() == PaperType.GENERATE) {
-			for (Paper paper : papers) {
-				if (paper.getInUse() != null && paper.getInUse() == 1) {
-					throw new StatusException("试卷[" + paper.getName() + "]已调用,不能删除");
-				}
-				if(randomPaperService.existPaper(Long.valueOf(paper.getCourse().getId()),paper.getId())) {
-					throw new StatusException("试卷[" + paper.getName() + "]被抽题模板使用,不能删除");
-				}
-				List<PaperDetailUnitDto> paperUnits = findUnitByPaperId(paper.getId());
-				if(CollectionUtils.isEmpty(paperUnits)) {
-					continue;
-				}
-				unitList.addAll(paperUnits);
-			}
-		}
-		List<String> unitids=unitList.stream().map(e->e.getId()).collect(Collectors.toList());
-		if(CollectionUtils.isNotEmpty(unitids)) {
-			removeByIds(unitids, "paperDetailUnit");
-		}
-		removeDetailByPaperIds(paperIds);
-		removeByIds(paperIds, "paper");
-
-		for (String paperId : paperIds) {
-			// 清除缓存
-			this.clearPaperCache(paperId);
-		}
-
-		for (Paper paper : papers) {
-			StringBuilder paperInfo = new StringBuilder();
-			paperInfo.append("课程:" + paper.getCourse().getName() + "(" + paper.getCourse().getCode() + ")");
-			paperInfo.append(" 试卷名称:" + paper.getName());
-			if (PaperType.IMPORT.equals(paper.getPaperType())) {
-				ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
-						AdminOperateType.TYPE46.getDesc(), paperInfo.toString()));
-			} else {
-				ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
-						AdminOperateType.TYPE47.getDesc(), paperInfo.toString()));
-
-			}
-		}
-	}
-
-	/**
-	 * 批量通过试卷
-	 *
-	 * @param paperIds
-	 */
-	public void passPapers(List<String> paperIds) {
-		List<Paper> papers = CommonUtils.toList(paperRepo.findByIdIn(paperIds));
-		papers.stream().forEach(paper -> {
-			paper.setPaperStatus(PaperStatus.PASS);
-		});
-		paperRepo.saveAll(papers);
-	}
-
-	@Override
-	public void updatePapersStorage(List<String> paperIds, int storage, String orgId) {
-		List<Paper> papers = CommonUtils.toList(paperRepo.findByIdIn(paperIds));
-		List<Paper> papersList = papers.stream().filter(p -> orgId.equals(p.getOrgId())).collect(Collectors.toList());
-		papersList.stream().forEach(paper -> {
-			paper.setStorage(storage);
-		});
-		if (papersList.size() > 0) {
-			paperRepo.saveAll(papersList);
-		}
-	}
-
-	/**
-	 * 批量不通过试卷
-	 *
-	 * @param paperIds
-	 */
-	public void noPassPapers(List<String> paperIds) {
-		List<Paper> papers = CommonUtils.toList(paperRepo.findByIdIn(paperIds));
-		papers.stream().forEach(paper -> {
-			paper.setPaperStatus(PaperStatus.NOPASS);
-		});
-		paperRepo.saveAll(papers);
-	}
-
-	/**
-	 * 批量待审核试卷
-	 *
-	 * @param paperIds
-	 */
-	public void backPapers(List<String> paperIds) {
-		List<Paper> papers = CommonUtils.toList(paperRepo.findByIdIn(paperIds));
-		papers.stream().forEach(paper -> {
-			paper.setPaperStatus(PaperStatus.DRAFT);
-		});
-		paperRepo.saveAll(papers);
-	}
-
-	/**
-	 * 初始化导出试卷DTO
-	 *
-	 * @param id
-	 * @return
-	 */
-	public PaperExp getPaperDto(String id) {
-		Paper paper = Model.of(paperRepo.findById(id));
-		// 创建paperDto
-		PaperExp paperExp = new PaperExp();
-		BeanUtils.copyProperties(paper, paperExp);
-		paperExp.setCourse(paper.getCourse());
-		// 获取大题
-		List<PaperDetail> paperDetails = paperDetailRepo.findByPaperOrderByNumber(paper);
-		List<PaperDetailExp> paperDetailExps = new ArrayList<>();
-		for (PaperDetail paperDetail : paperDetails) {
-			PaperDetailExp paperDetailExp = new PaperDetailExp();
-			BeanUtils.copyProperties(paperDetail, paperDetailExp);
-			paperDetailExps.add(paperDetailExp);
-		}
-		// 封装小题
-		for (int i = 0; i < paperDetailExps.size(); i++) {
-			List<PaperDetailUnit> paperDetailUnits = paperDetailUnitRepo
-					.findByPaperDetailOrderByNumber(paperDetails.get(i));
-			if (paperDetailUnits != null && paperDetailUnits.size() > 0) {
-				List<PaperDetailUnitExp> paperDetailUnitExps = new ArrayList<>();
-				for (PaperDetailUnit paperDetailUnit : paperDetailUnits) {
-					PaperDetailUnitExp paperDetailUnitExp = new PaperDetailUnitExp();
-					BeanUtils.copyProperties(paperDetailUnit, paperDetailUnitExp);
-					fillProperty(paperDetailUnitExp.getQuestion());
-					if (!CollectionUtils.isEmpty(paperDetailUnitExp.getQuestion().getSubQuestions())) {
-						for (Question subque : paperDetailUnitExp.getQuestion().getSubQuestions()) {
-							fillProperty(subque);
-						}
-					}
-					paperDetailUnitExps.add(paperDetailUnitExp);
-				}
-				// 选择题,套题下选择题 选项顺序重新排列
-				reorderChoicequestionOption(paperDetailUnitExps);
-				paperDetailExps.get(i).setPaperDetailUnits(paperDetailUnitExps);
-			} else {
-				paperDetailExps.get(i).setUnitCount(0);
-			}
-		}
-		paperExp.setPaperDetails(paperDetailExps);
-		// 初始化试卷内容
-		initPaper(paperExp);
-		return paperExp;
-	}
-
-	/**
-	 * 重新对选择题option进行排序(多选、单选、套题下选择题)
-	 */
-	public void reorderChoicequestionOption(List<PaperDetailUnitExp> paperDetailUnitExps) {
-		for (PaperDetailUnitExp paperDetailUnitExp : paperDetailUnitExps) {
-			String optionOrder = paperDetailUnitExp.getOptionOrder();
-			if (StringUtil.isNotBlank(optionOrder)) {
-				Question question = paperDetailUnitExp.getQuestion();
-				if (question.getQuestionType() == QuesStructType.SINGLE_ANSWER_QUESTION
-						|| question.getQuestionType() == QuesStructType.MULTIPLE_ANSWER_QUESTION) {
-					question.setQuesOptions(reorderOptionCore(question.getQuesOptions(), optionOrder));
-				}
-				if (question.getQuestionType() == QuesStructType.NESTED_ANSWER_QUESTION) {
-					List<Question> subQuestions = question.getSubQuestions();
-					int index = 0;
-					for (int k = 0; k < subQuestions.size(); k++) {
-						Question subQuestion = subQuestions.get(k);
-						if (subQuestion.getQuestionType() == QuesStructType.SINGLE_ANSWER_QUESTION
-								|| subQuestion.getQuestionType() == QuesStructType.MULTIPLE_ANSWER_QUESTION) {
-							subQuestion.setQuesOptions(
-									reorderOptionCore(subQuestion.getQuesOptions(), optionOrder.split(";")[index]));
-							index++;
-						}
-					}
-				}
-			}
-		}
-	}
-
-	private List<QuesOption> reorderOptionCore(List<QuesOption> quesOptions, String optionOrder) {
-		List<QuesOption> newQuesOptions = new ArrayList<>();
-		if (StringUtil.isBlank(optionOrder) || quesOptions.isEmpty()) {
-			return null;
-		}
-		String[] optionOrderArr = optionOrder.split(",");
-		for (int j = 0; j < optionOrderArr.length; j++) {
-			for (int k = 0; k < quesOptions.size(); k++) {
-				if (optionOrderArr[j].equals(quesOptions.get(k).getNumber())) {
-					newQuesOptions.add(quesOptions.get(k));
-				}
-			}
-		}
-		quesOptions = null;
-		return newQuesOptions;
-	}
-
-	/**
-	 * 初始化试卷内容(增加序号)
-	 *
-	 * @param paperExp
-	 */
-	public void initPaper(PaperExp paperExp) {
-		if (paperExp.getPaperDetails() == null || paperExp.getPaperDetails().size() == 0) {
-			return;
-		}
-		int mainNum = 0;
-		List<PaperDetailExp> paperDetailExpList = paperExp.getPaperDetails();
-		for (PaperDetailExp paperDetail : paperDetailExpList) {
-			// 大题序号
-			paperDetail.setNumber(++mainNum);
-			paperDetail.setCnNum(CommonUtils.toCHNum(paperDetail.getNumber()));
-			if (paperDetail != null && paperDetail.getPaperDetailUnits() != null
-					&& paperDetail.getPaperDetailUnits().size() > 0) {
-				for (PaperDetailUnitExp paperDetailUnit : paperDetail.getPaperDetailUnits()) {
-					Question question = paperDetailUnit.getQuestion();
-					if (question != null) {
-						if (question.getHasAudio() != null && question.getHasAudio()) {
-							paperExp.setHasAudio(true); // 设置试卷含有音频
-						}
-						quesService.formatQuesUnit(question);
-						List<Question> subQuesList = question.getSubQuestions();
-						// 套题序号
-						if (subQuesList != null && subQuesList.size() > 0) {
-							int index = 0;
-							for (Question subQues : subQuesList) {
-								Map<String, String> params = new HashMap<>();
-								params.put("number", String.valueOf(++index));
-								subQues.setQuesParams(params);
-								quesService.formatQuesUnit(subQues);
-							}
-							String quesBodyHtml = CommonUtils.relaceQuestionIdx(question.getQuesBody(), 0);
-							question.setQuesBody(quesBodyHtml);
-						}
-					}
-				}
-			}
-		}
-	}
-
-	/**
-	 * 格式化查询条件
-	 *
-	 * @param paperSearchInfo
-	 */
-	public void formatPaperSearchInfo(PaperSearchInfo paperSearchInfo) {
-		if (StringUtils.isEmpty(paperSearchInfo.getCourseNo())) {
-			paperSearchInfo.setCourseNo(null);
-		}
-		if (StringUtils.isEmpty(paperSearchInfo.getCreateTime())) {
-			paperSearchInfo.setCreateTime(null);
-		}
-		if (StringUtils.isEmpty(paperSearchInfo.getCreator())) {
-			paperSearchInfo.setCreator(null);
-		}
-		if (StringUtils.isEmpty(paperSearchInfo.getName())) {
-			paperSearchInfo.setName(null);
-		}
-	}
-
-	/**
-	 * 1.重新设置小题number,并返回试卷总分 2.重新计算大题的总分和小题总数 3.重新保存试卷大题数量、小题数量、试卷总分等信息
-	 *
-	 * @param paper
-	 */
-	public void formatPaper(Paper paper, User user) {
-		double paperTotalScore = reSetPaperDetailUnit(paper);
-		paper.setDifficultyDegree(reSetDifficulty(paper, paperTotalScore));
-		Map<String, Object> paperInfoMap = reSetPaperDetail(paper);
-		reSetPaper(paper, user, paperInfoMap, paperTotalScore);
-	}
-
-	/**
-	 * 计算试卷难度
-	 *
-	 * @param paper
-	 * @param paperTotalScore
-	 * @return
-	 */
-
-	@SuppressWarnings("unused")
-	public Double reSetDifficulty(Paper paper, double paperTotalScore) {
-		Double sum = 0.0;
-		List<PaperDetail> paperDetails = paperDetailRepo.findByPaperOrderByNumber(paper);
-		if (paperDetails != null && paperDetails.size() > 0) {
-			for (PaperDetail paperDetail : paperDetails) {
-				// 获取每个大题下面的所有小题
-				List<PaperDetailUnit> paperDetailUnits = paperDetailUnitRepo
-						.findByPaperDetailOrderByNumber(paperDetail);
-				if (paperDetailUnits != null && paperDetailUnits.size() > 0) {
-					for (PaperDetailUnit paperDetailUnit : paperDetailUnits) {
-						// 如果为套题,重新计算难度
-						if (paperDetailUnit.getQuestionType() == QuesStructType.NESTED_ANSWER_QUESTION) {
-							// 重新计算套题的难度,公开度
-							boolean publicity = false;
-							double totalSum = 0d;
-							double totalDou = 0d;
-							for (int i = 0; i < paperDetailUnit.getQuestion().getSubQuestions().size(); i++) {
-								Question subQuestion = paperDetailUnit.getQuestion().getSubQuestions().get(i);
-								// 设置公开度
-								if (subQuestion.getPublicity() == null) {
-									publicity = true;
-								} else {
-									if (subQuestion.getPublicity()) {
-										publicity = true;
-									}
-								}
-								if (subQuestion.getDifficultyDegree() == null) {
-									subQuestion.setDifficultyDegree(0.5);
-								}
-								totalSum = subQuestion.getDifficultyDegree() * paperDetailUnit.getSubScoreList().get(i)
-										+ totalSum;
-								totalDou = paperDetailUnit.getSubScoreList().get(i) + totalDou;
-							}
-
-							BigDecimal b;
-							if (totalDou != 0d) {
-								b = BigDecimal.valueOf(totalSum / totalDou);
-							} else {
-								b = BigDecimal.valueOf(0d);
-							}
-
-							Double difficulty = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
-							paperDetailUnit.getQuestion().setDifficultyDegree(difficulty);
-							paperDetailUnit.setScore(totalDou);
-						}
-						// 旧题没有难度值,需要重新赋值
-						if (paperDetailUnit.getQuestion().getDifficultyDegree() == null) {
-							paperDetailUnit.getQuestion().setDifficultyDegree(0.5);
-						}
-						if (paperDetailUnit.getScore() == null) {
-							paperDetailUnit.setScore(0d);
-						}
-						sum = paperDetailUnit.getScore() * paperDetailUnit.getQuestion().getDifficultyDegree() + sum;
-					}
-				}
-			}
-			if (paperTotalScore < 0.1) {
-				return 0.0;
-			}
-			BigDecimal b = BigDecimal.valueOf(sum / paperTotalScore);
-			Double difficulty = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
-			return difficulty;
-		}
-		return 0.0;
-	}
-
-	/**
-	 * 重新设置小题number,并返回试卷总分
-	 *
-	 * @param paper
-	 * @return
-	 */
-	private double reSetPaperDetailUnit(Paper paper) {
-		List<PaperDetailUnit> paperDetailUnitAll = paperDetailUnitService.findByPaperAndSort(paper);
-		double totalScore = 0;
-		for (int i = 0; i < paperDetailUnitAll.size(); i++) {
-			PaperDetailUnit unit = paperDetailUnitAll.get(i);
-			if (unit.getScore() != null) {
-				totalScore += unit.getScore();
-			}
-			unit.setNumber(i + 1);
-		}
-		paperDetailUnitRepo.saveAll(paperDetailUnitAll);
-		totalScore = CommonUtils.formatDouble(totalScore);
-		return totalScore;
-	}
-
-	/**
-	 * 重新计算大题的总分和小题总数
-	 *
-	 * @param paper
-	 */
-	private Map<String, Object> reSetPaperDetail(Paper paper) {
-		Map<String, Object> paperInfoMap = new HashMap<>();
-		int allQuesCount = 0;
-		List<PaperDetail> paperDetails = paperDetailRepo.findByPaperOrderByNumber(paper);
-		// 计算各大题总分和小题数量
-		for (PaperDetail paperDetail : paperDetails) {
-			List<PaperDetailUnit> paperDetailUnits = paperDetailUnitRepo.findByPaperDetailOrderByNumber(paperDetail);
-			if (paperDetailUnits.size() > 0) {
-				int count = 0;
-				double score = 0;
-				int nestQusNum = 0;
-				for (PaperDetailUnit unit : paperDetailUnits) {
-					if (unit.getScore() != null) {
-						score += unit.getScore();
-					}
-					if (unit.getQuestion() != null && unit.getQuestion().getSubQuestions() != null
-							&& unit.getQuestion().getSubQuestions().size() > 0) {
-						nestQusNum += unit.getQuestion().getSubQuestions().size() - 1;
-					}
-				}
-				count = paperDetailUnits.size() + nestQusNum;
-				score = CommonUtils.formatDouble(score);
-				paperDetail.setScore(score);
-				paperDetail.setUnitCount(count);
-				allQuesCount += count;
-			} else {
-				paperDetail.setScore(0d);
-			}
-		}
-		paperDetailRepo.saveAll(paperDetails);
-		paperInfoMap.put("allQuesCount", allQuesCount);
-		paperInfoMap.put("paperDetails", paperDetails);
-		return paperInfoMap;
-	}
-
-	/**
-	 * 重新设置试卷大题数量、小题数量、试卷总分等属性
-	 *
-	 * @param paper
-	 * @param user
-	 * @param paperInfoMap
-	 * @param paperTotalScore
-	 */
-	@SuppressWarnings("unchecked")
-	private void reSetPaper(Paper paper, User user, Map<String, Object> paperInfoMap, double paperTotalScore) {
-		List<PaperDetail> paperDetails = (List<PaperDetail>) paperInfoMap.get("paperDetails");
-		paper.setPaperDetailCount(paperDetails.size());// 设置大题数量
-		paper.setUnitCount(Integer.parseInt(paperInfoMap.get("allQuesCount") + ""));// 设置小题数量
-		paper.setTotalScore(paperTotalScore);// 设置试卷总分
-		if (user != null) {
-			paper.setLastModifyName(user.getDisplayName());
-		}
-		paperRepo.save(paper);
-
-		// 清除缓存
-		this.clearPaperCache(paper.getId());
-	}
-
-	/**
-	 * 先备份准备删掉的试题,然后再删掉
-	 *
-	 * @param questionId
-	 * @return
-	 */
-	public void deleteImportQuestionById(String detailUnitId, String questionId, User user) {
-		if(randomPaperQuestionService.existQuestion(questionId)) {
-        	throw new StatusException("该试题已被抽题模板使用,不能删除");
-        }
-		PaperDetailUnit paperDetailUnit = null;
-		if (detailUnitId != null) {
-			paperDetailUnit = Model.of(paperDetailUnitRepo.findById(detailUnitId));
-			Paper paper = paperDetailUnit.getPaper();
-			if (paper.getInUse() != null && paper.getInUse() == 1) {
-				throw new StatusException("500", "试卷已调用");
-			}
-		}
-		Question ques = Model.of(quesRepo.findById(questionId));
-
-		List<PaperDetailUnit> pdus = CommonUtils.toList(paperDetailUnitRepo.findByQuestion(ques));
-		List<String> paperNames = new ArrayList<>();
-
-		// 需要删除的小题
-		List<PaperDetailUnit> needPdus = new ArrayList<>();
-
-		List<Paper> papers = new ArrayList<>();
-		for (PaperDetailUnit pdu : pdus) {
-			if (pdu.getPaper() != null) {
-				if (!papers.contains(pdu.getPaper())) {
-					papers.add(pdu.getPaper());
-				}
-				if (PaperType.GENERATE == pdu.getPaper().getPaperType()) {
-					paperNames.add(pdu.getPaper().getName());
-				}
-			}
-		}
-		String changInfo = null;
-		if (paperNames.size() == 0) {
-			needPdus.addAll(pdus);// 此试题没有被组卷调用,则可以删除此试题
-			paperDetailUnitRepo.deleteAll(needPdus);
-			quesBakRepo.save(BeanCopierUtil.copyProperties(ques, QuestionBak.class));
-			quesRepo.delete(ques);
-
-			for (Paper paper : papers) {
-				if (paperDetailUnit != null && paperDetailUnit.getPaper().getId().equals(paper.getId())) {
-					Double total = paper.getTotalScore();
-					Integer dc = paper.getPaperDetailCount();
-					Integer uc = paper.getUnitCount();
-					formatPaper(paper, user);
-					changInfo = PaperUtil.getPaperChangeInfo(total, dc, uc, paper);
-				} else {
-					formatPaper(paper, user);
-				}
-			}
-		}
-
-		if (paperDetailUnit != null) {
-			StringBuilder sb = new StringBuilder();
-			sb.append("课程:" + paperDetailUnit.getPaper().getCourse().getName() + "("
-					+ paperDetailUnit.getPaper().getCourse().getCode() + ")");
-			sb.append(" 试卷名称:" + paperDetailUnit.getPaper().getName());
-			sb.append(" 第" + paperDetailUnit.getNumber() + "小题 ");
-			sb.append(changInfo);
-			ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
-					AdminOperateType.TYPE48.getDesc(), sb.toString()));
-		}
-		if (CollectionUtils.isNotEmpty(paperNames)) {
-			throw new StatusException("该试题被试卷:" + StringUtils.join(paperNames, ",") + "使用,不能删除");
-		}
-	}
-
-	/**
-	 * 向试卷中插入一个试题
-	 *
-	 * @param paperId
-	 * @param paperDetailId
-	 * @return
-	 */
-	public Paper insertQuestionToPaper(String paperId, String paperDetailId, Question question, User user) {
-		Paper paper = Model.of(paperRepo.findById(paperId));
-		question.setOrgId(user.getRootOrgId().toString());
-		question.setCourse(paper.getCourse());
-		question.setCourseNo(paper.getCourse().getCode());// 必须设置,因为部分方法需要courseNo作为查询条件
-		question = quesService.saveQues(question);
-
-		PaperDetail paperDetail = Model.of(paperDetailRepo.findById(paperDetailId));
-		PaperDetailUnit paperDetailUnit = new PaperDetailUnit(paper, paperDetail, question);
-		paperDetailUnit.setPaperType(PaperType.IMPORT);
-		PaperDetailUnit paperDetailUnit2 = paperDetailUnitService.findTopOrderByNumber(paperDetail, "DESC");
-		if (paperDetailUnit2 == null) {
-			paperDetailUnit.setNumber(1);
-		} else {
-			paperDetailUnit.setNumber(paperDetailUnit2.getNumber());// 设置number为大题的最大题号
-		}
-		paperDetailUnitRepo.save(paperDetailUnit);
-		formatPaper(paper, user);
-		return paper;
-	}
-
-	/**
-	 * 获取试题所在的试卷名称
-	 *
-	 * @param questionId
-	 * @return
-	 */
-	public List<String> getPaperNamesByQuestionId(String questionId) {
-		List<String> paperNames = new ArrayList<>();
-		List<PaperDetailUnit> pdus = paperDetailUnitRepo.findByQuestion(Model.of(quesRepo.findById(questionId)));
-		for (PaperDetailUnit pdu : pdus) {
-			paperNames.add(pdu.getPaper().getName());
-		}
-		return paperNames;
-
-	}
-
-	public Page<Question> listQuestionforSelect(String paperId, int curPage, int pageSize, QuesStructType quesType,
-			User user, String quesBody, UserDataRule ud) {
-		Set<String> selectedIds = new HashSet<>();
-		Paper paper = Model.of(paperRepo.findById(paperId));
-		List<PaperDetailUnit> pdus = paperDetailUnitRepo.findByPaperOrderByNumber(paper);
-		for (PaperDetailUnit pdu : pdus) {
-			selectedIds.add(pdu.getQuestion().getId());
-		}
-		return quesService.findByIdExclude(selectedIds, paper.getCourseNo(), quesType, curPage, pageSize,
-				user.getRootOrgId(), quesBody, ud);
-	}
-
-	@SuppressWarnings("unused")
-	public Paper selectQuestionsToPaper(String paperId, String paperDetailId, List<Question> questions, User user) {
-		Paper paper = Model.of(paperRepo.findById(paperId));
-		if (paper.getInUse() != null && paper.getInUse() == 1) {
-			throw new StatusException("500", "试卷已调用");
-		}
-		PaperDetail paperDetail = Model.of(paperDetailRepo.findById(paperDetailId));
-		PaperDetailUnit paperDetailUnit = paperDetailUnitRepo.findTopByPaperDetailOrderByNumberDesc(paperDetail);
-
-		List<PaperDetailUnit> saveUnits = new ArrayList<>();
-		for (Question ques : questions) {
-			PaperDetailUnit pdu = new PaperDetailUnit(paper, paperDetail, ques);
-
-			// 如果大题没有小题,取导入的试题分数
-			if (paperDetailUnit == null) {
-				pdu.setNumber(1);
-			} else {
-				pdu.setNumber(paperDetailUnit.getNumber());// 设置为大题中最大的number
-			}
-
-			pdu.setScore(ques.getScore() == null ? 0d : ques.getScore());
-
-			// 处理套题
-			if (pdu.getQuestionType() == QuesStructType.NESTED_ANSWER_QUESTION) {
-				List<Question> subQuestions = ques.getSubQuestions();
-				List<Double> subScoreList = new ArrayList<>();
-				if (subQuestions != null && subQuestions.size() > 0) {
-					for (Question subQuestion : subQuestions) {
-						subScoreList.add(CommonUtils.formatDouble(pdu.getScore() / subQuestions.size()));
-					}
-				}
-				pdu.setSubScoreListNew(subScoreList);
-			}
-
-			saveUnits.add(pdu);
-		}
-
-		paperDetailUnitRepo.saveAll(saveUnits);
-
-		// 清除缓存
-		this.clearPaperCache(paper.getId());
-		paper.setAuditStatus(false);
-		Double total = paper.getTotalScore();
-		Integer dc = paper.getPaperDetailCount();
-		Integer uc = paper.getUnitCount();
-		formatPaper(paper, user);
-
-		StringBuilder paperInfo = new StringBuilder();
-		paperInfo.append("课程:" + paper.getCourse().getName() + "(" + paper.getCourse().getCode() + ")");
-		paperInfo.append(" 试卷名称:" + paper.getName());
-		paperInfo.append(" 第" + paperDetail.getNumber() + "大题选题题数:" + questions.size());
-		String changInfo = PaperUtil.getPaperChangeInfo(total, dc, uc, paper);
-		if (changInfo != null) {
-			paperInfo.append(changInfo);
-		}
-		ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
-				AdminOperateType.TYPE49.getDesc(), paperInfo.toString()));
-		return paper;
-	}
-
-	public boolean checkPaperName(String paperName, String orgId) {
-		List<Paper> paperList = paperRepo.findByNameAndOrgId(paperName, orgId);
-		if (CollectionUtils.isNotEmpty(paperList)) {
-			return true;
-		}
-		return false;
-	}
-
-	public void checkPaperNameNew(String paperName, String orgId) throws Exception {
-		List<Paper> paperList = paperRepo.findByNameAndOrgId(paperName, orgId);
-		if (paperList != null && paperList.size() > 0) {
-			throw new PaperException("试卷名称重复,请重新命名");
-		}
-	}
-
-	public Page<Paper> getPapersNotInIds(PaperSearchInfo paperSearchInfo, String[] ids, int curPage, int pageSize,
-			PaperType paperType, UserDataRule ud) {
-		Set<String> selectedIds = new HashSet<>();
-		for (String id : ids) {
-			selectedIds.add(id);
-		}
-		if (ud.assertEmptyQueryResult()) {
-			return Page.empty();
-		}
-		Query query = new Query();
-		query.addCriteria(Criteria.where("orgId").is(paperSearchInfo.getOrgId()));
-		if (ud.assertNeedQueryRefIds()) {
-			query.addCriteria(Criteria.where("course.id").in(ud.stringRefIds()));
-		}
-		query.addCriteria(Criteria.where("paperType").is(paperType));
-		query.addCriteria(Criteria.where("course.code").is(paperSearchInfo.getCourseNo()));
-		query.addCriteria(Criteria.where("id").nin(selectedIds));
-		if (PaperType.GENERATE.equals(paperType)) {
-			query.addCriteria(Criteria.where("storage").ne(1));
-		}
-		long total = this.mongoTemplate.count(query, Paper.class);
-		if (total == 0) {
-			return Page.empty();
-		}
-
-		query.with(Sort.by(new Order(Direction.DESC, "createTime")));
-		query.limit(pageSize);
-		query.skip((curPage - 1L) * pageSize);
-		List<Paper> paperList = this.mongoTemplate.find(query, Paper.class);
-		Page<Paper> paperPageList = new PageImpl<Paper>(paperList, PageRequest.of(curPage - 1, pageSize), total);
-		return paperPageList;
-	}
-
-	/**
-	 * 使用原卷
-	 */
-	public void useBasePaper(String selectedPaperIds, String userId) {
-		Assert.hasLength(selectedPaperIds, "试卷id不能为空!");
-		String[] paperIds = selectedPaperIds.split(",");
-		for (int i = 0; i < paperIds.length; i++) {
-			Paper oldpaper = Model.of(paperRepo.findById(paperIds[i]));
-			List<PaperDetail> paperDetails = paperDetailRepo.findByPaperOrderByNumber(oldpaper);
-			for (PaperDetail paperDetail : paperDetails) {
-				List<PaperDetailUnit> paperDetailUnits = paperDetailUnitService.getUnitsByPaperDetail(paperDetail);
-				paperDetail.setPaperDetailUnits(paperDetailUnits);
-			}
-			// PaperUtil.sortDetails(paperDetails);
-			oldpaper.setId(null);
-			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-			String createTime = sdf.format(new Date());
-			oldpaper.setCreateTime(createTime);
-			oldpaper.setCreator(userId);
-			oldpaper.setLastModifyName(userId);
-			oldpaper.setPaperType(PaperType.GENERATE);// 试卷类型 修改为组卷
-			oldpaper.setAuditStatus(false);
-			Paper newPaper = paperRepo.save(oldpaper);
-			for (int j = 0; j < paperDetails.size(); j++) {
-				PaperDetail paperDetail = paperDetails.get(j);
-				paperDetail.setNumber(j + 1);
-				List<PaperDetailUnit> paperDetailUnits = paperDetail.getPaperDetailUnits();
-				paperDetail.setPaper(newPaper);// 关联新Paper
-				paperDetail.setId(null);
-				paperDetail.setCreateTime(createTime);
-				paperDetail.setCreator(userId);
-				PaperDetail newPaperDetail = paperDetailRepo.save(paperDetail);// 保存新的paperDetail
-				for (int k = 0; k < paperDetailUnits.size(); k++) {
-					// 重新设置保存PaperDetailUnit
-					PaperDetailUnit paperDetailUnit = paperDetailUnits.get(k);
-					paperDetailUnit.setPaper(newPaper); // 关联新Paper
-					paperDetailUnit.setPaperDetail(newPaperDetail); // 关联新paperDetail
-					paperDetailUnit.setId(null);
-					paperDetailUnit.setCreateTime(createTime);
-					paperDetailUnit.setCreator(userId);
-					paperDetailUnit.setPaperType(PaperType.GENERATE);
-					paperDetailUnitRepo.save(paperDetailUnit);// 保存新的paperDetailUnit
-				}
-			}
-		}
-	}
-
-	/**
-	 * 根据试卷名称、试卷类型检查名称是否存在
-	 *
-	 * @param paperName
-	 * @param paperType
-	 * @param orgId
-	 * @return
-	 * @throws Exception
-	 */
-	public boolean checkPaperName(String paperName, PaperType paperType, String orgId) throws Exception {
-		Query query = new Query();
-		query.addCriteria(Criteria.where("orgId").is(orgId));
-		query.addCriteria(Criteria.where("name").is(paperName.trim()));
-		query.addCriteria(Criteria.where("paperType").is(paperType));
-		List<Paper> papers = this.mongoTemplate.find(query, Paper.class);
-		if (papers != null && papers.size() > 0) {
-			return false;
-		}
-		return true;
-	}
-
-	/**
-	 * 上传音频文件检查
-	 *
-	 * @param paperId
-	 * @param filesName
-	 * @return
-	 */
-	public Map<String, String> checkRadioFile(String paperId, List<String> filesName) {
-		Map<String, String> messageMap = new HashMap<>();
-		// 判断文件名中格式是否正确
-		for (String fileName : filesName) {
-			String[] fileNames = fileName.split("\\.");
-			String fileType = fileNames[fileNames.length - 1];
-			if (sysProperty.getRadioType().indexOf(fileType) < 0) {
-				messageMap.put("errorMsg", fileName + ",文件格式不正确,当前支持格式:" + sysProperty.getRadioType());
-				return messageMap;
-			}
-
-			String pattern_01 = "\\d+_1_\\d{1,2}"; // 题干正则
-			String pattern_02 = "\\d+_2_[A-Z|a-z]_\\d{1,2}"; // 选项正则
-			if (!(Pattern.matches(pattern_01, fileNames[0]) || Pattern.matches(pattern_02, fileNames[0]))) {
-				messageMap.put("errorMsg", fileName + "文件名格式不正确,请检查");
-				return messageMap;
-			}
-		}
-
-		// 根据试卷id,查询该试卷
-		Paper paper = Model.of(paperRepo.findById(paperId));
-
-		// 根据试卷查询所有的小题
-		List<PaperDetailUnit> paperDetailUnits = paperDetailUnitRepo.findByPaperOrderByNumber(paper);
-
-		String names = "";
-		for (PaperDetailUnit paperDetailUnit : paperDetailUnits) {
-			names = names + paperDetailUnit.getNumber().toString() + ",";
-		}
-
-		for (String fileName : filesName) {
-			String fileNames[] = fileName.split("_");
-
-			// 先判断小题号是否正确
-			String fileNameFirst = fileNames[0];
-			if (!names.contains(fileNameFirst)) {
-				messageMap.put("errorMsg", fileName + "文件,试卷中没有对应的小题");
-				return messageMap;
-			}
-
-			// 再判断题干中是否存在ABCD
-			String fileNameSecond = fileNames[1];
-			if (fileNameSecond.equals("1")) {
-				if (fileNames.length > 3) {
-					Matcher m = Pattern.compile(".*[a-zA-Z]+.*").matcher(fileNames[2]);
-					if (m.matches()) {
-						messageMap.put("errorMsg", fileName + "文件名称不对,文件名为题干,但存在选项");
-						return messageMap;
-					}
-				}
-			}
-
-			// 判断选项
-			else if (fileNameSecond.equals("2")) {
-				messageMap = checkOptions(paperDetailUnits, fileNames, fileName);
-				if (messageMap != null) {
-					return messageMap;
-				}
-				messageMap = new HashMap<>();
-			} else {
-				messageMap.put("errorMsg", fileName + "文件名称不对,无法识别为题干或选项 ");
-				return messageMap;
-			}
-		}
-
-		messageMap.put("errorMsg", "OK");
-		return messageMap;
-	}
-
-	// 判断选项
-	public Map<String, String> checkOptions(List<PaperDetailUnit> paperDetailUnits, String fileNames[],
-			String fileName) {
-		Map<String, String> messageMap = new HashMap<>();
-		for (PaperDetailUnit paperDetailUnit : paperDetailUnits) {
-			if (paperDetailUnit.getNumber().toString().equals(fileNames[0])) {
-				// 判断是否为选择题
-				if (paperDetailUnit.getQuestionType() != QuesStructType.SINGLE_ANSWER_QUESTION
-						&& paperDetailUnit.getQuestionType() != QuesStructType.MULTIPLE_ANSWER_QUESTION) {
-					Matcher m = Pattern.compile(".*[a-zA-Z]+.*").matcher(fileNames[2]);
-					if (m.matches()) {
-						messageMap.put("errorMsg", fileName + "文件名称有误,题目不是选择题");
-						return messageMap;
-					}
-					break;
-				} else {
-					List<QuesOption> options = paperDetailUnit.getQuestion().getQuesOptions();
-					String option = "";
-					for (QuesOption quesOption : options) {
-						option = option + quesOption.getNumber() + ",";
-					}
-					Integer integer = CommonUtils.characterToNumber(fileNames[2]);
-					if (!option.contains(integer.toString())) {
-						messageMap.put("errorMsg", fileName + "文件名称有误,题目中没有对应的" + fileNames[2] + "选项");
-						return messageMap;
-					}
-					break;
-				}
-			}
-		}
-		return null;
-	}
-
-	/**
-	 * 上传音频文件到又拍云
-	 *
-	 * @param files
-	 * @param paperId
-	 * @throws IOException
-	 */
-	public void uploadRadio(List<MultipartFile> files, String paperId, User user) {
-		// 根据试卷id,查询该试卷
-		Paper paper = Model.of(paperRepo.findById(paperId));
-
-		for (MultipartFile file : files) {
-			// 判断文件大小
-			long fileSize = file.getSize();
-			int size = Integer.parseInt(sysProperty.getAudioMaxsize());
-			if (fileSize > (size * 1048576L)) {
-				throw new StatusException("400", "音频文件过大,限制" + size + "M内!");
-			}
-
-			// 根据试卷查询所有的小题,根据文件名匹配出当前小题ID
-			String numbers[] = file.getOriginalFilename().split("_");
-			if (numbers.length < 3) {
-				throw new StatusException("400", "音频文件命名格式错误!");
-			}
-
-			PaperDetailUnit unit = paperDetailUnitRepo.findByPaperAndNumber(paper, Integer.valueOf(numbers[0]));
-			if (unit == null || unit.getQuestion() == null) {
-				throw new StatusException("400", "对应试题不存在!");
-			}
-
-			Question question = unit.getQuestion();
-			uploadAudioFile(paperId, question.getId(), file, user);
-			appendAudioTag(file.getOriginalFilename(), question.getId());
-
-			// 清除缓存
-			this.clearQuestionCache(question.getId());
-		}
-
-		// 删除服务器文件夹
-		String mp3DirectoryPath = TEMP_FILE_EXP + File.separator + paperId;
-		try {
-			File mp3Directory = new File(mp3DirectoryPath);
-			FileUtils.deleteDirectory(mp3Directory);
-		} catch (IOException e) {
-			LOG.error(e.getMessage(), e);
-		}
-	}
-
-	/**
-	 * 上传音频文件至又拍云
-	 */
-	private void uploadAudioFile(String paperId, String questionId, MultipartFile file, User user) {
-		// 文件名包含随机数,防止缓存
-		int randomNumber = random.nextInt(1000);
-		final String mp3FileName = questionId + "_" + randomNumber + "_" + file.getOriginalFilename();
-
-		try {
-			String audioFilePath = String.format(FileConstants.RADIO_UPLOAD_PATH, mp3FileName);
-			FssFileInfo result = FssFactory.getInstance().writeFile(audioFilePath, file.getBytes(), null);
-
-			// 保存记录
-			QuestionAudio audio = new QuestionAudio(questionId, file.getOriginalFilename(), result.getFilePath());
-			questionAudioService.saveQuestionAudio(audio, user);
-		} catch (Exception e) {
-			LOG.error(e.getMessage(), e);
-			throw new StatusException("500", "音频文件保存失败!");
-		}
-	}
-
-	/**
-	 * 音频文件插入到标签
-	 */
-	private void appendAudioTag(String fileName, String questionId) {
-		QuestionAudio questionAudio = questionAudioService.findByQuestionIdAndFileName(questionId, fileName);
-		if (questionAudio == null) {
-			return;
-		}
-
-		Question question = Model.of(quesRepo.findById(questionAudio.getQuestionId()));
-
-		// 正则匹配音频标签
-		Pattern audioPattern = Pattern.compile(String.format("<a id=\"[\\d,\\w]+\" name=\"%s\"></a>", fileName));
-		final String audioTag = String.format("<a id=\"%s\" name=\"%s\"></a>", questionAudio.getId(), fileName);
-
-		String numbers[] = fileName.split("_");
-		if (numbers[1].equals("1")) {
-			// 处理题干
-			String quesBody = question.getQuesBody();
-			if (StringUtils.isBlank(quesBody)) {
-				question.setQuesBody("<p>" + audioTag + "</p>");
-			} else {
-				Matcher matcher = audioPattern.matcher(quesBody);
-				if (matcher.find()) {
-					// 已存在音频标签则直接替换
-					question.setQuesBody(matcher.replaceAll(audioTag));
-				} else {
-					// 不存在音频标签则添加
-					question.setQuesBody(quesBody + "<p>" + audioTag + "</p>");
-				}
-			}
-		} else {
-			// 处理选项
-			for (QuesOption quesOption : question.getQuesOptions()) {
-				Integer optNumber = CommonUtils.characterToNumber(numbers[2]);
-				if (!quesOption.getNumber().equals(optNumber.toString())) {
-					continue;
-				}
-
-				String optionBody = quesOption.getOptionBody();
-				if (StringUtils.isBlank(optionBody)) {
-					quesOption.setOptionBody("<p>" + audioTag + "</p>");
-					continue;
-				}
-
-				Matcher matcher = audioPattern.matcher(optionBody);
-				if (matcher.find()) {
-					// 已存在音频标签则直接替换
-					quesOption.setOptionBody(matcher.replaceAll(audioTag));
-				} else {
-					// 不存在音频标签则添加
-					quesOption.setOptionBody(optionBody + "<p>" + audioTag + "</p>");
-				}
-			}
-		}
-
-		question.setHasAudio(true);
-		quesRepo.save(question);
-	}
-
-	@Override
-	public Map<String, Object> getPaperPDF(String paperId, String type) {
-		PaperExp paperExp = getPaperDto(paperId);
-		Map<String, Object> map = new HashMap<>();
-		map.put("courseName", paperExp.getCourseName());
-		map.put("courseNo", paperExp.getCourseNo());
-		List<String> htmlList = new ArrayList<>();
-		if (paperExp.getPaperDetails() != null && paperExp.getPaperDetails().size() > 0) {
-			for (PaperDetailExp paperDetail : paperExp.getPaperDetails()) {
-				// 添加大题标题
-				if (StringUtils.isBlank(paperDetail.getTitle())) {
-					// htmlList.add(("<p>"+paperDetail.getCnNum()+"、"+paperDetail.getName()+"</p>").replaceAll("'",
-					// "&apos"));
-					htmlList.add(("<p class='paperDetailTitle'>" + paperDetail.getCnNum() + "、" + paperDetail.getName()
-							+ "</p>").replaceAll("'", "&apos"));
-				} else {
-					htmlList.add("<p class='paperDetailTitle'>" + paperDetail.getCnNum() + "、" + paperDetail.getName()
-							+ paperDetail.getTitle() + "</p>");
-				}
-				if (paperDetail.getPaperDetailUnits() != null && paperDetail.getPaperDetailUnits().size() > 0) {
-					for (PaperDetailUnitExp paperDetailUnitExp : paperDetail.getPaperDetailUnits()) {
-						Question question = paperDetailUnitExp.getQuestion();
-						if (type.equals("paper")) {
-							// 添加题干
-							String questionBody = CommonUtils.deleteHtmlP(paperDetailUnitExp.getNumber() + "."
-									+ question.getQuesBody() + "(" + paperDetailUnitExp.getScore() + "分)");
-							htmlList.add("<p class='questionBody'>" + questionBody + "</p>");
-							// 判断是否为选择题
-							if (paperDetailUnitExp.getQuestionType() == QuesStructType.SINGLE_ANSWER_QUESTION
-									|| paperDetailUnitExp
-											.getQuestionType() == QuesStructType.MULTIPLE_ANSWER_QUESTION) {
-								for (QuesOption quesOption : question.getQuesOptions()) {
-									// 添加选项
-									String questionOption = CommonUtils.deleteHtmlP(
-											CommonUtils.getOptionNum(Integer.parseInt(quesOption.getNumber()) - 1) + "."
-													+ quesOption.getOptionBody());
-									htmlList.add("<p class='selectOption'>" + questionOption + "</p>");
-								}
-							}
-							// 判断是否为套题
-							if (paperDetailUnitExp.getQuestionType() == QuesStructType.NESTED_ANSWER_QUESTION) {
-								// 得到子题
-								List<Question> subQuestions = question.getSubQuestions();
-								for (Question subQuestion : subQuestions) {
-									// 添加子题题干
-									String subQuestionBody = CommonUtils
-											.deleteHtmlP(subQuestion.getQuesParams().get("number") + "."
-													+ subQuestion.getQuesBody() + "(" + subQuestion.getScore() + "分)");
-									htmlList.add("<p class='questionBody'>" + subQuestionBody + "</p>");
-									// 判断是否为选择题
-									if (subQuestion.getQuestionType() == QuesStructType.SINGLE_ANSWER_QUESTION
-											|| subQuestion
-													.getQuestionType() == QuesStructType.MULTIPLE_ANSWER_QUESTION) {
-										for (QuesOption quesOption : subQuestion.getQuesOptions()) {
-											// 添加选项
-											String questionOption = CommonUtils.deleteHtmlP(CommonUtils
-													.getOptionNum(Integer.parseInt(quesOption.getNumber()) - 1) + "."
-													+ quesOption.getOptionBody());
-											htmlList.add("<p class='selectOption'>" + questionOption + "</p>");
-										}
-									}
-								}
-							}
-						} else {
-							// 判断是否为套题
-							if (paperDetailUnitExp.getQuestionType() == QuesStructType.NESTED_ANSWER_QUESTION) {
-								// 得到子题
-								List<Question> subQuestions = question.getSubQuestions();
-								for (Question subQuestion : subQuestions) {
-									// 添加答案
-									String questionAnswer = CommonUtils
-											.deleteHtmlP(subQuestion.getQuesParams().get("number") + "."
-													+ subQuestion.getQuesAnswer() + "(" + subQuestion.getScore()
-													+ "分)");
-									htmlList.add("<p class='questionAnswer'>" + questionAnswer + "</p>");
-								}
-							} else {
-								// 添加答案
-								String questionAnswer = CommonUtils.deleteHtmlP(paperDetailUnitExp.getNumber() + "."
-										+ question.getQuesAnswer() + "(" + paperDetailUnitExp.getScore() + "分)");
-								htmlList.add("<p class='questionAnswer'>" + questionAnswer + "</p>");
-							}
-						}
-
-					}
-				}
-			}
-		}
-		map.put("htmlList", htmlList);
-		return map;
-	}
-
-	@SuppressWarnings("unused")
-	@Override
-	public String sendPrint(String paperId, String orgId, String examId) {
-		// 查询原paper对象
-		Paper paper = Model.of(paperRepo.findById(paperId));
-		SyncCoursePaperBean bean = new SyncCoursePaperBean();
-		bean.setOrgId(Long.valueOf(orgId));
-		bean.setExamId(Long.valueOf(examId));
-		Course course = courseService.getCourse(Long.valueOf(orgId), paper.getCourse().getCode());
-		bean.setCourseId(Long.valueOf(course.getId()));
-		bean.setCourseCode(paper.getCourse().getCode());
-		bean.setCourseName(paper.getCourse().getName());
-		bean.setPaperId(paper.getId());
-		bean.setPaperName(paper.getName());
-		SyncCoursePaperReq req = new SyncCoursePaperReq();
-		req.setBean(bean);
-		SyncCoursePaperResp resp = coursePaperCloudService.syncCoursePaper(req);
-		return "success";
-	}
-
-	@Override
-	public String findQuestionStructure(String paperId) throws Exception {
-		// 根据paperId查询新的对象
-		ExportPaperAbstractService exportPaperAbstractService = (ExportPaperAbstractService) SpringContextHolder
-				.getBean("exportPaperAbstractService");
-		DownloadPaperDto dto = new DownloadPaperDto();
-		dto.setPaperId(paperId);
-		dto.setSeqMode(PaperSeqMode.MODE3);
-		PaperExp paperExp = exportPaperAbstractService.initPaperExp(dto);
-		LOG.info("已经获取试卷");
-		// 得到试卷中的客观大题
-		List<PaperDetailExp> objectiveDetails = exportPaperAbstractService.getAllObjectiveDetails(paperExp);
-		// 客观题中如果有套题,要拆开
-		List<PaperDetailExp> newObjectiveDetails = buildPaperDetailExp(objectiveDetails);
-		// 生成客观题数集合
-		List<ObjectiveQuestionStructure> objectiveQuestionStructureList = new ArrayList<>();
-		for (PaperDetailExp paperDetailExp : newObjectiveDetails) {
-			for (PaperDetailUnitExp unit : paperDetailExp.getPaperDetailUnits()) {
-				objectiveQuestionStructureList
-						.add(new ObjectiveQuestionStructure(paperExp, paperDetailExp, unit, null));
-			}
-		}
-		LOG.info("生成客观题数集合");
-		// 得到试卷中的主观大题
-		List<PaperDetailExp> subjectiveDetails = exportPaperAbstractService.getAllSubjectiveDetails(paperExp);
-		// 生成主观题数集合
-		List<SubjectiveQuestionStructure> subjectiveQuestionStructureList = new ArrayList<>();
-		for (PaperDetailExp paperDetailExp : subjectiveDetails) {
-			for (PaperDetailUnitExp unit : paperDetailExp.getPaperDetailUnits()) {
-				subjectiveQuestionStructureList
-						.add(new SubjectiveQuestionStructure(paperExp, paperDetailExp, unit, null));
-			}
-		}
-		LOG.info("生成主观题数集合");
-		PaperQuestionStructureInfo info = new PaperQuestionStructureInfo();
-		info.setObjectives(objectiveQuestionStructureList);
-		info.setSubjectives(subjectiveQuestionStructureList);
-		String jsonResp = JsonUtil.toJson(info);
-		LOG.info("jsonResp:" + jsonResp);
-		return jsonResp;
-	}
-
-	public List<PaperDetailExp> buildPaperDetailExp(List<PaperDetailExp> objectiveDetails) {
-		// 1.得到所有客观题大题的类型
-		Set<QuesStructType> types = new HashSet<>();
-		for (PaperDetailExp paperDetailExp : objectiveDetails) {
-			types.add(QuesStructType.getQuesStructTypeById(paperDetailExp.getSortNumber()));
-		}
-		// 2.生成新的大题集合
-		List<PaperDetailExp> newObjs = new ArrayList<>();
-		for (QuesStructType type : types) {
-			for (PaperDetailExp paperDetailExp : objectiveDetails) {
-				if (paperDetailExp.getSortNumber().equals(type.getId())) {
-					// 生成新的大题
-					PaperDetailExp newPaperDetailExp = new PaperDetailExp();
-					// 生成新的小题
-					List<PaperDetailUnitExp> newPaperDetailUnits = new ArrayList<>();
-					// 得到旧大题下的所有小题
-					List<PaperDetailUnitExp> paperDetailUnits = paperDetailExp.getPaperDetailUnits();
-					for (PaperDetailUnitExp paperDetailUnitExp : paperDetailUnits) {
-						if (paperDetailUnitExp.getQuestionType() != QuesStructType.NESTED_ANSWER_QUESTION) {
-							newPaperDetailUnits.add(paperDetailUnitExp);
-						} else {
-							List<Question> subQuestions = paperDetailUnitExp.getQuestion().getSubQuestions();
-							if (subQuestions != null && subQuestions.size() > 0) {
-								for (int i = 0; i < subQuestions.size(); i++) {
-									newPaperDetailUnits.add(new PaperDetailUnitExp(type, subQuestions.get(i)));
-								}
-							}
-						}
-					}
-					// 设置小题
-					newPaperDetailExp.setPaperDetailUnits(newPaperDetailUnits);
-					// 设置大题题号
-					newPaperDetailExp.setNumber(Integer.parseInt(type.getId() + ""));
-					newPaperDetailExp.setSortNumber(paperDetailExp.getSortNumber());
-					newObjs.add(newPaperDetailExp);
-				}
-			}
-		}
-		// 刷一遍number
-		int num = 0;
-		for (QuesStructType type : types) {
-			for (int i = 0; i < newObjs.size(); i++) {
-				if (newObjs.get(i).getSortNumber().equals(type.getId())) {
-					List<PaperDetailUnitExp> exps = newObjs.get(i).getPaperDetailUnits();
-					for (int j = 0; j < exps.size(); j++) {
-						num++;
-						exps.get(j).setNumber(num);
-					}
-				}
-			}
-		}
-		return newObjs;
-	}
-
-	@Override
-	public PaperExp getDownPaperExp(String paperId) {
-		Paper paper = Model.of(paperRepo.findById(paperId));
-		// 创建paperDto
-		PaperExp paperExp = BeanCopierUtil.copyProperties(paper, PaperExp.class);
-		paperExp.setCourseName(paper.getCourse().getName());
-		paperExp.setCourseNo(paper.getCourse().getCode());
-		paperExp.setCourse(paper.getCourse());
-		// 获取大题
-		List<PaperDetail> paperDetails = paperDetailRepo.findByPaperOrderByNumber(paper);
-		List<PaperDetailExp> paperDetailExps = new ArrayList<>();
-		for (PaperDetail paperDetail : paperDetails) {
-			PaperDetailExp paperDetailExp = new PaperDetailExp();
-			BeanUtils.copyProperties(paperDetail, paperDetailExp);
-			if (StringUtils.isBlank(paperDetailExp.getName())) {
-				paperDetailExp.setName("默认大题");
-			}
-			paperDetailExps.add(paperDetailExp);
-		}
-		// 封装小题
-		for (int i = 0; i < paperDetailExps.size(); i++) {
-			List<PaperDetailUnit> paperDetailUnits = paperDetailUnitRepo
-					.findByPaperDetailOrderByNumber(paperDetails.get(i));
-			if (paperDetailUnits != null && paperDetailUnits.size() > 0) {
-				List<PaperDetailUnitExp> paperDetailUnitExps = new ArrayList<>();
-				for (PaperDetailUnit paperDetailUnit : paperDetailUnits) {
-					PaperDetailUnitExp paperDetailUnitExp = new PaperDetailUnitExp();
-					BeanUtils.copyProperties(paperDetailUnit, paperDetailUnitExp);
-					paperDetailUnitExps.add(paperDetailUnitExp);
-				}
-				paperDetailExps.get(i).setPaperDetailUnits(paperDetailUnitExps);
-				paperDetailExps.get(i).setUnitCount(paperDetailUnitExps.size());
-			} else {
-				paperDetailExps.get(i).setUnitCount(0);
-			}
-		}
-		paperExp.setPaperDetails(paperDetailExps);
-		if (paperExp.getPaperDetails() == null || paperExp.getPaperDetails().size() == 0) {
-			return paperExp;
-		}
-		int mainNum = 0;
-		List<PaperDetailExp> paperDetailExpList = paperExp.getPaperDetails();
-		for (PaperDetailExp paperDetail : paperDetailExpList) {
-			// 大题序号
-			paperDetail.setNumber(++mainNum);
-			paperDetail.setCnNum(CommonUtils.toCHNum(paperDetail.getNumber()));
-			if (paperDetail.getPaperDetailUnits() == null || paperDetail.getPaperDetailUnits().size() == 0) {
-				throw new StatusException("500", "第" + mainNum + "大题没有小题");
-			}
-			if (paperDetail != null && paperDetail.getPaperDetailUnits() != null
-					&& paperDetail.getPaperDetailUnits().size() > 0) {
-				for (PaperDetailUnitExp paperDetailUnit : paperDetail.getPaperDetailUnits()) {
-					Question question = paperDetailUnit.getQuestion();
-					question.setDifficultyDegree(question.getDifficultyDegree() * 10);
-					if (question.getPublicity() == null || question.getPublicity() == true) {
-						paperDetailUnit.setPublicity("公开");
-					} else {
-						paperDetailUnit.setPublicity("非公开");
-					}
-					if (StringUtils.isBlank(paperDetail.getQuesType())) {
-						paperDetail.setQuesType(question.getQuestionType().getName());
-					}
-					// 设置选项
-					List<QuesOption> optionList = paperDetailUnit.getQuestion().getQuesOptions();
-					if (optionList != null && optionList.size() > 0) {
-						// int index = 0;
-						// for (QuesOption quesOption : optionList) {
-						// quesOption.setOptionBodyWord(setOptionNum(quesOption.getOptionBodyWord(),
-						// getOptionNum(index)));
-						// index++;
-						// }
-					}
-					if (question.getQuestionType() != QuesStructType.NESTED_ANSWER_QUESTION) {
-						// 给小题设置序号
-						// question.setQuesBodyWord(setSubQuesNum(question.getQuesBodyWord(),
-						// minNum++));
-						// question.setQuesAnswerWord(setAnswerNum(question.getQuesAnswerWord()));
-						fillProperty(question);
-						if (paperDetail.getFirstScore() == null) {
-							if (question.getScore() == null) {
-								paperDetail.setFirstScore(0d);
-							} else {
-								paperDetail.setFirstScore(question.getScore());
-							}
-						}
-					} else {
-						List<Question> subQuesList = question.getSubQuestions();
-						// 套题小题设置序号
-						if (subQuesList != null && subQuesList.size() > 0) {
-							for (Question subQues : subQuesList) {
-								subQues.setDifficultyDegree(subQues.getDifficultyDegree() * 10);
-								// subQues.setQuesBodyWord(setSubQuesNum(subQues.getQuesBodyWord(), index++));
-								// subQues.setQuesAnswerWord(setAnswerNum(subQues.getQuesAnswerWord()));
-								if (paperDetail.getFirstScore() == null) {
-									if (subQues.getScore() == null) {
-										paperDetail.setFirstScore(0d);
-									} else {
-										paperDetail.setFirstScore(subQues.getScore());
-									}
-								}
-								fillProperty(subQues);
-							}
-						}
-					}
-					List<QuesProperty> quesProperties = question.getQuesProperties();
-					if (quesProperties != null && quesProperties.size() > 0) {
-						QuesProperty quesProperty = quesProperties.get(0);
-						if (quesProperty.getFirstProperty() != null) {
-							paperDetailUnit.setFirstName(quesProperty.getFirstProperty().getName());
-							paperDetailUnit.setFirstCode(quesProperty.getFirstProperty().getCode());
-						}
-						if (quesProperty.getSecondProperty() != null) {
-							paperDetailUnit.setSecondName(quesProperty.getSecondProperty().getName());
-							paperDetailUnit.setSecondCode(quesProperty.getSecondProperty().getCode());
-						}
-					}
-				}
-			}
-		}
-		return paperExp;
-	}
-
-	private void fillProperty(Question question) {
-		List<QuesProperty> ret = new ArrayList<>();
-		List<QuesProperty> quesProperties = question.getQuesProperties();
-		if (quesProperties != null && quesProperties.size() > 0) {
-			for (QuesProperty quesProperty : quesProperties) {
-				if (quesProperty.getFirstProperty() != null && quesProperty.getFirstProperty().getId() != null) {
-					Property curProperty = Model.of(propertyRepo.findById(quesProperty.getFirstProperty().getId()));
-					if (curProperty == null) {
-						continue;
-					}
-					quesProperty.setFirstProperty(curProperty);
-				}
-				if (quesProperty.getSecondProperty() != null && quesProperty.getSecondProperty().getId() != null) {
-					Property curProperty = Model.of(propertyRepo.findById(quesProperty.getSecondProperty().getId()));
-					if (curProperty == null) {
-						continue;
-					}
-					quesProperty.setSecondProperty(curProperty);
-				}
-				ret.add(quesProperty);
-			}
-		}
-		question.setQuesProperties(ret);
-	}
-
-	/**
-	 * 设置题号
-	 *
-	 * @param quesBodyWordMl
-	 * @param num
-	 * @return
-	 * @throws Exception
-	 */
-	// public String setSubQuesNum(String quesBodyWordMl, int num) throws Exception
-	// {
-	// String tmpStr = DocxProcessUtil.BODY_HEADER + quesBodyWordMl +
-	// DocxProcessUtil.BODY_TAIL;
-	// Body body = (Body) XmlUtils.unmarshalString(tmpStr, Context.jc, Body.class);
-	// List<Object> pList = body.getContent();
-	// int index = 0;
-	// for (Object pObj : pList) {
-	// if (index > 0) {
-	// break;
-	// }
-	// P p = (P) pObj;
-	// List<Object> pContent = p.getContent();
-	// R run = new R();
-	// Text text = new Text();
-	// text.setValue(num + ". ");
-	// run.getContent().add(text);
-	// pContent.add(0, run);
-	// index++;
-	// }
-	// StringBuffer pWordMl = new StringBuffer();
-	// for (Object pObj : pList) {
-	// if (pObj instanceof P) {
-	// pWordMl.append(DocxProcessUtil.formatPWordMl(XmlUtils.marshaltoString(pObj)));
-	// }
-	// }
-	// return pWordMl.toString();
-	// }
-
-	/**
-	 * 将数字1,2,3,4转化成A,B,C,D
-	 *
-	 * @param number
-	 * @return
-	 */
-	public String getOptionNum(int number) {
-		char optionNum = (char) (65 + number);
-		return String.valueOf(optionNum);
-	}
-
-	/**
-	 * 设置选项号
-	 *
-	 * @param optionWordMl
-	 * @param num
-	 * @return
-	 * @throws Exception
-	 */
-	// public String setOptionNum(String optionWordMl, String num) throws Exception
-	// {
-	// String tmpStr = DocxProcessUtil.BODY_HEADER + optionWordMl +
-	// DocxProcessUtil.BODY_TAIL;
-	// Body body = (Body) XmlUtils.unmarshalString(tmpStr, Context.jc, Body.class);
-	// List<Object> pList = body.getContent();
-	// int index = 0;
-	// for (Object pObj : pList) {
-	// if (index > 0) {
-	// break;
-	// }
-	// P p = (P) pObj;
-	// List<Object> pContent = p.getContent();
-	// R run = new R();
-	// Text text = new Text();
-	// text.setValue(num + ". ");
-	// run.getContent().add(text);
-	// pContent.add(0, run);
-	// index++;
-	// }
-	// StringBuffer pWordMl = new StringBuffer();
-	// for (Object pObj : pList) {
-	// if (pObj instanceof P) {
-	// pWordMl.append(DocxProcessUtil.formatPWordMl(XmlUtils.marshaltoString(pObj)));
-	// }
-	// }
-	// return pWordMl.toString();
-	// }
-
-	// public String setAnswerNum(String quesBodyWordMl) throws Exception {
-	// String tmpStr = DocxProcessUtil.BODY_HEADER + quesBodyWordMl +
-	// DocxProcessUtil.BODY_TAIL;
-	// Body body = (Body) XmlUtils.unmarshalString(tmpStr, Context.jc, Body.class);
-	// List<Object> pList = body.getContent();
-	// int index = 0;
-	// for (Object pObj : pList) {
-	// if (index > 0) {
-	// break;
-	// }
-	// P p = (P) pObj;
-	// List<Object> pContent = p.getContent();
-	// R run = new R();
-	// Text text = new Text();
-	// text.setValue("[答案]:");
-	// run.getContent().add(text);
-	// pContent.add(0, run);
-	// index++;
-	// }
-	// StringBuffer pWordMl = new StringBuffer();
-	// for (Object pObj : pList) {
-	// if (pObj instanceof P) {
-	// pWordMl.append(DocxProcessUtil.formatPWordMl(XmlUtils.marshaltoString(pObj)));
-	// }
-	// }
-	// return pWordMl.toString();
-	// }
-	@Override
-	public int getQuestionTypeNumbers(String paperId, Integer publicityType, Integer difficultyType) {
-		if (publicityType == null || difficultyType == null) {
-			return 0;
-		}
-		Boolean publicity = null;
-		String difficulty = null;
-		if (publicityType == 1) {
-			publicity = true;
-		} else {
-			publicity = false;
-		}
-		if (difficultyType == 1) {
-			difficulty = "易";
-		} else if (difficultyType == 2) {
-			difficulty = "中";
-		} else {
-			difficulty = "难";
-		}
-		String needType = publicity + "-" + difficulty;
-		Paper paper = Model.of(paperRepo.findById(paperId));
-		List<PaperDetailUnit> units = paperDetailUnitRepo.findByPaperOrderByNumber(paper);
-		if (units != null && units.size() > 0) {
-			int total = 0;
-			for (PaperDetailUnit unit : units) {
-				if (unit.getQuestion().getPublicity() == null) {
-					unit.getQuestion().setPublicity(true);
-				}
-				if (unit.getQuestion().getDifficulty() == null) {
-					unit.getQuestion().setDifficulty("中");
-				}
-				String factType = unit.getQuestion().getPublicity() + "-" + unit.getQuestion().getDifficulty();
-				if (needType.equals(factType)) {
-					total += 1;
-				}
-			}
-			return total;
-		}
-		return 0;
-	}
-
-	@Override
-	public double getQuestionTypeScore(String paperId, Integer publicityType, Integer difficultyType) {
-		if (publicityType == null || difficultyType == null) {
-			return 0;
-		}
-		Boolean publicity = null;
-		String difficulty = null;
-		if (publicityType == 1) {
-			publicity = true;
-		} else {
-			publicity = false;
-		}
-		if (difficultyType == 1) {
-			difficulty = "易";
-		} else if (difficultyType == 2) {
-			difficulty = "中";
-		} else {
-			difficulty = "难";
-		}
-		String needType = publicity + "-" + difficulty;
-		Paper paper = Model.of(paperRepo.findById(paperId));
-		List<PaperDetailUnit> units = paperDetailUnitRepo.findByPaperOrderByNumber(paper);
-		if (units != null && units.size() > 0) {
-			double total = 0;
-			BigDecimal b1 = BigDecimal.valueOf(total);
-			for (PaperDetailUnit unit : units) {
-				if (unit.getQuestion().getPublicity() == null) {
-					unit.getQuestion().setPublicity(true);
-				}
-				if (unit.getQuestion().getDifficulty() == null) {
-					unit.getQuestion().setDifficulty("中");
-				}
-				String factType = unit.getQuestion().getPublicity() + "-" + unit.getQuestion().getDifficulty();
-				if (needType.equals(factType)) {
-					BigDecimal b2 = BigDecimal.valueOf(unit.getScore());
-					b1 = b1.add(b2);
-				}
-			}
-			return b1.doubleValue();
-		}
-		return 0;
-	}
-
-	private void clearPaperCache(String paperId) {
-		// 清理与当前试卷相关的缓存
-		// final String patternKey = CACHE_KEY_PAPER + "*" + paperId;
-		// Set<String> keys = redisTemplate.keys(patternKey);
-		// if (CollectionUtils.isNotEmpty(keys)) {
-		// redisTemplate.delete(keys);
-		// }
-		extractConfigPaperCache.remove(paperId);
-		basePaperCache.remove(paperId);
-	}
-
-	private void clearQuestionCache(String questionId) {
-		// 清理与当前试题相关的缓存
-		// final String patternKey = CACHE_KEY_QUESTION + "*" + questionId;
-		// Set<String> keys = redisTemplate.keys(patternKey);
-		// if (CollectionUtils.isNotEmpty(keys)) {
-		// redisTemplate.delete(keys);
-		// }
-		questionCache.remove(questionId);
-		questionAnswerCache.remove(questionId);
-	}
-
-	@Override
-	public List<PaperAnswerDomain> answerExport(Paper paper) {
-		List<PaperAnswerDomain> ret = new ArrayList<PaperAnswerDomain>();
-		List<PaperDetail> paperDetails = paperDetailRepo.findByPaperOrderByNumber(paper);
-		if (paperDetails != null && paperDetails.size() > 0) {
-			for (PaperDetail paperDetail : paperDetails) {
-				List<PaperDetailUnit> paperDetailUnits = paperDetailUnitRepo
-						.findByPaperDetailOrderByNumber(paperDetail);
-				if (paperDetailUnits != null && paperDetailUnits.size() > 0) {
-					for (PaperDetailUnit paperDetailUnit : paperDetailUnits) {
-						Question ques = paperDetailUnit.getQuestion();
-						if (QuesStructType.NESTED_ANSWER_QUESTION.equals(ques.getQuestionType())) {
-							List<Question> subques = ques.getSubQuestions();
-							if (subques != null && subques.size() > 0) {
-								for (int i = 0; i < subques.size(); i++) {
-									Question subq = subques.get(i);
-									PaperAnswerDomain domain = new PaperAnswerDomain();
-									domain.setName(paperDetail.getName());
-									domain.setNumber(paperDetail.getNumber());
-									domain.setSubNumber(paperDetailUnit.getNumber());
-									domain.setSubType(subq.getQuestionType().getName());
-									domain.setChildNumber(i + 1);
-									domain.setAnswer(subq.getQuesAnswer());
-									ret.add(domain);
-								}
-							}
-						} else {
-							PaperAnswerDomain domain = new PaperAnswerDomain();
-							domain.setName(paperDetail.getName());
-							domain.setNumber(paperDetail.getNumber());
-							domain.setSubNumber(paperDetailUnit.getNumber());
-							domain.setSubType(paperDetailUnit.getQuestionType().getName());
-							domain.setAnswer(ques.getQuesAnswer());
-							ret.add(domain);
-						}
-					}
-				}
-			}
-		}
-		return ret;
-	}
-
-	@Override
-	public void answerImport(Paper paper, MultipartFile dataFile) {
-		File file = new File(systemProperties.getTempDataDir() + File.separator + UUID.randomUUID() + ".xlsx");
-		try {
-			file.createNewFile();
-			dataFile.transferTo(file);
-			List<String[]> lineList = getData(file);
-			if (lineList == null || lineList.size() == 0) {
-				throw new StatusException("500", "没有导入的数据");
-			}
-			List<PaperAnswerDomain> ret = new ArrayList<PaperAnswerDomain>();
-			for (int i = 0; i < lineList.size(); i++) {
-				String[] line = lineList.get(i);
-				PaperAnswerDomain domain = new PaperAnswerDomain();
-				domain.setNumber(getNumber(trimAndNullIfBlank(line[0])));
-				domain.setName(trimAndNullIfBlank(line[1]));
-				domain.setSubNumber(getNumber(trimAndNullIfBlank(line[2])));
-				domain.setChildNumber(getNumber(trimAndNullIfBlank(line[3])));
-				domain.setSubType(trimAndNullIfBlank(line[4]));
-				domain.setAnswer(trimAndNullIfBlank(line[5]));
-				ret.add(domain);
-			}
-			if (ret == null || ret.size() == 0) {
-				throw new StatusException("500", "没有导入的数据");
-			}
-			diposeAnswer(paper, ret);
-		} catch (StatusException e) {
-			throw e;
-		} catch (Exception e) {
-			throw new StatusException("500", "导入答案失败:" + e.getMessage(), e);
-		} finally {
-			FileUtil.deleteFile(file.getAbsolutePath());
-		}
-	}
-
-	private List<String[]> getData(File file) {
-		XSSFWorkbook wb = null;
-		try {
-			try {
-				wb = new XSSFWorkbook(file);
-			} catch (Exception e) {
-				throw new StatusException("500", "文件类型错误");
-			}
-			List<String[]> outerList = new ArrayList<String[]>();
-			XSSFSheet sheet = wb.getSheetAt(0);
-			for (int i = 1; i <= sheet.getLastRowNum(); i++) {
-				String[] innerList = new String[6];
-				XSSFRow row = sheet.getRow(i);
-				for (int j = 0; j < 6; j++) {
-					XSSFCell cell = row.getCell(j);
-					if (cell != null) {
-						String cellinfo = cell.getStringCellValue();
-						innerList[j] = cellinfo;
-					} else {
-						innerList[j] = "";
-					}
-				}
-				if (!isEmpty(innerList)) {
-					if (StringUtils.isEmpty(innerList[0])) {
-						throw new StatusException("500", "文件类型错误" + (i + 1) + "行大题号不能为空");
-					}
-					if (StringUtils.isEmpty(innerList[2])) {
-						throw new StatusException("500", "文件类型错误" + (i + 1) + "行小题号不能为空");
-					}
-					outerList.add(innerList);
-				}
-			}
-			return outerList;
-		} finally {
-			if (wb != null) {
-				try {
-					wb.close();
-				} catch (IOException e) {
-					LOG.debug("wb.close() error " + e);
-				}
-			}
-		}
-
-	}
-
-	private boolean isEmpty(String[] ss) {
-		for (String s : ss) {
-			if (StringUtils.isNotEmpty(s)) {
-				return false;
-			}
-		}
-		return true;
-	}
-
-	private void diposeAnswer(Paper paper, List<PaperAnswerDomain> domains) {
-		Map<String, PaperAnswerDomain> answerMap = new LinkedHashMap<String, PaperAnswerDomain>();
-		for (PaperAnswerDomain domain : domains) {
-			String key = null;
-			if (domain.getChildNumber() != null) {
-				key = domain.getSubNumber() + "-" + domain.getChildNumber();
-			} else {
-				key = domain.getSubNumber().toString();
-			}
-			if (answerMap.get(key) == null) {
-				answerMap.put(key, domain);
-			} else {
-				throw new StatusException("500", "导入数据中第" + domain.getSubNumber() + "小题"
-						+ (domain.getChildNumber() != null ? "第" + domain.getChildNumber() + "子题" : "") + "重复");
-			}
-		}
-
-		Map<String, Question> quesMap = new LinkedHashMap<String, Question>();
-		List<PaperDetailUnit> paperDetailUnits = paperDetailUnitRepo.findByPaperIdOrderByNumber(paper.getId());
-		for (PaperDetailUnit unit : paperDetailUnits) {
-			Question qu = unit.getQuestion();
-			if (QuesStructType.NESTED_ANSWER_QUESTION.equals(qu.getQuestionType())) {
-				for (int i = 0; i < unit.getQuestion().getSubQuestions().size(); i++) {
-					quesMap.put(unit.getNumber() + "-" + (i + 1), unit.getQuestion().getSubQuestions().get(i));
-				}
-			} else {
-				quesMap.put(unit.getNumber().toString(), qu);
-			}
-		}
-
-		Set<String> saveQuestion = new HashSet<String>();
-		for (String key : answerMap.keySet()) {
-			PaperAnswerDomain domain = answerMap.get(key);
-			Question qu = quesMap.get(key);
-			if (qu == null) {
-				answerFomatErr(domain.getSubNumber(), domain.getChildNumber(), "试题信息不存在");
-			}
-			saveQuestion.add(domain.getSubNumber().toString());
-		}
-
-		Set<String> updateQuesIds = new HashSet<String>();
-		List<Question> ques = new ArrayList<Question>();
-		for (PaperDetailUnit unit : paperDetailUnits) {
-			Question qu = unit.getQuestion();
-			if (saveQuestion.contains(unit.getNumber().toString())) {
-				if (QuesStructType.NESTED_ANSWER_QUESTION.equals(qu.getQuestionType())) {
-					for (int i = 0; i < unit.getQuestion().getSubQuestions().size(); i++) {
-						if (answerMap.get(unit.getNumber() + "-" + (i + 1)) != null) {
-							checkAndSetAnswer(unit.getQuestion().getSubQuestions().get(i),
-									answerMap.get(unit.getNumber() + "-" + (i + 1)).getAnswer(), unit.getNumber(),
-									i + 1);
-							updateQuesIds.add(qu.getId());
-						}
-					}
-				} else {
-					if (answerMap.get(unit.getNumber().toString()) != null) {
-						checkAndSetAnswer(qu, answerMap.get(unit.getNumber().toString()).getAnswer(), unit.getNumber(),
-								null);
-						updateQuesIds.add(qu.getId());
-					}
-				}
-			}
-			ques.add(qu);
-		}
-		quesRepo.saveAll(ques);
-		// 清除缓存
-		for (String qid : updateQuesIds) {
-			paperDetailUnitService.clearQuestionCache(qid);
-		}
-	}
-
-	private void checkAndSetAnswer(Question question, String answer, Integer subNum, Integer childNum) {
-		String fomatErrMsg = "答案格式错误";
-		if (answer != null) {
-			answer = answer.trim();
-		}
-		if (StringUtils.isBlank(answer)) {
-			return;
-		}
-		if (QuesStructType.SINGLE_ANSWER_QUESTION.equals(question.getQuestionType())
-				|| QuesStructType.MULTIPLE_ANSWER_QUESTION.equals(question.getQuestionType())) {
-			answer = answer.replaceAll("\\s*", "");
-			if (QuesStructType.SINGLE_ANSWER_QUESTION.equals(question.getQuestionType())) {
-				if (answer.length() > 1) {
-					answerFomatErr(subNum, childNum, fomatErrMsg);
-				}
-			}
-			String[] pAnswerArray;
-			if (answer.indexOf(",") != -1) {
-				pAnswerArray = answer.split(",");
-			} else {
-				pAnswerArray = answer.split("");
-			}
-			List<QuesOption> options = question.getQuesOptions();
-			List<String> optionNumList = new ArrayList<>();
-			for (QuesOption quesOption : options) {
-				Integer numInteger = Integer.parseInt(quesOption.getNumber());
-				char word = (char) (numInteger + 64);
-				optionNumList.add(word + "");
-			}
-			for (String option : pAnswerArray) {
-				String pattern = "[A-Z]";
-				if (!Pattern.matches(pattern, option)) {
-					answerFomatErr(subNum, childNum, fomatErrMsg);
-				}
-				if (!optionNumList.contains(option)) {
-					answerFomatErr(subNum, childNum, "答案选项不存在");
-				}
-			}
-			if (pAnswerArray.length > 1) {
-				question.setQuesAnswer(StringUtils.join(pAnswerArray, ","));
-			} else {
-				question.setQuesAnswer(answer);
-			}
-			processSelectOption(question);
-		} else if (QuesStructType.BOOL_ANSWER_QUESTION.equals(question.getQuestionType())) {
-			if (!answer.equals("正确") && !answer.equals("错误")) {
-				answerFomatErr(subNum, childNum, fomatErrMsg);
-			}
-			question.setQuesAnswer(answer);
-		} else if (QuesStructType.FILL_BLANK_QUESTION.equals(question.getQuestionType())) {
-			String body = question.getQuesBody();
-			Document bodyDoc = Jsoup.parse(body);
-			String bodyText = bodyDoc.body().html();
-			Document answerDoc = null;
-			try {
-				answerDoc = Jsoup.parse(answer);
-			} catch (Exception e) {
-				answerFomatErr(subNum, childNum, "答案格式html解析错误");
-			}
-			if (answerDoc.body().childrenSize() != 0) {
-				String answerText = answerDoc.body().html();
-				if (StringUtils.isNotBlank(answerText)) {
-					if (getSubStringCount(bodyText, "###") != answerText.split("##").length) {
-						answerFomatErr(subNum, childNum, "题干空格数量和答案数量不一致");
-					}
-				}
-			}
-			question.setQuesAnswer(answer);
-		} else if (QuesStructType.TEXT_ANSWER_QUESTION.equals(question.getQuestionType())) {
-			try {
-				Jsoup.parse(answer);
-			} catch (Exception e) {
-				answerFomatErr(subNum, childNum, "答案格式html解析错误");
-			}
-			question.setQuesAnswer(answer);
-		}
-
-	}
-
-	private int getSubStringCount(String src, String find) {
-		int o = 0;
-		int index = -1;
-		while ((index = src.indexOf(find, index)) > -1) {
-			++index;
-			++o;
-		}
-		return o;
-	}
-
-	private void processSelectOption(Question question) {
-		String answer = question.getQuesAnswer();
-		if (StringUtils.isNotBlank(answer)) {
-			String[] answerArray = answer.split(",");
-			for (int i = 0; i < question.getQuesOptions().size(); i++) {
-				QuesOption quesOption = question.getQuesOptions().get(i);
-				char number = (char) (Integer.parseInt(quesOption.getNumber()) + 64);
-				if (ArrayUtils.contains(answerArray, String.valueOf(number))) {
-					quesOption.setIsCorrect((short) 1);
-				} else {
-					quesOption.setIsCorrect((short) 0);
-				}
-			}
-		}
-	}
-
-	private void answerFomatErr(Integer subNum, Integer childNum, String msg) {
-		throw new StatusException("500",
-				"导入数据中第" + subNum + "小题" + (childNum != null ? "第" + childNum + "子题" : "") + msg);
-	}
-
-	private String trimAndNullIfBlank(String s) {
-		if (StringUtils.isBlank(s)) {
-			return null;
-		}
-		return s.trim();
-	}
-
-	private Integer getNumber(String s) {
-		if (StringUtils.isBlank(s)) {
-			return null;
-		}
-		return Integer.valueOf(s.trim());
-	}
-
-	@Override
-	public List<String> findPaperId(Long fromRootOrgId) {
-		Query query = new Query();
-		query.addCriteria(Criteria.where("orgId").is(fromRootOrgId.toString()));
-		query.addCriteria(Criteria.where("paperType").is(PaperType.IMPORT));
-		List<PaperId> paperList = this.mongoTemplate.find(query, PaperId.class, "paper");
-		if (CollectionUtils.isEmpty(paperList)) {
-			return null;
-		}
-		List<String> ids = paperList.stream().map(e -> e.getId()).collect(Collectors.toList());
-		return ids;
-	}
+    @Resource(name = "mongoTemplate2")
+    private MongoTemplate mongoTemplate2;
+
+    @Autowired
+    private QuestionAudioServiceImpl questionAudioService;
+
+    @Autowired
+    private SysProperty sysProperty;
+
+    @Autowired
+    private CoursePaperCloudService coursePaperCloudService;
+
+    @Autowired
+    private CourseService courseService;
+
+    @Autowired
+    private ExtractConfigPaperCache extractConfigPaperCache;
+
+    @Autowired
+    private BasePaperCache basePaperCache;
+
+    @Autowired
+    private RandomPaperQuestionService randomPaperQuestionService;
+
+    @Autowired
+    private RandomPaperService randomPaperService;
+
+    @Autowired
+    private QuestionCache questionCache;
+
+    @Autowired
+    private QuestionAnswerCache questionAnswerCache;
+
+    @Autowired
+    private SystemProperties systemProperties;
+
+    private Random random = new Random();
+
+    public static final String TEMP_FILE_EXP = "docxExport/";
+
+    /**
+     * 查询所有已导入试卷
+     */
+    @Override
+    public Page<Paper> getImportPapers(PaperSearchInfo paperSearchInfo, int curPage, int pageSize, UserDataRule ud) {
+
+        if (ud.assertEmptyQueryResult()) {
+            return Page.empty();
+        }
+        Query query = new Query();
+
+        query.addCriteria(Criteria.where("orgId").is(paperSearchInfo.getOrgId()));
+
+        if (ud.assertNeedQueryRefIds()) {
+            query.addCriteria(Criteria.where("course.id").in(ud.stringRefIds()));
+        }
+
+        query.addCriteria(Criteria.where("paperType").is(PaperType.IMPORT));
+
+        query.addCriteria(Criteria.where("course.enable").is("true"));
+
+        if (StringUtils.isNotBlank(paperSearchInfo.getCourseNo())) {
+            query.addCriteria(Criteria.where("course.code").is(paperSearchInfo.getCourseNo()));
+        }
+
+        if (StringUtils.isNotBlank(paperSearchInfo.getLevel())) {
+            query.addCriteria(Criteria.where("course.level").is(paperSearchInfo.getLevel()));
+        }
+
+        if (StringUtils.isNoneBlank(paperSearchInfo.getName())) {
+            String paperName = CommonUtils.escapeExprSpecialWord(paperSearchInfo.getName());
+            query.addCriteria(Criteria.where("name").regex(".*?\\.*" + paperName + ".*"));
+        }
+
+        if (StringUtils.isNoneBlank(paperSearchInfo.getCreator())) {
+            String creator = CommonUtils.escapeExprSpecialWord(paperSearchInfo.getCreator());
+            query.addCriteria(Criteria.where("creator").regex(".*?\\.*" + creator + ".*"));
+        }
+
+        if (StringUtils.isNoneBlank(paperSearchInfo.getLastModifyName())) {
+            String lastModifyName = CommonUtils.escapeExprSpecialWord(paperSearchInfo.getLastModifyName());
+            query.addCriteria(Criteria.where("lastModifyName").regex(".*?\\.*" + lastModifyName + ".*"));
+        }
+
+        if (StringUtils.isNotBlank(paperSearchInfo.getSpecialtyNo())) {
+            query.addCriteria(Criteria.where("specialty.code").is(paperSearchInfo.getSpecialtyNo()));
+        }
+
+        long total = this.mongoTemplate.count(query, Paper.class);
+        if (total == 0) {
+            return Page.empty();
+        }
+
+        PageRequest pageable = PageRequest.of(curPage - 1, pageSize);
+        query.with(Sort.by(Sort.Order.desc("createTime")));
+        query.skip(pageable.getOffset());
+        query.limit(pageable.getPageSize());
+
+        List<Paper> paperList = this.mongoTemplate.find(query, Paper.class);
+        if (CollectionUtils.isEmpty(paperList)) {
+            return Page.empty();
+        }
+
+        return new PageImpl<>(paperList, pageable, total);
+    }
+
+    /**
+     * 查询所有待审核和审核不通过的导入试卷
+     *
+     * @param paperSearchInfo
+     * @param curPage
+     * @param pageSize
+     * @return
+     */
+    public Page<Paper> getImportPapersNotSuccess(PaperSearchInfo paperSearchInfo, int curPage, int pageSize) {
+        Query query = new Query();
+        query.addCriteria(Criteria.where("orgId").is(paperSearchInfo.getOrgId()));
+        query.addCriteria(Criteria.where("paperType").is(PaperType.IMPORT));
+        query.addCriteria(Criteria.where("course.enable").is("true"));
+        if (paperSearchInfo.getPaperStatus() != null) {
+            query.addCriteria(Criteria.where("paperStatus").is(paperSearchInfo.getPaperStatus()));
+        } else {
+            query.addCriteria(Criteria.where("paperStatus").ne(PaperStatus.PASS));
+        }
+        if (StringUtil.isNotBlank(paperSearchInfo.getCourseNo())) {
+            query.addCriteria(Criteria.where("course.code").is(paperSearchInfo.getCourseNo()));
+        }
+        long total = this.mongoTemplate.count(query, Paper.class);
+        if (total == 0) {
+            return Page.empty();
+        }
+
+        query.limit(pageSize);
+        query.skip((curPage - 1L) * pageSize);
+        List<Paper> paperList = this.mongoTemplate.find(query, Paper.class);
+        return new PageImpl<Paper>(paperList, PageRequest.of(curPage - 1, pageSize), total);
+    }
+
+    /**
+     * 根据条件查询
+     *
+     * @param paperSearchInfo
+     * @return
+     */
+    public List<Paper> getImportPapersBySearch(PaperSearchInfo paperSearchInfo) {
+        Query query = new Query();
+        query.addCriteria(Criteria.where("orgId").is(paperSearchInfo.getOrgId()));
+        query.addCriteria(Criteria.where("paperType").is(PaperType.IMPORT.name()));
+        query.addCriteria(Criteria.where("course.enable").is("true"));
+        if (StringUtils.isNotBlank(paperSearchInfo.getCourseNo())) {
+            query.addCriteria(Criteria.where("course.code").is(paperSearchInfo.getCourseNo()));
+        }
+        if (StringUtils.isNotBlank(paperSearchInfo.getLevel())) {
+            query.addCriteria(Criteria.where("course.level").is(paperSearchInfo.getLevel()));
+        }
+        List<Paper> paperList = this.mongoTemplate.find(query, Paper.class);
+        return paperList;
+    }
+
+    @Override
+    public List<Paper> getPapersByCourse(Long ordId, String courseCode, PaperType paperType) {
+        Query query = new Query();
+        query.addCriteria(Criteria.where("orgId").is(ordId.toString()));
+        query.addCriteria(Criteria.where("paperType").is(paperType.name()));
+        query.addCriteria(Criteria.where("course.code").is(courseCode));
+        List<Paper> paperList = this.mongoTemplate.find(query, Paper.class);
+        return paperList;
+    }
+
+    @Override
+    public boolean existsPaperBySourceId(Long ordId, String courseCode, PaperType paperType, String sourceId) {
+        Query query = new Query();
+        query.addCriteria(Criteria.where("orgId").is(ordId.toString()));
+        query.addCriteria(Criteria.where("paperType").is(paperType.name()));
+        query.addCriteria(Criteria.where("course.code").is(courseCode));
+        query.addCriteria(Criteria.where("sourceId").is(sourceId));
+        List<Paper> paperList = this.mongoTemplate.find(query, Paper.class);
+        return CollectionUtils.isNotEmpty(paperList);
+    }
+
+    /**
+     * 根据条件查询
+     *
+     * @param paperSearchInfo
+     * @return
+     */
+    public List<Paper> getGenPapersBySearch(PaperSearchInfo paperSearchInfo) {
+        Query query = new Query();
+        query.addCriteria(Criteria.where("orgId").is(paperSearchInfo.getOrgId()));
+        query.addCriteria(Criteria.where("paperType").is(PaperType.GENERATE.name()));
+        query.addCriteria(Criteria.where("course.enable").is("true"));
+        query.addCriteria(Criteria.where("storage").ne(1));
+        if (StringUtils.isNotBlank(paperSearchInfo.getCourseNo())) {
+            query.addCriteria(Criteria.where("course.code").is(paperSearchInfo.getCourseNo()));
+        }
+
+        if (StringUtils.isNotBlank(paperSearchInfo.getLevel())) {
+            query.addCriteria(Criteria.where("course.level").is(paperSearchInfo.getLevel()));
+        }
+
+        query.with(Sort.by(Sort.Direction.DESC, "createTime"));
+
+        List<Paper> paperList = this.mongoTemplate.find(query, Paper.class);
+        return paperList;
+    }
+
+    /**
+     * 保存试卷
+     *
+     * @param paperExp
+     * @return
+     */
+    public Map<String, Object> savePaper(PaperExp paperExp, User user) {
+        Map<String, Object> msgMap = new HashMap<>();
+
+        Paper oldPaper = Model.of(paperRepo.findById(paperExp.getId()));
+        if (oldPaper != null) {
+            if (PaperType.GENERATE.equals(oldPaper.getPaperType())) {
+                oldPaper.setAuditStatus(false);
+            }
+            String oldName = oldPaper.getName().trim();
+            oldPaper.setTitle(paperExp.getTitle());
+            oldPaper.setName(paperExp.getName().trim());
+            oldPaper.setLastModifyName(user.getDisplayName());
+            oldPaper.setExamRemark(paperExp.getExamRemark());
+            if (!oldName.equals(paperExp.getName().trim())) {// 假如改变了试卷名称
+                // 则要效验试卷名称唯一性
+                boolean existName = this.checkPaperName(paperExp.getName().trim(), user.getRootOrgId().toString());
+                if (existName) {
+                    msgMap.put("msg", "试卷名称重复,请重新命名!");
+                } else {
+                    formatPaper(oldPaper, user);
+                    paperRepo.save(oldPaper);
+                    msgMap.put("msg", "success");
+                }
+            } else {
+                formatPaper(oldPaper, user);
+                paperRepo.save(oldPaper);
+                msgMap.put("msg", "success");
+            }
+        }
+
+        // 清除缓存
+        this.clearPaperCache(paperExp.getId());
+
+        return msgMap;
+    }
+
+    /**
+     * 查询所有已组试卷
+     *
+     * @param paperSearchInfo
+     * @param curPage
+     * @param pageSize
+     * @return
+     */
+    public Page<Paper> getGenPapers(PaperSearchInfo paperSearchInfo, int curPage, int pageSize, UserDataRule ud) {
+        if (ud.assertEmptyQueryResult()) {
+            return Page.empty();
+        }
+        Query query = new Query();
+        query.addCriteria(Criteria.where("orgId").is(paperSearchInfo.getOrgId()));
+        if (ud.assertNeedQueryRefIds()) {
+            query.addCriteria(Criteria.where("course.id").in(ud.stringRefIds()));
+        }
+        if (paperSearchInfo.getAuditStatus() != null) {
+            if (paperSearchInfo.getAuditStatus()) {
+                query.addCriteria(Criteria.where("auditStatus").ne(false));
+            } else {
+                query.addCriteria(Criteria.where("auditStatus").is(false));
+            }
+        }
+        if (paperSearchInfo.getAppAnswer() != null) {
+            if (paperSearchInfo.getAppAnswer()) {
+                query.addCriteria(Criteria.where("appAnswer").is(true));
+            } else {
+                query.addCriteria(Criteria.where("appAnswer").ne(true));
+            }
+        }
+        query.addCriteria(Criteria.where("paperType").is(PaperType.GENERATE.name()));
+        query.addCriteria(Criteria.where("storage").ne(1));
+        query.addCriteria(Criteria.where("course.enable").is("true"));
+        if (paperSearchInfo.getInUse() != null) {
+            if (paperSearchInfo.getInUse() == 0) {
+                query.addCriteria(Criteria.where("inUse").ne(1));
+            } else if (paperSearchInfo.getInUse() == 1) {
+                query.addCriteria(Criteria.where("inUse").is(1));
+            }
+        }
+        if (StringUtils.isNotBlank(paperSearchInfo.getCourseNo())) {
+            query.addCriteria(Criteria.where("course.code").is(paperSearchInfo.getCourseNo()));
+        }
+        if (StringUtils.isNotBlank(paperSearchInfo.getName())) {
+            String paperName = CommonUtils.escapeExprSpecialWord(paperSearchInfo.getName());
+            query.addCriteria(Criteria.where("name").regex(".*?\\.*" + paperName + ".*"));
+        }
+        if (StringUtils.isNotBlank(paperSearchInfo.getLevel())) {
+            query.addCriteria(Criteria.where("course.level").is(paperSearchInfo.getLevel()));
+        }
+        if (StringUtils.isNotBlank(paperSearchInfo.getCreator())) {
+            String creator = CommonUtils.escapeExprSpecialWord(paperSearchInfo.getCreator());
+            query.addCriteria(Criteria.where("creator").regex(".*?\\.*" + creator + ".*"));
+        }
+        if (StringUtils.isNotBlank(paperSearchInfo.getLastModifyName())) {
+            String lastModifyName = CommonUtils.escapeExprSpecialWord(paperSearchInfo.getLastModifyName());
+            query.addCriteria(Criteria.where("lastModifyName").regex(".*?\\.*" + lastModifyName + ".*"));
+        }
+
+        long total = this.mongoTemplate.count(query, Paper.class);
+        if (total == 0) {
+            return Page.empty();
+        }
+
+        query.with(Sort.by(new Order(Direction.DESC, "createTime")));
+        query.limit(pageSize);
+        query.skip((curPage - 1L) * pageSize);
+        List<Paper> paperList = this.mongoTemplate.find(query, Paper.class);
+        return new PageImpl<Paper>(paperList, PageRequest.of(curPage - 1, pageSize), total);
+    }
+
+    @Override
+    public Page<Paper> getStoragePaperPage(PaperSearchInfo paperSearchInfo, int curPage, int pageSize,
+            UserDataRule ud) {
+        if (ud.assertEmptyQueryResult()) {
+            return Page.empty();
+        }
+        Query query = new Query();
+        query.addCriteria(Criteria.where("orgId").is(paperSearchInfo.getOrgId()));
+        if (ud.assertNeedQueryRefIds()) {
+            query.addCriteria(Criteria.where("course.id").in(ud.stringRefIds()));
+        }
+        query.addCriteria(Criteria.where("paperType").is(PaperType.GENERATE.name()));
+        query.addCriteria(Criteria.where("storage").is(1));
+        query.addCriteria(Criteria.where("course.enable").is("true"));
+        if (StringUtils.isNotBlank(paperSearchInfo.getCourseNo())) {
+            query.addCriteria(Criteria.where("course.code").is(paperSearchInfo.getCourseNo()));
+        }
+        if (StringUtils.isNoneBlank(paperSearchInfo.getName())) {
+            String paperName = CommonUtils.escapeExprSpecialWord(paperSearchInfo.getName());
+            query.addCriteria(Criteria.where("name").regex(".*?\\.*" + paperName + ".*"));
+        }
+        if (StringUtils.isNotBlank(paperSearchInfo.getLevel())) {
+            query.addCriteria(Criteria.where("course.level").is(paperSearchInfo.getLevel()));
+        }
+        if (StringUtils.isNoneBlank(paperSearchInfo.getCreator())) {
+            String creator = CommonUtils.escapeExprSpecialWord(paperSearchInfo.getCreator());
+            query.addCriteria(Criteria.where("creator").regex(".*?\\.*" + creator + ".*"));
+        }
+        if (StringUtils.isNoneBlank(paperSearchInfo.getLastModifyName())) {
+            String lastModifyName = CommonUtils.escapeExprSpecialWord(paperSearchInfo.getLastModifyName());
+            query.addCriteria(Criteria.where("lastModifyName").regex(".*?\\.*" + lastModifyName + ".*"));
+        }
+
+        long total = this.mongoTemplate.count(query, Paper.class);
+        if (total == 0) {
+            return Page.empty();
+        }
+
+        query.with(Sort.by(new Order(Direction.DESC, "createTime")));
+        query.limit(pageSize);
+        query.skip((curPage - 1L) * pageSize);
+        List<Paper> paperList = this.mongoTemplate.find(query, Paper.class);
+        return new PageImpl<Paper>(paperList, PageRequest.of(curPage - 1, pageSize), total);
+    }
+
+    /**
+     * 查询考试试卷
+     *
+     * @param id
+     * @param courseCode
+     * @param groupCode
+     * @return
+     */
+    public List<Paper> listExamPapers(long id, String courseCode, String groupCode) {
+        List<Paper> papers = new ArrayList<>();
+        ExamPaper examPaper = new ExamPaper();
+        examPaper.setExamId(id);
+        examPaper.setCourseCode(courseCode);
+        examPaper.setGroupCode(groupCode);
+        Example<ExamPaper> example = Example.of(examPaper);
+        List<ExamPaper> examPapers = examPaperRepo.findAll(example);
+        for (ExamPaper ePaper : examPapers) {
+            Paper paper = Model.of(paperRepo.findById(ePaper.getPaper().getId()));
+            papers.add(paper);
+        }
+        return papers;
+    }
+
+    /**
+     * 设置考试试卷
+     *
+     * @param examId
+     * @param courseCode
+     * @param groupCode
+     * @param paperId
+     * @return
+     */
+    public void joinToExamPaper(long examId, String courseCode, String groupCode, String paperId) {
+        ExamPaper examPaper = new ExamPaper();
+        examPaper.setExamId(examId);
+        examPaper.setGroupCode(groupCode);
+        examPaper.setCourseCode(courseCode);
+        // examPaper.setPaperId(paperId);
+        examPaperRepo.save(examPaper);
+    }
+
+    public void releaseExamPaper(long examId, String courseCode, String groupCode, String paperId) {
+        ExamPaper examPaper = new ExamPaper();
+        examPaper.setExamId(examId);
+        examPaper.setGroupCode(groupCode);
+        examPaper.setCourseCode(courseCode);
+        // examPaper.setPaperId(paperId);
+        examPaperRepo.delete(examPaper);
+    }
+
+    public Set<String> listGroupCodes(long examId, String courseCode) {
+        Set<String> groupSet = new HashSet<>();
+        ExamPaper examPaper = new ExamPaper();
+        examPaper.setExamId(examId);
+        examPaper.setCourseCode(courseCode);
+        List<ExamPaper> examPapers = examPaperRepo.findAll(Example.of(examPaper));
+        for (ExamPaper expaper : examPapers) {
+            groupSet.add(expaper.getGroupCode());
+        }
+        return groupSet;
+    }
+
+    public void deletGroupCode(long examId, String courseCode, String groupCode) {
+        ExamPaper examPaper = new ExamPaper();
+        examPaper.setExamId(examId);
+        examPaper.setCourseCode(courseCode);
+        examPaper.setCourseCode(courseCode);
+        examPaperRepo.delete(examPaper);
+    }
+
+    /**
+     * 根据试卷ID获取试卷下面的大题
+     *
+     * @param id
+     * @return
+     */
+    public List<PaperDetail> findPaperDetailsById(String id) {
+        return paperDetailService.getPaperDetailsByPaper(Model.of(paperRepo.findById(id)));
+    }
+
+    /**
+     * 批量删除试卷
+     *
+     * @param paperIds
+     */
+    @Override
+    public void deletePapers(List<String> paperIds, User user) {
+        List<Paper> papers = CommonUtils.toList(paperRepo.findByIdIn(paperIds));
+        if (papers.get(0).getPaperType() == PaperType.IMPORT) {
+            List<Question> quesList = new ArrayList<>();
+            for (Paper paper : papers) {
+                List<PaperDetailUnit> paperUnits = paperDetailUnitRepo.findByPaperOrderByNumber(paper);
+                List<String> questionIds = paperUnits.stream().map(e -> e.getQuestion().getId())
+                        .collect(Collectors.toList());
+                if (randomPaperQuestionService.existQuestion(questionIds)) {
+                    throw new StatusException("试卷[" + paper.getName() + "]中有试题被抽题模板使用,不能删除");
+                }
+                for (PaperDetailUnit pdu : paperUnits) {
+                    if (pdu.getQuestion() != null) {
+                        quesList.add(pdu.getQuestion());
+                    }
+                }
+            }
+            List<PaperDetailUnit> allUnits = paperDetailUnitRepo.findByQuestionIn(quesList);
+            for (PaperDetailUnit pdu : allUnits) {
+                if (pdu.getPaper() != null && pdu.getPaper().getPaperType() == PaperType.GENERATE) {
+                    // msg = "待删除试卷中有试题被组卷使用,不能删除!";
+                    // msgMap.put("msg", msg);
+                    // msgMap.put("paperName", pdu.getPaper().getName());
+                    // return msgMap;
+                    throw new StatusException("试卷[" + pdu.getPaper().getName() + "]中有试题被组卷使用,不能删除");
+                }
+            }
+            // 删除音频
+            questionAudioService.deleteAudio(quesList);
+            quesRepo.deleteAll(quesList);
+        } else if (papers.get(0).getPaperType() == PaperType.GENERATE) {
+            for (Paper paper : papers) {
+                // List<String> examPaperIds =
+                // extractConfigService.getExamPaperId(paper.getCourseNo(),
+                // paper.getOrgId());
+                // if (examPaperIds != null &&
+                // examPaperIds.contains(paper.getId())) {
+                // msg = "待删除试卷有被调卷规则使用,不能删除!";
+                // msgMap.put("msg", msg);
+                // msgMap.put("paperName", paper.getName());
+                // return msgMap;
+                // }
+                if (paper.getInUse() != null && paper.getInUse() == 1) {
+                    throw new StatusException("试卷[" + paper.getName() + "]已调用,不能删除");
+                }
+                if (randomPaperService.existPaper(Long.valueOf(paper.getCourse().getId()), paper.getId())) {
+                    throw new StatusException("试卷[" + paper.getName() + "]被抽题模板使用,不能删除");
+                }
+            }
+        }
+        paperDetailService.deletePaperDetailsByPapers(papers);
+        paperRepo.deleteAll(papers);
+
+        for (String paperId : paperIds) {
+            // 清除缓存
+            this.clearPaperCache(paperId);
+        }
+
+        for (Paper paper : papers) {
+            StringBuilder paperInfo = new StringBuilder();
+            paperInfo.append("课程:" + paper.getCourse().getName() + "(" + paper.getCourse().getCode() + ")");
+            paperInfo.append(" 试卷名称:" + paper.getName());
+            if (PaperType.IMPORT.equals(paper.getPaperType())) {
+                ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
+                        AdminOperateType.TYPE46.getDesc(), paperInfo.toString()));
+            } else {
+                ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
+                        AdminOperateType.TYPE47.getDesc(), paperInfo.toString()));
+
+            }
+        }
+    }
+
+    private List<PaperDetailUnitDto> findUnitByPaperId(String paperId) {
+        Object id;
+        if (paperId.length() > 24) {
+            id = paperId;
+        } else {
+            id = new ObjectId(paperId);
+        }
+        Query query = new Query();
+        query.addCriteria(Criteria.where("paper.$id").is(id));
+        List<PaperDetailUnitDto> units = this.mongoTemplate2.find(query, PaperDetailUnitDto.class, "paperDetailUnit");
+        return units;
+    }
+
+    private boolean existGenerateQuestion(List<String> questionIds) {
+        List<Object> ids = new ArrayList<>();
+        for (String pid : questionIds) {
+            if (pid.length() > 24) {
+                ids.add(pid);
+            } else {
+                ids.add(new ObjectId(pid));
+            }
+        }
+        Query query = new Query();
+        query.addCriteria(Criteria.where("question.$id").in(ids));
+        query.addCriteria(Criteria.where("paperType").is(PaperType.GENERATE.name()));
+        long count = mongoTemplate.count(query, "paperDetailUnit");
+        return count > 0;
+    }
+
+    private void removeByIds(List<String> stringIds, String collectionName) {
+        List<Object> ids = new ArrayList<>();
+        for (String pid : stringIds) {
+            if (pid.length() > 24) {
+                ids.add(pid);
+            } else {
+                ids.add(new ObjectId(pid));
+            }
+        }
+        Query query = new Query();
+        query.addCriteria(Criteria.where("_id").in(ids));
+        mongoTemplate.remove(query, collectionName);
+    }
+
+    private void removeDetailByPaperIds(List<String> paperIds) {
+        List<Object> ids = new ArrayList<>();
+        for (String pid : paperIds) {
+            if (pid.length() > 24) {
+                ids.add(pid);
+            } else {
+                ids.add(new ObjectId(pid));
+            }
+        }
+        Query query = new Query();
+        query.addCriteria(Criteria.where("paper.$id").in(ids));
+        mongoTemplate.remove(query, "paperDetail");
+    }
+
+    @Override
+    public void deletePapersPlus(List<String> paperIds, User user) {
+        List<Paper> papers = paperRepo.findByIdIn(paperIds);
+        List<PaperDetailUnitDto> unitList = new ArrayList<>();
+        if (papers.get(0).getPaperType() == PaperType.IMPORT) {
+            List<String> quesList = new ArrayList<>();
+            for (Paper paper : papers) {
+                List<PaperDetailUnitDto> paperUnits = findUnitByPaperId(paper.getId());
+                if (CollectionUtils.isEmpty(paperUnits)) {
+                    continue;
+                }
+                List<String> questionIds = paperUnits.stream().map(e -> e.getQuestion().getId())
+                        .collect(Collectors.toList());
+                if (existGenerateQuestion(questionIds)) {
+                    throw new StatusException("试卷[" + paper.getName() + "]中有试题被组卷使用,不能删除");
+                }
+                if (randomPaperQuestionService.existQuestion(questionIds)) {
+                    throw new StatusException("试卷[" + paper.getName() + "]中有试题被抽题模板使用,不能删除");
+                }
+                unitList.addAll(paperUnits);
+                quesList.addAll(questionIds);
+            }
+            if (CollectionUtils.isNotEmpty(quesList)) {
+                questionAudioService.deleteAudioByQuestionId(quesList);
+                removeByIds(quesList, "question");
+            }
+        } else if (papers.get(0).getPaperType() == PaperType.GENERATE) {
+            for (Paper paper : papers) {
+                if (paper.getInUse() != null && paper.getInUse() == 1) {
+                    throw new StatusException("试卷[" + paper.getName() + "]已调用,不能删除");
+                }
+                if (randomPaperService.existPaper(Long.valueOf(paper.getCourse().getId()), paper.getId())) {
+                    throw new StatusException("试卷[" + paper.getName() + "]被抽题模板使用,不能删除");
+                }
+                List<PaperDetailUnitDto> paperUnits = findUnitByPaperId(paper.getId());
+                if (CollectionUtils.isEmpty(paperUnits)) {
+                    continue;
+                }
+                unitList.addAll(paperUnits);
+            }
+        }
+        List<String> unitids = unitList.stream().map(e -> e.getId()).collect(Collectors.toList());
+        if (CollectionUtils.isNotEmpty(unitids)) {
+            removeByIds(unitids, "paperDetailUnit");
+        }
+        removeDetailByPaperIds(paperIds);
+        removeByIds(paperIds, "paper");
+
+        for (String paperId : paperIds) {
+            // 清除缓存
+            this.clearPaperCache(paperId);
+        }
+
+        for (Paper paper : papers) {
+            StringBuilder paperInfo = new StringBuilder();
+            paperInfo.append("课程:" + paper.getCourse().getName() + "(" + paper.getCourse().getCode() + ")");
+            paperInfo.append(" 试卷名称:" + paper.getName());
+            if (PaperType.IMPORT.equals(paper.getPaperType())) {
+                ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
+                        AdminOperateType.TYPE46.getDesc(), paperInfo.toString()));
+            } else {
+                ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
+                        AdminOperateType.TYPE47.getDesc(), paperInfo.toString()));
+
+            }
+        }
+    }
+
+    /**
+     * 批量通过试卷
+     *
+     * @param paperIds
+     */
+    public void passPapers(List<String> paperIds) {
+        List<Paper> papers = CommonUtils.toList(paperRepo.findByIdIn(paperIds));
+        papers.stream().forEach(paper -> {
+            paper.setPaperStatus(PaperStatus.PASS);
+        });
+        paperRepo.saveAll(papers);
+    }
+
+    @Override
+    public void updatePapersStorage(List<String> paperIds, int storage, String orgId) {
+        List<Paper> papers = CommonUtils.toList(paperRepo.findByIdIn(paperIds));
+        List<Paper> papersList = papers.stream().filter(p -> orgId.equals(p.getOrgId())).collect(Collectors.toList());
+        papersList.stream().forEach(paper -> {
+            paper.setStorage(storage);
+        });
+        if (papersList.size() > 0) {
+            paperRepo.saveAll(papersList);
+        }
+    }
+
+    /**
+     * 批量不通过试卷
+     *
+     * @param paperIds
+     */
+    public void noPassPapers(List<String> paperIds) {
+        List<Paper> papers = CommonUtils.toList(paperRepo.findByIdIn(paperIds));
+        papers.stream().forEach(paper -> {
+            paper.setPaperStatus(PaperStatus.NOPASS);
+        });
+        paperRepo.saveAll(papers);
+    }
+
+    /**
+     * 批量待审核试卷
+     *
+     * @param paperIds
+     */
+    public void backPapers(List<String> paperIds) {
+        List<Paper> papers = CommonUtils.toList(paperRepo.findByIdIn(paperIds));
+        papers.stream().forEach(paper -> {
+            paper.setPaperStatus(PaperStatus.DRAFT);
+        });
+        paperRepo.saveAll(papers);
+    }
+
+    /**
+     * 初始化导出试卷DTO
+     *
+     * @param id
+     * @return
+     */
+    public PaperExp getPaperDto(String id) {
+        Paper paper = Model.of(paperRepo.findById(id));
+        // 创建paperDto
+        PaperExp paperExp = new PaperExp();
+        BeanUtils.copyProperties(paper, paperExp);
+        paperExp.setCourse(paper.getCourse());
+        // 获取大题
+        List<PaperDetail> paperDetails = paperDetailRepo.findByPaperOrderByNumber(paper);
+        List<PaperDetailExp> paperDetailExps = new ArrayList<>();
+        for (PaperDetail paperDetail : paperDetails) {
+            PaperDetailExp paperDetailExp = new PaperDetailExp();
+            BeanUtils.copyProperties(paperDetail, paperDetailExp);
+            paperDetailExps.add(paperDetailExp);
+        }
+        // 封装小题
+        for (int i = 0; i < paperDetailExps.size(); i++) {
+            List<PaperDetailUnit> paperDetailUnits = paperDetailUnitRepo
+                    .findByPaperDetailOrderByNumber(paperDetails.get(i));
+            if (paperDetailUnits != null && paperDetailUnits.size() > 0) {
+                List<PaperDetailUnitExp> paperDetailUnitExps = new ArrayList<>();
+                for (PaperDetailUnit paperDetailUnit : paperDetailUnits) {
+                    PaperDetailUnitExp paperDetailUnitExp = new PaperDetailUnitExp();
+                    BeanUtils.copyProperties(paperDetailUnit, paperDetailUnitExp);
+                    fillProperty(paperDetailUnitExp.getQuestion());
+                    if (!CollectionUtils.isEmpty(paperDetailUnitExp.getQuestion().getSubQuestions())) {
+                        for (Question subque : paperDetailUnitExp.getQuestion().getSubQuestions()) {
+                            fillProperty(subque);
+                        }
+                    }
+                    paperDetailUnitExps.add(paperDetailUnitExp);
+                }
+                // 选择题,套题下选择题 选项顺序重新排列
+                reorderChoicequestionOption(paperDetailUnitExps);
+                paperDetailExps.get(i).setPaperDetailUnits(paperDetailUnitExps);
+            } else {
+                paperDetailExps.get(i).setUnitCount(0);
+            }
+        }
+        paperExp.setPaperDetails(paperDetailExps);
+        // 初始化试卷内容
+        initPaper(paperExp);
+        return paperExp;
+    }
+
+    /**
+     * 重新对选择题option进行排序(多选、单选、套题下选择题)
+     */
+    public void reorderChoicequestionOption(List<PaperDetailUnitExp> paperDetailUnitExps) {
+        for (PaperDetailUnitExp paperDetailUnitExp : paperDetailUnitExps) {
+            String optionOrder = paperDetailUnitExp.getOptionOrder();
+            if (StringUtil.isNotBlank(optionOrder)) {
+                Question question = paperDetailUnitExp.getQuestion();
+                if (question.getQuestionType() == QuesStructType.SINGLE_ANSWER_QUESTION
+                        || question.getQuestionType() == QuesStructType.MULTIPLE_ANSWER_QUESTION) {
+                    question.setQuesOptions(reorderOptionCore(question.getQuesOptions(), optionOrder));
+                }
+                if (question.getQuestionType() == QuesStructType.NESTED_ANSWER_QUESTION) {
+                    List<Question> subQuestions = question.getSubQuestions();
+                    int index = 0;
+                    for (int k = 0; k < subQuestions.size(); k++) {
+                        Question subQuestion = subQuestions.get(k);
+                        if (subQuestion.getQuestionType() == QuesStructType.SINGLE_ANSWER_QUESTION
+                                || subQuestion.getQuestionType() == QuesStructType.MULTIPLE_ANSWER_QUESTION) {
+                            subQuestion.setQuesOptions(
+                                    reorderOptionCore(subQuestion.getQuesOptions(), optionOrder.split(";")[index]));
+                            index++;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private List<QuesOption> reorderOptionCore(List<QuesOption> quesOptions, String optionOrder) {
+        List<QuesOption> newQuesOptions = new ArrayList<>();
+        if (StringUtil.isBlank(optionOrder) || quesOptions.isEmpty()) {
+            return null;
+        }
+        String[] optionOrderArr = optionOrder.split(",");
+        for (int j = 0; j < optionOrderArr.length; j++) {
+            for (int k = 0; k < quesOptions.size(); k++) {
+                if (optionOrderArr[j].equals(quesOptions.get(k).getNumber())) {
+                    newQuesOptions.add(quesOptions.get(k));
+                }
+            }
+        }
+        quesOptions = null;
+        return newQuesOptions;
+    }
+
+    /**
+     * 初始化试卷内容(增加序号)
+     *
+     * @param paperExp
+     */
+    public void initPaper(PaperExp paperExp) {
+        if (paperExp.getPaperDetails() == null || paperExp.getPaperDetails().size() == 0) {
+            return;
+        }
+        int mainNum = 0;
+        List<PaperDetailExp> paperDetailExpList = paperExp.getPaperDetails();
+        for (PaperDetailExp paperDetail : paperDetailExpList) {
+            // 大题序号
+            paperDetail.setNumber(++mainNum);
+            paperDetail.setCnNum(CommonUtils.toCHNum(paperDetail.getNumber()));
+            if (paperDetail != null && paperDetail.getPaperDetailUnits() != null
+                    && paperDetail.getPaperDetailUnits().size() > 0) {
+                for (PaperDetailUnitExp paperDetailUnit : paperDetail.getPaperDetailUnits()) {
+                    Question question = paperDetailUnit.getQuestion();
+                    if (question != null) {
+                        if (question.getHasAudio() != null && question.getHasAudio()) {
+                            paperExp.setHasAudio(true); // 设置试卷含有音频
+                        }
+                        quesService.formatQuesUnit(question);
+                        List<Question> subQuesList = question.getSubQuestions();
+                        // 套题序号
+                        if (subQuesList != null && subQuesList.size() > 0) {
+                            int index = 0;
+                            for (Question subQues : subQuesList) {
+                                Map<String, String> params = new HashMap<>();
+                                params.put("number", String.valueOf(++index));
+                                subQues.setQuesParams(params);
+                                quesService.formatQuesUnit(subQues);
+                            }
+                            String quesBodyHtml = CommonUtils.relaceQuestionIdx(question.getQuesBody(), 0);
+                            question.setQuesBody(quesBodyHtml);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 格式化查询条件
+     *
+     * @param paperSearchInfo
+     */
+    public void formatPaperSearchInfo(PaperSearchInfo paperSearchInfo) {
+        if (StringUtils.isEmpty(paperSearchInfo.getCourseNo())) {
+            paperSearchInfo.setCourseNo(null);
+        }
+        if (StringUtils.isEmpty(paperSearchInfo.getCreateTime())) {
+            paperSearchInfo.setCreateTime(null);
+        }
+        if (StringUtils.isEmpty(paperSearchInfo.getCreator())) {
+            paperSearchInfo.setCreator(null);
+        }
+        if (StringUtils.isEmpty(paperSearchInfo.getName())) {
+            paperSearchInfo.setName(null);
+        }
+    }
+
+    /**
+     * 1.重新设置小题number,并返回试卷总分 2.重新计算大题的总分和小题总数 3.重新保存试卷大题数量、小题数量、试卷总分等信息
+     *
+     * @param paper
+     */
+    public void formatPaper(Paper paper, User user) {
+        double paperTotalScore = reSetPaperDetailUnit(paper);
+        paper.setDifficultyDegree(reSetDifficulty(paper, paperTotalScore));
+        Map<String, Object> paperInfoMap = reSetPaperDetail(paper);
+        reSetPaper(paper, user, paperInfoMap, paperTotalScore);
+    }
+
+    /**
+     * 计算试卷难度
+     *
+     * @param paper
+     * @param paperTotalScore
+     * @return
+     */
+
+    @SuppressWarnings("unused")
+    public Double reSetDifficulty(Paper paper, double paperTotalScore) {
+        Double sum = 0.0;
+        List<PaperDetail> paperDetails = paperDetailRepo.findByPaperOrderByNumber(paper);
+        if (paperDetails != null && paperDetails.size() > 0) {
+            for (PaperDetail paperDetail : paperDetails) {
+                // 获取每个大题下面的所有小题
+                List<PaperDetailUnit> paperDetailUnits = paperDetailUnitRepo
+                        .findByPaperDetailOrderByNumber(paperDetail);
+                if (paperDetailUnits != null && paperDetailUnits.size() > 0) {
+                    for (PaperDetailUnit paperDetailUnit : paperDetailUnits) {
+                        // 如果为套题,重新计算难度
+                        if (paperDetailUnit.getQuestionType() == QuesStructType.NESTED_ANSWER_QUESTION) {
+                            // 重新计算套题的难度,公开度
+                            boolean publicity = false;
+                            double totalSum = 0d;
+                            double totalDou = 0d;
+                            for (int i = 0; i < paperDetailUnit.getQuestion().getSubQuestions().size(); i++) {
+                                Question subQuestion = paperDetailUnit.getQuestion().getSubQuestions().get(i);
+                                // 设置公开度
+                                if (subQuestion.getPublicity() == null) {
+                                    publicity = true;
+                                } else {
+                                    if (subQuestion.getPublicity()) {
+                                        publicity = true;
+                                    }
+                                }
+                                if (subQuestion.getDifficultyDegree() == null) {
+                                    subQuestion.setDifficultyDegree(0.5);
+                                }
+                                totalSum = subQuestion.getDifficultyDegree() * paperDetailUnit.getSubScoreList().get(i)
+                                        + totalSum;
+                                totalDou = paperDetailUnit.getSubScoreList().get(i) + totalDou;
+                            }
+
+                            BigDecimal b;
+                            if (totalDou != 0d) {
+                                b = BigDecimal.valueOf(totalSum / totalDou);
+                            } else {
+                                b = BigDecimal.valueOf(0d);
+                            }
+
+                            Double difficulty = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
+                            paperDetailUnit.getQuestion().setDifficultyDegree(difficulty);
+                            paperDetailUnit.setScore(totalDou);
+                        }
+                        // 旧题没有难度值,需要重新赋值
+                        if (paperDetailUnit.getQuestion().getDifficultyDegree() == null) {
+                            paperDetailUnit.getQuestion().setDifficultyDegree(0.5);
+                        }
+                        if (paperDetailUnit.getScore() == null) {
+                            paperDetailUnit.setScore(0d);
+                        }
+                        sum = paperDetailUnit.getScore() * paperDetailUnit.getQuestion().getDifficultyDegree() + sum;
+                    }
+                }
+            }
+            if (paperTotalScore < 0.1) {
+                return 0.0;
+            }
+            BigDecimal b = BigDecimal.valueOf(sum / paperTotalScore);
+            Double difficulty = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
+            return difficulty;
+        }
+        return 0.0;
+    }
+
+    /**
+     * 重新设置小题number,并返回试卷总分
+     *
+     * @param paper
+     * @return
+     */
+    private double reSetPaperDetailUnit(Paper paper) {
+        List<PaperDetailUnit> paperDetailUnitAll = paperDetailUnitService.findByPaperAndSort(paper);
+        double totalScore = 0;
+        for (int i = 0; i < paperDetailUnitAll.size(); i++) {
+            PaperDetailUnit unit = paperDetailUnitAll.get(i);
+            if (unit.getScore() != null) {
+                totalScore += unit.getScore();
+            }
+            unit.setNumber(i + 1);
+        }
+        paperDetailUnitRepo.saveAll(paperDetailUnitAll);
+        totalScore = CommonUtils.formatDouble(totalScore);
+        return totalScore;
+    }
+
+    /**
+     * 重新计算大题的总分和小题总数
+     *
+     * @param paper
+     */
+    private Map<String, Object> reSetPaperDetail(Paper paper) {
+        Map<String, Object> paperInfoMap = new HashMap<>();
+        int allQuesCount = 0;
+        List<PaperDetail> paperDetails = paperDetailRepo.findByPaperOrderByNumber(paper);
+        // 计算各大题总分和小题数量
+        for (PaperDetail paperDetail : paperDetails) {
+            List<PaperDetailUnit> paperDetailUnits = paperDetailUnitRepo.findByPaperDetailOrderByNumber(paperDetail);
+            if (paperDetailUnits.size() > 0) {
+                int count = 0;
+                double score = 0;
+                int nestQusNum = 0;
+                for (PaperDetailUnit unit : paperDetailUnits) {
+                    if (unit.getScore() != null) {
+                        score += unit.getScore();
+                    }
+                    if (unit.getQuestion() != null && unit.getQuestion().getSubQuestions() != null
+                            && unit.getQuestion().getSubQuestions().size() > 0) {
+                        nestQusNum += unit.getQuestion().getSubQuestions().size() - 1;
+                    }
+                }
+                count = paperDetailUnits.size() + nestQusNum;
+                score = CommonUtils.formatDouble(score);
+                paperDetail.setScore(score);
+                paperDetail.setUnitCount(count);
+                allQuesCount += count;
+            } else {
+                paperDetail.setScore(0d);
+            }
+        }
+        paperDetailRepo.saveAll(paperDetails);
+        paperInfoMap.put("allQuesCount", allQuesCount);
+        paperInfoMap.put("paperDetails", paperDetails);
+        return paperInfoMap;
+    }
+
+    /**
+     * 重新设置试卷大题数量、小题数量、试卷总分等属性
+     *
+     * @param paper
+     * @param user
+     * @param paperInfoMap
+     * @param paperTotalScore
+     */
+    @SuppressWarnings("unchecked")
+    private void reSetPaper(Paper paper, User user, Map<String, Object> paperInfoMap, double paperTotalScore) {
+        List<PaperDetail> paperDetails = (List<PaperDetail>) paperInfoMap.get("paperDetails");
+        paper.setPaperDetailCount(paperDetails.size());// 设置大题数量
+        paper.setUnitCount(Integer.parseInt(paperInfoMap.get("allQuesCount") + ""));// 设置小题数量
+        paper.setTotalScore(paperTotalScore);// 设置试卷总分
+        if (user != null) {
+            paper.setLastModifyName(user.getDisplayName());
+        }
+        paperRepo.save(paper);
+
+        // 清除缓存
+        this.clearPaperCache(paper.getId());
+    }
+
+    /**
+     * 先备份准备删掉的试题,然后再删掉
+     *
+     * @param questionId
+     * @return
+     */
+    public void deleteImportQuestionById(String detailUnitId, String questionId, User user) {
+        if (randomPaperQuestionService.existQuestion(questionId)) {
+            throw new StatusException("该试题已被抽题模板使用,不能删除");
+        }
+        PaperDetailUnit paperDetailUnit = null;
+        if (detailUnitId != null) {
+            paperDetailUnit = Model.of(paperDetailUnitRepo.findById(detailUnitId));
+            Paper paper = paperDetailUnit.getPaper();
+            if (paper.getInUse() != null && paper.getInUse() == 1) {
+                throw new StatusException("500", "试卷已调用");
+            }
+        }
+        Question ques = Model.of(quesRepo.findById(questionId));
+
+        List<PaperDetailUnit> pdus = CommonUtils.toList(paperDetailUnitRepo.findByQuestion(ques));
+        List<String> paperNames = new ArrayList<>();
+
+        // 需要删除的小题
+        List<PaperDetailUnit> needPdus = new ArrayList<>();
+
+        List<Paper> papers = new ArrayList<>();
+        for (PaperDetailUnit pdu : pdus) {
+            if (pdu.getPaper() != null) {
+                if (!papers.contains(pdu.getPaper())) {
+                    papers.add(pdu.getPaper());
+                }
+                if (PaperType.GENERATE == pdu.getPaper().getPaperType()) {
+                    paperNames.add(pdu.getPaper().getName());
+                }
+            }
+        }
+        String changInfo = null;
+        if (paperNames.size() == 0) {
+            needPdus.addAll(pdus);// 此试题没有被组卷调用,则可以删除此试题
+            paperDetailUnitRepo.deleteAll(needPdus);
+            quesBakRepo.save(BeanCopierUtil.copyProperties(ques, QuestionBak.class));
+            quesRepo.delete(ques);
+
+            for (Paper paper : papers) {
+                if (paperDetailUnit != null && paperDetailUnit.getPaper().getId().equals(paper.getId())) {
+                    Double total = paper.getTotalScore();
+                    Integer dc = paper.getPaperDetailCount();
+                    Integer uc = paper.getUnitCount();
+                    formatPaper(paper, user);
+                    changInfo = PaperUtil.getPaperChangeInfo(total, dc, uc, paper);
+                } else {
+                    formatPaper(paper, user);
+                }
+            }
+        }
+
+        if (paperDetailUnit != null) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("课程:" + paperDetailUnit.getPaper().getCourse().getName() + "("
+                    + paperDetailUnit.getPaper().getCourse().getCode() + ")");
+            sb.append(" 试卷名称:" + paperDetailUnit.getPaper().getName());
+            sb.append(" 第" + paperDetailUnit.getNumber() + "小题 ");
+            sb.append(changInfo);
+            ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
+                    AdminOperateType.TYPE48.getDesc(), sb.toString()));
+        }
+        if (CollectionUtils.isNotEmpty(paperNames)) {
+            throw new StatusException("该试题被试卷:" + StringUtils.join(paperNames, ",") + "使用,不能删除");
+        }
+    }
+
+    /**
+     * 向试卷中插入一个试题
+     *
+     * @param paperId
+     * @param paperDetailId
+     * @return
+     */
+    public Paper insertQuestionToPaper(String paperId, String paperDetailId, Question question, User user) {
+        Paper paper = Model.of(paperRepo.findById(paperId));
+        question.setOrgId(user.getRootOrgId().toString());
+        question.setCourse(paper.getCourse());
+        question.setCourseNo(paper.getCourse().getCode());// 必须设置,因为部分方法需要courseNo作为查询条件
+        question = quesService.saveQues(question);
+
+        PaperDetail paperDetail = Model.of(paperDetailRepo.findById(paperDetailId));
+        PaperDetailUnit paperDetailUnit = new PaperDetailUnit(paper, paperDetail, question);
+        paperDetailUnit.setPaperType(PaperType.IMPORT);
+        PaperDetailUnit paperDetailUnit2 = paperDetailUnitService.findTopOrderByNumber(paperDetail, "DESC");
+        if (paperDetailUnit2 == null) {
+            paperDetailUnit.setNumber(1);
+        } else {
+            paperDetailUnit.setNumber(paperDetailUnit2.getNumber());// 设置number为大题的最大题号
+        }
+        paperDetailUnitRepo.save(paperDetailUnit);
+        formatPaper(paper, user);
+        return paper;
+    }
+
+    /**
+     * 获取试题所在的试卷名称
+     *
+     * @param questionId
+     * @return
+     */
+    public List<String> getPaperNamesByQuestionId(String questionId) {
+        List<String> paperNames = new ArrayList<>();
+        List<PaperDetailUnit> pdus = paperDetailUnitRepo.findByQuestion(Model.of(quesRepo.findById(questionId)));
+        for (PaperDetailUnit pdu : pdus) {
+            paperNames.add(pdu.getPaper().getName());
+        }
+        return paperNames;
+
+    }
+
+    public Page<Question> listQuestionforSelect(String paperId, int curPage, int pageSize, QuesStructType quesType,
+            User user, String quesBody, UserDataRule ud) {
+        Set<String> selectedIds = new HashSet<>();
+        Paper paper = Model.of(paperRepo.findById(paperId));
+        List<PaperDetailUnit> pdus = paperDetailUnitRepo.findByPaperOrderByNumber(paper);
+        for (PaperDetailUnit pdu : pdus) {
+            selectedIds.add(pdu.getQuestion().getId());
+        }
+        return quesService.findByIdExclude(selectedIds, paper.getCourseNo(), quesType, curPage, pageSize,
+                user.getRootOrgId(), quesBody, ud);
+    }
+
+    @SuppressWarnings("unused")
+    public Paper selectQuestionsToPaper(String paperId, String paperDetailId, List<Question> questions, User user) {
+        Paper paper = Model.of(paperRepo.findById(paperId));
+        if (paper.getInUse() != null && paper.getInUse() == 1) {
+            throw new StatusException("500", "试卷已调用");
+        }
+        PaperDetail paperDetail = Model.of(paperDetailRepo.findById(paperDetailId));
+        PaperDetailUnit paperDetailUnit = paperDetailUnitRepo.findTopByPaperDetailOrderByNumberDesc(paperDetail);
+
+        List<PaperDetailUnit> saveUnits = new ArrayList<>();
+        for (Question ques : questions) {
+            PaperDetailUnit pdu = new PaperDetailUnit(paper, paperDetail, ques);
+
+            // 如果大题没有小题,取导入的试题分数
+            if (paperDetailUnit == null) {
+                pdu.setNumber(1);
+            } else {
+                pdu.setNumber(paperDetailUnit.getNumber());// 设置为大题中最大的number
+            }
+
+            pdu.setScore(ques.getScore() == null ? 0d : ques.getScore());
+
+            // 处理套题
+            if (pdu.getQuestionType() == QuesStructType.NESTED_ANSWER_QUESTION) {
+                List<Question> subQuestions = ques.getSubQuestions();
+                List<Double> subScoreList = new ArrayList<>();
+                if (subQuestions != null && subQuestions.size() > 0) {
+                    for (Question subQuestion : subQuestions) {
+                        subScoreList.add(CommonUtils.formatDouble(pdu.getScore() / subQuestions.size()));
+                    }
+                }
+                pdu.setSubScoreListNew(subScoreList);
+            }
+
+            saveUnits.add(pdu);
+        }
+
+        paperDetailUnitRepo.saveAll(saveUnits);
+
+        // 清除缓存
+        this.clearPaperCache(paper.getId());
+        paper.setAuditStatus(false);
+        Double total = paper.getTotalScore();
+        Integer dc = paper.getPaperDetailCount();
+        Integer uc = paper.getUnitCount();
+        formatPaper(paper, user);
+
+        StringBuilder paperInfo = new StringBuilder();
+        paperInfo.append("课程:" + paper.getCourse().getName() + "(" + paper.getCourse().getCode() + ")");
+        paperInfo.append(" 试卷名称:" + paper.getName());
+        paperInfo.append(" 第" + paperDetail.getNumber() + "大题选题题数:" + questions.size());
+        String changInfo = PaperUtil.getPaperChangeInfo(total, dc, uc, paper);
+        if (changInfo != null) {
+            paperInfo.append(changInfo);
+        }
+        ReportsUtil.report(new AdminOperateReport(user.getRootOrgId(), user.getUserId(),
+                AdminOperateType.TYPE49.getDesc(), paperInfo.toString()));
+        return paper;
+    }
+
+    public boolean checkPaperName(String paperName, String orgId) {
+        List<Paper> paperList = paperRepo.findByNameAndOrgId(paperName, orgId);
+        if (CollectionUtils.isNotEmpty(paperList)) {
+            return true;
+        }
+        return false;
+    }
+
+    public void checkPaperNameNew(String paperName, String orgId) throws Exception {
+        List<Paper> paperList = paperRepo.findByNameAndOrgId(paperName, orgId);
+        if (paperList != null && paperList.size() > 0) {
+            throw new PaperException("试卷名称重复,请重新命名");
+        }
+    }
+
+    public Page<Paper> getPapersNotInIds(PaperSearchInfo paperSearchInfo, String[] ids, int curPage, int pageSize,
+            PaperType paperType, UserDataRule ud) {
+        Set<String> selectedIds = new HashSet<>();
+        for (String id : ids) {
+            selectedIds.add(id);
+        }
+        if (ud.assertEmptyQueryResult()) {
+            return Page.empty();
+        }
+        Query query = new Query();
+        query.addCriteria(Criteria.where("orgId").is(paperSearchInfo.getOrgId()));
+        if (ud.assertNeedQueryRefIds()) {
+            query.addCriteria(Criteria.where("course.id").in(ud.stringRefIds()));
+        }
+        query.addCriteria(Criteria.where("paperType").is(paperType));
+        query.addCriteria(Criteria.where("course.code").is(paperSearchInfo.getCourseNo()));
+        query.addCriteria(Criteria.where("id").nin(selectedIds));
+        if (PaperType.GENERATE.equals(paperType)) {
+            query.addCriteria(Criteria.where("storage").ne(1));
+        }
+        long total = this.mongoTemplate.count(query, Paper.class);
+        if (total == 0) {
+            return Page.empty();
+        }
+
+        query.with(Sort.by(new Order(Direction.DESC, "createTime")));
+        query.limit(pageSize);
+        query.skip((curPage - 1L) * pageSize);
+        List<Paper> paperList = this.mongoTemplate.find(query, Paper.class);
+        Page<Paper> paperPageList = new PageImpl<Paper>(paperList, PageRequest.of(curPage - 1, pageSize), total);
+        return paperPageList;
+    }
+
+    /**
+     * 使用原卷
+     */
+    public void useBasePaper(String selectedPaperIds, String userId) {
+        Assert.hasLength(selectedPaperIds, "试卷id不能为空!");
+        String[] paperIds = selectedPaperIds.split(",");
+        for (int i = 0; i < paperIds.length; i++) {
+            Paper oldpaper = Model.of(paperRepo.findById(paperIds[i]));
+            List<PaperDetail> paperDetails = paperDetailRepo.findByPaperOrderByNumber(oldpaper);
+            for (PaperDetail paperDetail : paperDetails) {
+                List<PaperDetailUnit> paperDetailUnits = paperDetailUnitService.getUnitsByPaperDetail(paperDetail);
+                paperDetail.setPaperDetailUnits(paperDetailUnits);
+            }
+            // PaperUtil.sortDetails(paperDetails);
+            oldpaper.setId(null);
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            String createTime = sdf.format(new Date());
+            oldpaper.setCreateTime(createTime);
+            oldpaper.setCreator(userId);
+            oldpaper.setLastModifyName(userId);
+            oldpaper.setPaperType(PaperType.GENERATE);// 试卷类型 修改为组卷
+            oldpaper.setAuditStatus(false);
+            Paper newPaper = paperRepo.save(oldpaper);
+            for (int j = 0; j < paperDetails.size(); j++) {
+                PaperDetail paperDetail = paperDetails.get(j);
+                paperDetail.setNumber(j + 1);
+                List<PaperDetailUnit> paperDetailUnits = paperDetail.getPaperDetailUnits();
+                paperDetail.setPaper(newPaper);// 关联新Paper
+                paperDetail.setId(null);
+                paperDetail.setCreateTime(createTime);
+                paperDetail.setCreator(userId);
+                PaperDetail newPaperDetail = paperDetailRepo.save(paperDetail);// 保存新的paperDetail
+                for (int k = 0; k < paperDetailUnits.size(); k++) {
+                    // 重新设置保存PaperDetailUnit
+                    PaperDetailUnit paperDetailUnit = paperDetailUnits.get(k);
+                    paperDetailUnit.setPaper(newPaper); // 关联新Paper
+                    paperDetailUnit.setPaperDetail(newPaperDetail); // 关联新paperDetail
+                    paperDetailUnit.setId(null);
+                    paperDetailUnit.setCreateTime(createTime);
+                    paperDetailUnit.setCreator(userId);
+                    paperDetailUnit.setPaperType(PaperType.GENERATE);
+                    paperDetailUnitRepo.save(paperDetailUnit);// 保存新的paperDetailUnit
+                }
+            }
+        }
+    }
+
+    /**
+     * 根据试卷名称、试卷类型检查名称是否存在
+     *
+     * @param paperName
+     * @param paperType
+     * @param orgId
+     * @return
+     * @throws Exception
+     */
+    public boolean checkPaperName(String paperName, PaperType paperType, String orgId) throws Exception {
+        Query query = new Query();
+        query.addCriteria(Criteria.where("orgId").is(orgId));
+        query.addCriteria(Criteria.where("name").is(paperName.trim()));
+        query.addCriteria(Criteria.where("paperType").is(paperType));
+        List<Paper> papers = this.mongoTemplate.find(query, Paper.class);
+        if (papers != null && papers.size() > 0) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 上传音频文件检查
+     *
+     * @param paperId
+     * @param filesName
+     * @return
+     */
+    public Map<String, String> checkRadioFile(String paperId, List<String> filesName) {
+        Map<String, String> messageMap = new HashMap<>();
+        // 判断文件名中格式是否正确
+        for (String fileName : filesName) {
+            String[] fileNames = fileName.split("\\.");
+            String fileType = fileNames[fileNames.length - 1];
+            if (sysProperty.getRadioType().indexOf(fileType) < 0) {
+                messageMap.put("errorMsg", fileName + ",文件格式不正确,当前支持格式:" + sysProperty.getRadioType());
+                return messageMap;
+            }
+
+            String pattern_01 = "\\d+_1_\\d{1,2}"; // 题干正则
+            String pattern_02 = "\\d+_2_[A-Z|a-z]_\\d{1,2}"; // 选项正则
+            if (!(Pattern.matches(pattern_01, fileNames[0]) || Pattern.matches(pattern_02, fileNames[0]))) {
+                messageMap.put("errorMsg", fileName + "文件名格式不正确,请检查");
+                return messageMap;
+            }
+        }
+
+        // 根据试卷id,查询该试卷
+        Paper paper = Model.of(paperRepo.findById(paperId));
+
+        // 根据试卷查询所有的小题
+        List<PaperDetailUnit> paperDetailUnits = paperDetailUnitRepo.findByPaperOrderByNumber(paper);
+
+        String names = "";
+        for (PaperDetailUnit paperDetailUnit : paperDetailUnits) {
+            names = names + paperDetailUnit.getNumber().toString() + ",";
+        }
+
+        for (String fileName : filesName) {
+            String fileNames[] = fileName.split("_");
+
+            // 先判断小题号是否正确
+            String fileNameFirst = fileNames[0];
+            if (!names.contains(fileNameFirst)) {
+                messageMap.put("errorMsg", fileName + "文件,试卷中没有对应的小题");
+                return messageMap;
+            }
+
+            // 再判断题干中是否存在ABCD
+            String fileNameSecond = fileNames[1];
+            if (fileNameSecond.equals("1")) {
+                if (fileNames.length > 3) {
+                    Matcher m = Pattern.compile(".*[a-zA-Z]+.*").matcher(fileNames[2]);
+                    if (m.matches()) {
+                        messageMap.put("errorMsg", fileName + "文件名称不对,文件名为题干,但存在选项");
+                        return messageMap;
+                    }
+                }
+            }
+
+            // 判断选项
+            else if (fileNameSecond.equals("2")) {
+                messageMap = checkOptions(paperDetailUnits, fileNames, fileName);
+                if (messageMap != null) {
+                    return messageMap;
+                }
+                messageMap = new HashMap<>();
+            } else {
+                messageMap.put("errorMsg", fileName + "文件名称不对,无法识别为题干或选项 ");
+                return messageMap;
+            }
+        }
+
+        messageMap.put("errorMsg", "OK");
+        return messageMap;
+    }
+
+    // 判断选项
+    public Map<String, String> checkOptions(List<PaperDetailUnit> paperDetailUnits, String fileNames[],
+            String fileName) {
+        Map<String, String> messageMap = new HashMap<>();
+        for (PaperDetailUnit paperDetailUnit : paperDetailUnits) {
+            if (paperDetailUnit.getNumber().toString().equals(fileNames[0])) {
+                // 判断是否为选择题
+                if (paperDetailUnit.getQuestionType() != QuesStructType.SINGLE_ANSWER_QUESTION
+                        && paperDetailUnit.getQuestionType() != QuesStructType.MULTIPLE_ANSWER_QUESTION) {
+                    Matcher m = Pattern.compile(".*[a-zA-Z]+.*").matcher(fileNames[2]);
+                    if (m.matches()) {
+                        messageMap.put("errorMsg", fileName + "文件名称有误,题目不是选择题");
+                        return messageMap;
+                    }
+                    break;
+                } else {
+                    List<QuesOption> options = paperDetailUnit.getQuestion().getQuesOptions();
+                    String option = "";
+                    for (QuesOption quesOption : options) {
+                        option = option + quesOption.getNumber() + ",";
+                    }
+                    Integer integer = CommonUtils.characterToNumber(fileNames[2]);
+                    if (!option.contains(integer.toString())) {
+                        messageMap.put("errorMsg", fileName + "文件名称有误,题目中没有对应的" + fileNames[2] + "选项");
+                        return messageMap;
+                    }
+                    break;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 上传音频文件到又拍云
+     *
+     * @param files
+     * @param paperId
+     * @throws IOException
+     */
+    public void uploadRadio(List<MultipartFile> files, String paperId, User user) {
+        // 根据试卷id,查询该试卷
+        Paper paper = Model.of(paperRepo.findById(paperId));
+
+        for (MultipartFile file : files) {
+            // 判断文件大小
+            long fileSize = file.getSize();
+            int size = Integer.parseInt(sysProperty.getAudioMaxsize());
+            if (fileSize > (size * 1048576L)) {
+                throw new StatusException("400", "音频文件过大,限制" + size + "M内!");
+            }
+
+            // 根据试卷查询所有的小题,根据文件名匹配出当前小题ID
+            String numbers[] = file.getOriginalFilename().split("_");
+            if (numbers.length < 3) {
+                throw new StatusException("400", "音频文件命名格式错误!");
+            }
+
+            PaperDetailUnit unit = paperDetailUnitRepo.findByPaperAndNumber(paper, Integer.valueOf(numbers[0]));
+            if (unit == null || unit.getQuestion() == null) {
+                throw new StatusException("400", "对应试题不存在!");
+            }
+
+            Question question = unit.getQuestion();
+            uploadAudioFile(paperId, question.getId(), file, user);
+            appendAudioTag(file.getOriginalFilename(), question.getId());
+
+            // 清除缓存
+            this.clearQuestionCache(question.getId());
+        }
+
+        // 删除服务器文件夹
+        String mp3DirectoryPath = TEMP_FILE_EXP + File.separator + paperId;
+        try {
+            File mp3Directory = new File(mp3DirectoryPath);
+            FileUtils.deleteDirectory(mp3Directory);
+        } catch (IOException e) {
+            LOG.error(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 上传音频文件至又拍云
+     */
+    private void uploadAudioFile(String paperId, String questionId, MultipartFile file, User user) {
+        // 文件名包含随机数,防止缓存
+        int randomNumber = random.nextInt(1000);
+        final String mp3FileName = questionId + "_" + randomNumber + "_" + file.getOriginalFilename();
+
+        try {
+            String audioFilePath = String.format(FileConstants.RADIO_UPLOAD_PATH, mp3FileName);
+            FssFileInfo result = FssFactory.getInstance().writeFile(audioFilePath, file.getBytes(), null);
+
+            // 保存记录
+            QuestionAudio audio = new QuestionAudio(questionId, file.getOriginalFilename(), result.getFilePath());
+            questionAudioService.saveQuestionAudio(audio, user);
+        } catch (Exception e) {
+            LOG.error(e.getMessage(), e);
+            throw new StatusException("500", "音频文件保存失败!");
+        }
+    }
+
+    /**
+     * 音频文件插入到标签
+     */
+    private void appendAudioTag(String fileName, String questionId) {
+        QuestionAudio questionAudio = questionAudioService.findByQuestionIdAndFileName(questionId, fileName);
+        if (questionAudio == null) {
+            return;
+        }
+
+        Question question = Model.of(quesRepo.findById(questionAudio.getQuestionId()));
+
+        // 正则匹配音频标签
+        Pattern audioPattern = Pattern.compile(String.format("<a id=\"[\\d,\\w]+\" name=\"%s\"></a>", fileName));
+        final String audioTag = String.format("<a id=\"%s\" name=\"%s\"></a>", questionAudio.getId(), fileName);
+
+        String numbers[] = fileName.split("_");
+        if (numbers[1].equals("1")) {
+            // 处理题干
+            String quesBody = question.getQuesBody();
+            if (StringUtils.isBlank(quesBody)) {
+                question.setQuesBody("<p>" + audioTag + "</p>");
+            } else {
+                Matcher matcher = audioPattern.matcher(quesBody);
+                if (matcher.find()) {
+                    // 已存在音频标签则直接替换
+                    question.setQuesBody(matcher.replaceAll(audioTag));
+                } else {
+                    // 不存在音频标签则添加
+                    question.setQuesBody(quesBody + "<p>" + audioTag + "</p>");
+                }
+            }
+        } else {
+            // 处理选项
+            for (QuesOption quesOption : question.getQuesOptions()) {
+                Integer optNumber = CommonUtils.characterToNumber(numbers[2]);
+                if (!quesOption.getNumber().equals(optNumber.toString())) {
+                    continue;
+                }
+
+                String optionBody = quesOption.getOptionBody();
+                if (StringUtils.isBlank(optionBody)) {
+                    quesOption.setOptionBody("<p>" + audioTag + "</p>");
+                    continue;
+                }
+
+                Matcher matcher = audioPattern.matcher(optionBody);
+                if (matcher.find()) {
+                    // 已存在音频标签则直接替换
+                    quesOption.setOptionBody(matcher.replaceAll(audioTag));
+                } else {
+                    // 不存在音频标签则添加
+                    quesOption.setOptionBody(optionBody + "<p>" + audioTag + "</p>");
+                }
+            }
+        }
+
+        question.setHasAudio(true);
+        quesRepo.save(question);
+    }
+
+    @Override
+    public Map<String, Object> getPaperPDF(String paperId, String type) {
+        PaperExp paperExp = getPaperDto(paperId);
+        Map<String, Object> map = new HashMap<>();
+        map.put("courseName", paperExp.getCourseName());
+        map.put("courseNo", paperExp.getCourseNo());
+        List<String> htmlList = new ArrayList<>();
+        if (paperExp.getPaperDetails() != null && paperExp.getPaperDetails().size() > 0) {
+            for (PaperDetailExp paperDetail : paperExp.getPaperDetails()) {
+                // 添加大题标题
+                if (StringUtils.isBlank(paperDetail.getTitle())) {
+                    // htmlList.add(("<p>"+paperDetail.getCnNum()+"、"+paperDetail.getName()+"</p>").replaceAll("'",
+                    // "&apos"));
+                    htmlList.add(("<p class='paperDetailTitle'>" + paperDetail.getCnNum() + "、" + paperDetail.getName()
+                            + "</p>").replaceAll("'", "&apos"));
+                } else {
+                    htmlList.add("<p class='paperDetailTitle'>" + paperDetail.getCnNum() + "、" + paperDetail.getName()
+                            + paperDetail.getTitle() + "</p>");
+                }
+                if (paperDetail.getPaperDetailUnits() != null && paperDetail.getPaperDetailUnits().size() > 0) {
+                    for (PaperDetailUnitExp paperDetailUnitExp : paperDetail.getPaperDetailUnits()) {
+                        Question question = paperDetailUnitExp.getQuestion();
+                        if (type.equals("paper")) {
+                            // 添加题干
+                            String questionBody = CommonUtils.deleteHtmlP(paperDetailUnitExp.getNumber() + "."
+                                    + question.getQuesBody() + "(" + paperDetailUnitExp.getScore() + "分)");
+                            htmlList.add("<p class='questionBody'>" + questionBody + "</p>");
+                            // 判断是否为选择题
+                            if (paperDetailUnitExp.getQuestionType() == QuesStructType.SINGLE_ANSWER_QUESTION
+                                    || paperDetailUnitExp
+                                            .getQuestionType() == QuesStructType.MULTIPLE_ANSWER_QUESTION) {
+                                for (QuesOption quesOption : question.getQuesOptions()) {
+                                    // 添加选项
+                                    String questionOption = CommonUtils.deleteHtmlP(
+                                            CommonUtils.getOptionNum(Integer.parseInt(quesOption.getNumber()) - 1) + "."
+                                                    + quesOption.getOptionBody());
+                                    htmlList.add("<p class='selectOption'>" + questionOption + "</p>");
+                                }
+                            }
+                            // 判断是否为套题
+                            if (paperDetailUnitExp.getQuestionType() == QuesStructType.NESTED_ANSWER_QUESTION) {
+                                // 得到子题
+                                List<Question> subQuestions = question.getSubQuestions();
+                                for (Question subQuestion : subQuestions) {
+                                    // 添加子题题干
+                                    String subQuestionBody = CommonUtils
+                                            .deleteHtmlP(subQuestion.getQuesParams().get("number") + "."
+                                                    + subQuestion.getQuesBody() + "(" + subQuestion.getScore() + "分)");
+                                    htmlList.add("<p class='questionBody'>" + subQuestionBody + "</p>");
+                                    // 判断是否为选择题
+                                    if (subQuestion.getQuestionType() == QuesStructType.SINGLE_ANSWER_QUESTION
+                                            || subQuestion
+                                                    .getQuestionType() == QuesStructType.MULTIPLE_ANSWER_QUESTION) {
+                                        for (QuesOption quesOption : subQuestion.getQuesOptions()) {
+                                            // 添加选项
+                                            String questionOption = CommonUtils.deleteHtmlP(CommonUtils
+                                                    .getOptionNum(Integer.parseInt(quesOption.getNumber()) - 1) + "."
+                                                    + quesOption.getOptionBody());
+                                            htmlList.add("<p class='selectOption'>" + questionOption + "</p>");
+                                        }
+                                    }
+                                }
+                            }
+                        } else {
+                            // 判断是否为套题
+                            if (paperDetailUnitExp.getQuestionType() == QuesStructType.NESTED_ANSWER_QUESTION) {
+                                // 得到子题
+                                List<Question> subQuestions = question.getSubQuestions();
+                                for (Question subQuestion : subQuestions) {
+                                    // 添加答案
+                                    String questionAnswer = CommonUtils
+                                            .deleteHtmlP(subQuestion.getQuesParams().get("number") + "."
+                                                    + subQuestion.getQuesAnswer() + "(" + subQuestion.getScore()
+                                                    + "分)");
+                                    htmlList.add("<p class='questionAnswer'>" + questionAnswer + "</p>");
+                                }
+                            } else {
+                                // 添加答案
+                                String questionAnswer = CommonUtils.deleteHtmlP(paperDetailUnitExp.getNumber() + "."
+                                        + question.getQuesAnswer() + "(" + paperDetailUnitExp.getScore() + "分)");
+                                htmlList.add("<p class='questionAnswer'>" + questionAnswer + "</p>");
+                            }
+                        }
+
+                    }
+                }
+            }
+        }
+        map.put("htmlList", htmlList);
+        return map;
+    }
+
+    @SuppressWarnings("unused")
+    @Override
+    public String sendPrint(String paperId, String orgId, String examId) {
+        // 查询原paper对象
+        Paper paper = Model.of(paperRepo.findById(paperId));
+        SyncCoursePaperBean bean = new SyncCoursePaperBean();
+        bean.setOrgId(Long.valueOf(orgId));
+        bean.setExamId(Long.valueOf(examId));
+        Course course = courseService.getCourse(Long.valueOf(orgId), paper.getCourse().getCode());
+        bean.setCourseId(Long.valueOf(course.getId()));
+        bean.setCourseCode(paper.getCourse().getCode());
+        bean.setCourseName(paper.getCourse().getName());
+        bean.setPaperId(paper.getId());
+        bean.setPaperName(paper.getName());
+        SyncCoursePaperReq req = new SyncCoursePaperReq();
+        req.setBean(bean);
+        SyncCoursePaperResp resp = coursePaperCloudService.syncCoursePaper(req);
+        return "success";
+    }
+
+    @Override
+    public String findQuestionStructure(String paperId) throws Exception {
+        // 根据paperId查询新的对象
+        ExportPaperAbstractService exportPaperAbstractService = (ExportPaperAbstractService) SpringContextHolder
+                .getBean("exportPaperAbstractService");
+        DownloadPaperDto dto = new DownloadPaperDto();
+        dto.setPaperId(paperId);
+        dto.setSeqMode(PaperSeqMode.MODE3);
+        PaperExp paperExp = exportPaperAbstractService.initPaperExp(dto);
+        LOG.info("已经获取试卷");
+        // 得到试卷中的客观大题
+        List<PaperDetailExp> objectiveDetails = exportPaperAbstractService.getAllObjectiveDetails(paperExp);
+        // 客观题中如果有套题,要拆开
+        List<PaperDetailExp> newObjectiveDetails = buildPaperDetailExp(objectiveDetails);
+        // 生成客观题数集合
+        List<ObjectiveQuestionStructure> objectiveQuestionStructureList = new ArrayList<>();
+        for (PaperDetailExp paperDetailExp : newObjectiveDetails) {
+            for (PaperDetailUnitExp unit : paperDetailExp.getPaperDetailUnits()) {
+                objectiveQuestionStructureList
+                        .add(new ObjectiveQuestionStructure(paperExp, paperDetailExp, unit, null));
+            }
+        }
+        LOG.info("生成客观题数集合");
+        // 得到试卷中的主观大题
+        List<PaperDetailExp> subjectiveDetails = exportPaperAbstractService.getAllSubjectiveDetails(paperExp);
+        // 生成主观题数集合
+        List<SubjectiveQuestionStructure> subjectiveQuestionStructureList = new ArrayList<>();
+        for (PaperDetailExp paperDetailExp : subjectiveDetails) {
+            for (PaperDetailUnitExp unit : paperDetailExp.getPaperDetailUnits()) {
+                subjectiveQuestionStructureList
+                        .add(new SubjectiveQuestionStructure(paperExp, paperDetailExp, unit, null));
+            }
+        }
+        LOG.info("生成主观题数集合");
+        PaperQuestionStructureInfo info = new PaperQuestionStructureInfo();
+        info.setObjectives(objectiveQuestionStructureList);
+        info.setSubjectives(subjectiveQuestionStructureList);
+        String jsonResp = JsonUtil.toJson(info);
+        LOG.info("jsonResp:" + jsonResp);
+        return jsonResp;
+    }
+
+    public List<PaperDetailExp> buildPaperDetailExp(List<PaperDetailExp> objectiveDetails) {
+        // 1.得到所有客观题大题的类型
+        Set<QuesStructType> types = new HashSet<>();
+        for (PaperDetailExp paperDetailExp : objectiveDetails) {
+            types.add(QuesStructType.getQuesStructTypeById(paperDetailExp.getSortNumber()));
+        }
+        // 2.生成新的大题集合
+        List<PaperDetailExp> newObjs = new ArrayList<>();
+        for (QuesStructType type : types) {
+            for (PaperDetailExp paperDetailExp : objectiveDetails) {
+                if (paperDetailExp.getSortNumber().equals(type.getId())) {
+                    // 生成新的大题
+                    PaperDetailExp newPaperDetailExp = new PaperDetailExp();
+                    // 生成新的小题
+                    List<PaperDetailUnitExp> newPaperDetailUnits = new ArrayList<>();
+                    // 得到旧大题下的所有小题
+                    List<PaperDetailUnitExp> paperDetailUnits = paperDetailExp.getPaperDetailUnits();
+                    for (PaperDetailUnitExp paperDetailUnitExp : paperDetailUnits) {
+                        if (paperDetailUnitExp.getQuestionType() != QuesStructType.NESTED_ANSWER_QUESTION) {
+                            newPaperDetailUnits.add(paperDetailUnitExp);
+                        } else {
+                            List<Question> subQuestions = paperDetailUnitExp.getQuestion().getSubQuestions();
+                            if (subQuestions != null && subQuestions.size() > 0) {
+                                for (int i = 0; i < subQuestions.size(); i++) {
+                                    newPaperDetailUnits.add(new PaperDetailUnitExp(type, subQuestions.get(i)));
+                                }
+                            }
+                        }
+                    }
+                    // 设置小题
+                    newPaperDetailExp.setPaperDetailUnits(newPaperDetailUnits);
+                    // 设置大题题号
+                    newPaperDetailExp.setNumber(Integer.parseInt(type.getId() + ""));
+                    newPaperDetailExp.setSortNumber(paperDetailExp.getSortNumber());
+                    newObjs.add(newPaperDetailExp);
+                }
+            }
+        }
+        // 刷一遍number
+        int num = 0;
+        for (QuesStructType type : types) {
+            for (int i = 0; i < newObjs.size(); i++) {
+                if (newObjs.get(i).getSortNumber().equals(type.getId())) {
+                    List<PaperDetailUnitExp> exps = newObjs.get(i).getPaperDetailUnits();
+                    for (int j = 0; j < exps.size(); j++) {
+                        num++;
+                        exps.get(j).setNumber(num);
+                    }
+                }
+            }
+        }
+        return newObjs;
+    }
+
+    @Override
+    public PaperExp getDownPaperExp(String paperId) {
+        Paper paper = Model.of(paperRepo.findById(paperId));
+        // 创建paperDto
+        PaperExp paperExp = BeanCopierUtil.copyProperties(paper, PaperExp.class);
+        paperExp.setCourseName(paper.getCourse().getName());
+        paperExp.setCourseNo(paper.getCourse().getCode());
+        paperExp.setCourse(paper.getCourse());
+        // 获取大题
+        List<PaperDetail> paperDetails = paperDetailRepo.findByPaperOrderByNumber(paper);
+        List<PaperDetailExp> paperDetailExps = new ArrayList<>();
+        for (PaperDetail paperDetail : paperDetails) {
+            PaperDetailExp paperDetailExp = new PaperDetailExp();
+            BeanUtils.copyProperties(paperDetail, paperDetailExp);
+            if (StringUtils.isBlank(paperDetailExp.getName())) {
+                paperDetailExp.setName("默认大题");
+            }
+            paperDetailExps.add(paperDetailExp);
+        }
+        // 封装小题
+        for (int i = 0; i < paperDetailExps.size(); i++) {
+            List<PaperDetailUnit> paperDetailUnits = paperDetailUnitRepo
+                    .findByPaperDetailOrderByNumber(paperDetails.get(i));
+            if (paperDetailUnits != null && paperDetailUnits.size() > 0) {
+                List<PaperDetailUnitExp> paperDetailUnitExps = new ArrayList<>();
+                for (PaperDetailUnit paperDetailUnit : paperDetailUnits) {
+                    PaperDetailUnitExp paperDetailUnitExp = new PaperDetailUnitExp();
+                    BeanUtils.copyProperties(paperDetailUnit, paperDetailUnitExp);
+                    paperDetailUnitExps.add(paperDetailUnitExp);
+                }
+                paperDetailExps.get(i).setPaperDetailUnits(paperDetailUnitExps);
+                paperDetailExps.get(i).setUnitCount(paperDetailUnitExps.size());
+            } else {
+                paperDetailExps.get(i).setUnitCount(0);
+            }
+        }
+        paperExp.setPaperDetails(paperDetailExps);
+        if (paperExp.getPaperDetails() == null || paperExp.getPaperDetails().size() == 0) {
+            return paperExp;
+        }
+        int mainNum = 0;
+        List<PaperDetailExp> paperDetailExpList = paperExp.getPaperDetails();
+        for (PaperDetailExp paperDetail : paperDetailExpList) {
+            // 大题序号
+            paperDetail.setNumber(++mainNum);
+            paperDetail.setCnNum(CommonUtils.toCHNum(paperDetail.getNumber()));
+            if (paperDetail.getPaperDetailUnits() == null || paperDetail.getPaperDetailUnits().size() == 0) {
+                throw new StatusException("500", "第" + mainNum + "大题没有小题");
+            }
+            if (paperDetail != null && paperDetail.getPaperDetailUnits() != null
+                    && paperDetail.getPaperDetailUnits().size() > 0) {
+                for (PaperDetailUnitExp paperDetailUnit : paperDetail.getPaperDetailUnits()) {
+                    Question question = paperDetailUnit.getQuestion();
+                    question.setDifficultyDegree(question.getDifficultyDegree() * 10);
+                    if (question.getPublicity() == null || question.getPublicity() == true) {
+                        paperDetailUnit.setPublicity("公开");
+                    } else {
+                        paperDetailUnit.setPublicity("非公开");
+                    }
+                    if (StringUtils.isBlank(paperDetail.getQuesType())) {
+                        paperDetail.setQuesType(question.getQuestionType().getName());
+                    }
+                    // 设置选项
+                    List<QuesOption> optionList = paperDetailUnit.getQuestion().getQuesOptions();
+                    if (optionList != null && optionList.size() > 0) {
+                        // int index = 0;
+                        // for (QuesOption quesOption : optionList) {
+                        // quesOption.setOptionBodyWord(setOptionNum(quesOption.getOptionBodyWord(),
+                        // getOptionNum(index)));
+                        // index++;
+                        // }
+                    }
+                    if (question.getQuestionType() != QuesStructType.NESTED_ANSWER_QUESTION) {
+                        // 给小题设置序号
+                        // question.setQuesBodyWord(setSubQuesNum(question.getQuesBodyWord(),
+                        // minNum++));
+                        // question.setQuesAnswerWord(setAnswerNum(question.getQuesAnswerWord()));
+                        fillProperty(question);
+                        if (paperDetail.getFirstScore() == null) {
+                            if (question.getScore() == null) {
+                                paperDetail.setFirstScore(0d);
+                            } else {
+                                paperDetail.setFirstScore(question.getScore());
+                            }
+                        }
+                    } else {
+                        List<Question> subQuesList = question.getSubQuestions();
+                        // 套题小题设置序号
+                        if (subQuesList != null && subQuesList.size() > 0) {
+                            for (Question subQues : subQuesList) {
+                                subQues.setDifficultyDegree(subQues.getDifficultyDegree() * 10);
+                                // subQues.setQuesBodyWord(setSubQuesNum(subQues.getQuesBodyWord(),
+                                // index++));
+                                // subQues.setQuesAnswerWord(setAnswerNum(subQues.getQuesAnswerWord()));
+                                if (paperDetail.getFirstScore() == null) {
+                                    if (subQues.getScore() == null) {
+                                        paperDetail.setFirstScore(0d);
+                                    } else {
+                                        paperDetail.setFirstScore(subQues.getScore());
+                                    }
+                                }
+                                fillProperty(subQues);
+                            }
+                        }
+                    }
+                    List<QuesProperty> quesProperties = question.getQuesProperties();
+                    if (quesProperties != null && quesProperties.size() > 0) {
+                        QuesProperty quesProperty = quesProperties.get(0);
+                        if (quesProperty.getFirstProperty() != null) {
+                            paperDetailUnit.setFirstName(quesProperty.getFirstProperty().getName());
+                            paperDetailUnit.setFirstCode(quesProperty.getFirstProperty().getCode());
+                        }
+                        if (quesProperty.getSecondProperty() != null) {
+                            paperDetailUnit.setSecondName(quesProperty.getSecondProperty().getName());
+                            paperDetailUnit.setSecondCode(quesProperty.getSecondProperty().getCode());
+                        }
+                    }
+                }
+            }
+        }
+        return paperExp;
+    }
+
+    private void fillProperty(Question question) {
+        List<QuesProperty> ret = new ArrayList<>();
+        List<QuesProperty> quesProperties = question.getQuesProperties();
+        if (quesProperties != null && quesProperties.size() > 0) {
+            for (QuesProperty quesProperty : quesProperties) {
+                if (quesProperty.getFirstProperty() != null && quesProperty.getFirstProperty().getId() != null) {
+                    Property curProperty = Model.of(propertyRepo.findById(quesProperty.getFirstProperty().getId()));
+                    if (curProperty == null) {
+                        continue;
+                    }
+                    quesProperty.setFirstProperty(curProperty);
+                }
+                if (quesProperty.getSecondProperty() != null && quesProperty.getSecondProperty().getId() != null) {
+                    Property curProperty = Model.of(propertyRepo.findById(quesProperty.getSecondProperty().getId()));
+                    if (curProperty == null) {
+                        continue;
+                    }
+                    quesProperty.setSecondProperty(curProperty);
+                }
+                ret.add(quesProperty);
+            }
+        }
+        question.setQuesProperties(ret);
+    }
+
+    /**
+     * 设置题号
+     *
+     * @param quesBodyWordMl
+     * @param num
+     * @return
+     * @throws Exception
+     */
+    // public String setSubQuesNum(String quesBodyWordMl, int num) throws
+    // Exception
+    // {
+    // String tmpStr = DocxProcessUtil.BODY_HEADER + quesBodyWordMl +
+    // DocxProcessUtil.BODY_TAIL;
+    // Body body = (Body) XmlUtils.unmarshalString(tmpStr, Context.jc,
+    // Body.class);
+    // List<Object> pList = body.getContent();
+    // int index = 0;
+    // for (Object pObj : pList) {
+    // if (index > 0) {
+    // break;
+    // }
+    // P p = (P) pObj;
+    // List<Object> pContent = p.getContent();
+    // R run = new R();
+    // Text text = new Text();
+    // text.setValue(num + ". ");
+    // run.getContent().add(text);
+    // pContent.add(0, run);
+    // index++;
+    // }
+    // StringBuffer pWordMl = new StringBuffer();
+    // for (Object pObj : pList) {
+    // if (pObj instanceof P) {
+    // pWordMl.append(DocxProcessUtil.formatPWordMl(XmlUtils.marshaltoString(pObj)));
+    // }
+    // }
+    // return pWordMl.toString();
+    // }
+
+    /**
+     * 将数字1,2,3,4转化成A,B,C,D
+     *
+     * @param number
+     * @return
+     */
+    public String getOptionNum(int number) {
+        char optionNum = (char) (65 + number);
+        return String.valueOf(optionNum);
+    }
+
+    /**
+     * 设置选项号
+     *
+     * @param optionWordMl
+     * @param num
+     * @return
+     * @throws Exception
+     */
+    // public String setOptionNum(String optionWordMl, String num) throws
+    // Exception
+    // {
+    // String tmpStr = DocxProcessUtil.BODY_HEADER + optionWordMl +
+    // DocxProcessUtil.BODY_TAIL;
+    // Body body = (Body) XmlUtils.unmarshalString(tmpStr, Context.jc,
+    // Body.class);
+    // List<Object> pList = body.getContent();
+    // int index = 0;
+    // for (Object pObj : pList) {
+    // if (index > 0) {
+    // break;
+    // }
+    // P p = (P) pObj;
+    // List<Object> pContent = p.getContent();
+    // R run = new R();
+    // Text text = new Text();
+    // text.setValue(num + ". ");
+    // run.getContent().add(text);
+    // pContent.add(0, run);
+    // index++;
+    // }
+    // StringBuffer pWordMl = new StringBuffer();
+    // for (Object pObj : pList) {
+    // if (pObj instanceof P) {
+    // pWordMl.append(DocxProcessUtil.formatPWordMl(XmlUtils.marshaltoString(pObj)));
+    // }
+    // }
+    // return pWordMl.toString();
+    // }
+
+    // public String setAnswerNum(String quesBodyWordMl) throws Exception {
+    // String tmpStr = DocxProcessUtil.BODY_HEADER + quesBodyWordMl +
+    // DocxProcessUtil.BODY_TAIL;
+    // Body body = (Body) XmlUtils.unmarshalString(tmpStr, Context.jc,
+    // Body.class);
+    // List<Object> pList = body.getContent();
+    // int index = 0;
+    // for (Object pObj : pList) {
+    // if (index > 0) {
+    // break;
+    // }
+    // P p = (P) pObj;
+    // List<Object> pContent = p.getContent();
+    // R run = new R();
+    // Text text = new Text();
+    // text.setValue("[答案]:");
+    // run.getContent().add(text);
+    // pContent.add(0, run);
+    // index++;
+    // }
+    // StringBuffer pWordMl = new StringBuffer();
+    // for (Object pObj : pList) {
+    // if (pObj instanceof P) {
+    // pWordMl.append(DocxProcessUtil.formatPWordMl(XmlUtils.marshaltoString(pObj)));
+    // }
+    // }
+    // return pWordMl.toString();
+    // }
+    @Override
+    public int getQuestionTypeNumbers(String paperId, Integer publicityType, Integer difficultyType) {
+        if (publicityType == null || difficultyType == null) {
+            return 0;
+        }
+        Boolean publicity = null;
+        String difficulty = null;
+        if (publicityType == 1) {
+            publicity = true;
+        } else {
+            publicity = false;
+        }
+        if (difficultyType == 1) {
+            difficulty = "易";
+        } else if (difficultyType == 2) {
+            difficulty = "中";
+        } else {
+            difficulty = "难";
+        }
+        String needType = publicity + "-" + difficulty;
+        Paper paper = Model.of(paperRepo.findById(paperId));
+        List<PaperDetailUnit> units = paperDetailUnitRepo.findByPaperOrderByNumber(paper);
+        if (units != null && units.size() > 0) {
+            int total = 0;
+            for (PaperDetailUnit unit : units) {
+                if (unit.getQuestion().getPublicity() == null) {
+                    unit.getQuestion().setPublicity(true);
+                }
+                if (unit.getQuestion().getDifficulty() == null) {
+                    unit.getQuestion().setDifficulty("中");
+                }
+                String factType = unit.getQuestion().getPublicity() + "-" + unit.getQuestion().getDifficulty();
+                if (needType.equals(factType)) {
+                    total += 1;
+                }
+            }
+            return total;
+        }
+        return 0;
+    }
+
+    @Override
+    public double getQuestionTypeScore(String paperId, Integer publicityType, Integer difficultyType) {
+        if (publicityType == null || difficultyType == null) {
+            return 0;
+        }
+        Boolean publicity = null;
+        String difficulty = null;
+        if (publicityType == 1) {
+            publicity = true;
+        } else {
+            publicity = false;
+        }
+        if (difficultyType == 1) {
+            difficulty = "易";
+        } else if (difficultyType == 2) {
+            difficulty = "中";
+        } else {
+            difficulty = "难";
+        }
+        String needType = publicity + "-" + difficulty;
+        Paper paper = Model.of(paperRepo.findById(paperId));
+        List<PaperDetailUnit> units = paperDetailUnitRepo.findByPaperOrderByNumber(paper);
+        if (units != null && units.size() > 0) {
+            double total = 0;
+            BigDecimal b1 = BigDecimal.valueOf(total);
+            for (PaperDetailUnit unit : units) {
+                if (unit.getQuestion().getPublicity() == null) {
+                    unit.getQuestion().setPublicity(true);
+                }
+                if (unit.getQuestion().getDifficulty() == null) {
+                    unit.getQuestion().setDifficulty("中");
+                }
+                String factType = unit.getQuestion().getPublicity() + "-" + unit.getQuestion().getDifficulty();
+                if (needType.equals(factType)) {
+                    BigDecimal b2 = BigDecimal.valueOf(unit.getScore());
+                    b1 = b1.add(b2);
+                }
+            }
+            return b1.doubleValue();
+        }
+        return 0;
+    }
+
+    private void clearPaperCache(String paperId) {
+        // 清理与当前试卷相关的缓存
+        // final String patternKey = CACHE_KEY_PAPER + "*" + paperId;
+        // Set<String> keys = redisTemplate.keys(patternKey);
+        // if (CollectionUtils.isNotEmpty(keys)) {
+        // redisTemplate.delete(keys);
+        // }
+        extractConfigPaperCache.remove(paperId);
+        basePaperCache.remove(paperId);
+    }
+
+    private void clearQuestionCache(String questionId) {
+        // 清理与当前试题相关的缓存
+        // final String patternKey = CACHE_KEY_QUESTION + "*" + questionId;
+        // Set<String> keys = redisTemplate.keys(patternKey);
+        // if (CollectionUtils.isNotEmpty(keys)) {
+        // redisTemplate.delete(keys);
+        // }
+        questionCache.remove(questionId);
+        questionAnswerCache.remove(questionId);
+    }
+
+    @Override
+    public List<PaperAnswerDomain> answerExport(Paper paper) {
+        List<PaperAnswerDomain> ret = new ArrayList<PaperAnswerDomain>();
+        List<PaperDetail> paperDetails = paperDetailRepo.findByPaperOrderByNumber(paper);
+        if (paperDetails != null && paperDetails.size() > 0) {
+            for (PaperDetail paperDetail : paperDetails) {
+                List<PaperDetailUnit> paperDetailUnits = paperDetailUnitRepo
+                        .findByPaperDetailOrderByNumber(paperDetail);
+                if (paperDetailUnits != null && paperDetailUnits.size() > 0) {
+                    for (PaperDetailUnit paperDetailUnit : paperDetailUnits) {
+                        Question ques = paperDetailUnit.getQuestion();
+                        if (QuesStructType.NESTED_ANSWER_QUESTION.equals(ques.getQuestionType())) {
+                            List<Question> subques = ques.getSubQuestions();
+                            if (subques != null && subques.size() > 0) {
+                                for (int i = 0; i < subques.size(); i++) {
+                                    Question subq = subques.get(i);
+                                    PaperAnswerDomain domain = new PaperAnswerDomain();
+                                    domain.setName(paperDetail.getName());
+                                    domain.setNumber(paperDetail.getNumber());
+                                    domain.setSubNumber(paperDetailUnit.getNumber());
+                                    domain.setSubType(subq.getQuestionType().getName());
+                                    domain.setChildNumber(i + 1);
+                                    domain.setAnswer(subq.getQuesAnswer());
+                                    ret.add(domain);
+                                }
+                            }
+                        } else {
+                            PaperAnswerDomain domain = new PaperAnswerDomain();
+                            domain.setName(paperDetail.getName());
+                            domain.setNumber(paperDetail.getNumber());
+                            domain.setSubNumber(paperDetailUnit.getNumber());
+                            domain.setSubType(paperDetailUnit.getQuestionType().getName());
+                            domain.setAnswer(ques.getQuesAnswer());
+                            ret.add(domain);
+                        }
+                    }
+                }
+            }
+        }
+        return ret;
+    }
+
+    @Override
+    public void answerImport(Paper paper, MultipartFile dataFile) {
+        File file = new File(systemProperties.getTempDataDir() + File.separator + UUID.randomUUID() + ".xlsx");
+        try {
+            file.createNewFile();
+            dataFile.transferTo(file);
+            List<String[]> lineList = getData(file);
+            if (lineList == null || lineList.size() == 0) {
+                throw new StatusException("500", "没有导入的数据");
+            }
+            List<PaperAnswerDomain> ret = new ArrayList<PaperAnswerDomain>();
+            for (int i = 0; i < lineList.size(); i++) {
+                String[] line = lineList.get(i);
+                PaperAnswerDomain domain = new PaperAnswerDomain();
+                domain.setNumber(getNumber(trimAndNullIfBlank(line[0])));
+                domain.setName(trimAndNullIfBlank(line[1]));
+                domain.setSubNumber(getNumber(trimAndNullIfBlank(line[2])));
+                domain.setChildNumber(getNumber(trimAndNullIfBlank(line[3])));
+                domain.setSubType(trimAndNullIfBlank(line[4]));
+                domain.setAnswer(trimAndNullIfBlank(line[5]));
+                ret.add(domain);
+            }
+            if (ret == null || ret.size() == 0) {
+                throw new StatusException("500", "没有导入的数据");
+            }
+            diposeAnswer(paper, ret);
+        } catch (StatusException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new StatusException("500", "导入答案失败:" + e.getMessage(), e);
+        } finally {
+            FileUtil.deleteFile(file.getAbsolutePath());
+        }
+    }
+
+    private List<String[]> getData(File file) {
+        XSSFWorkbook wb = null;
+        try {
+            try {
+                wb = new XSSFWorkbook(file);
+            } catch (Exception e) {
+                throw new StatusException("500", "文件类型错误");
+            }
+            List<String[]> outerList = new ArrayList<String[]>();
+            XSSFSheet sheet = wb.getSheetAt(0);
+            for (int i = 1; i <= sheet.getLastRowNum(); i++) {
+                String[] innerList = new String[6];
+                XSSFRow row = sheet.getRow(i);
+                for (int j = 0; j < 6; j++) {
+                    XSSFCell cell = row.getCell(j);
+                    if (cell != null) {
+                        String cellinfo = cell.getStringCellValue();
+                        innerList[j] = cellinfo;
+                    } else {
+                        innerList[j] = "";
+                    }
+                }
+                if (!isEmpty(innerList)) {
+                    if (StringUtils.isEmpty(innerList[0])) {
+                        throw new StatusException("500", "文件类型错误" + (i + 1) + "行大题号不能为空");
+                    }
+                    if (StringUtils.isEmpty(innerList[2])) {
+                        throw new StatusException("500", "文件类型错误" + (i + 1) + "行小题号不能为空");
+                    }
+                    outerList.add(innerList);
+                }
+            }
+            return outerList;
+        } finally {
+            if (wb != null) {
+                try {
+                    wb.close();
+                } catch (IOException e) {
+                    LOG.debug("wb.close() error " + e);
+                }
+            }
+        }
+
+    }
+
+    private boolean isEmpty(String[] ss) {
+        for (String s : ss) {
+            if (StringUtils.isNotEmpty(s)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private void diposeAnswer(Paper paper, List<PaperAnswerDomain> domains) {
+        Map<String, PaperAnswerDomain> answerMap = new LinkedHashMap<String, PaperAnswerDomain>();
+        for (PaperAnswerDomain domain : domains) {
+            String key = null;
+            if (domain.getChildNumber() != null) {
+                key = domain.getSubNumber() + "-" + domain.getChildNumber();
+            } else {
+                key = domain.getSubNumber().toString();
+            }
+            if (answerMap.get(key) == null) {
+                answerMap.put(key, domain);
+            } else {
+                throw new StatusException("500", "导入数据中第" + domain.getSubNumber() + "小题"
+                        + (domain.getChildNumber() != null ? "第" + domain.getChildNumber() + "子题" : "") + "重复");
+            }
+        }
+
+        Map<String, Question> quesMap = new LinkedHashMap<String, Question>();
+        List<PaperDetailUnit> paperDetailUnits = paperDetailUnitRepo.findByPaperIdOrderByNumber(paper.getId());
+        for (PaperDetailUnit unit : paperDetailUnits) {
+            Question qu = unit.getQuestion();
+            if (QuesStructType.NESTED_ANSWER_QUESTION.equals(qu.getQuestionType())) {
+                for (int i = 0; i < unit.getQuestion().getSubQuestions().size(); i++) {
+                    quesMap.put(unit.getNumber() + "-" + (i + 1), unit.getQuestion().getSubQuestions().get(i));
+                }
+            } else {
+                quesMap.put(unit.getNumber().toString(), qu);
+            }
+        }
+
+        Set<String> saveQuestion = new HashSet<String>();
+        for (String key : answerMap.keySet()) {
+            PaperAnswerDomain domain = answerMap.get(key);
+            Question qu = quesMap.get(key);
+            if (qu == null) {
+                answerFomatErr(domain.getSubNumber(), domain.getChildNumber(), "试题信息不存在");
+            }
+            saveQuestion.add(domain.getSubNumber().toString());
+        }
+
+        Set<String> updateQuesIds = new HashSet<String>();
+        List<Question> ques = new ArrayList<Question>();
+        for (PaperDetailUnit unit : paperDetailUnits) {
+            Question qu = unit.getQuestion();
+            if (saveQuestion.contains(unit.getNumber().toString())) {
+                if (QuesStructType.NESTED_ANSWER_QUESTION.equals(qu.getQuestionType())) {
+                    for (int i = 0; i < unit.getQuestion().getSubQuestions().size(); i++) {
+                        if (answerMap.get(unit.getNumber() + "-" + (i + 1)) != null) {
+                            checkAndSetAnswer(unit.getQuestion().getSubQuestions().get(i),
+                                    answerMap.get(unit.getNumber() + "-" + (i + 1)).getAnswer(), unit.getNumber(),
+                                    i + 1);
+                            updateQuesIds.add(qu.getId());
+                        }
+                    }
+                } else {
+                    if (answerMap.get(unit.getNumber().toString()) != null) {
+                        checkAndSetAnswer(qu, answerMap.get(unit.getNumber().toString()).getAnswer(), unit.getNumber(),
+                                null);
+                        updateQuesIds.add(qu.getId());
+                    }
+                }
+            }
+            ques.add(qu);
+        }
+        quesRepo.saveAll(ques);
+        // 清除缓存
+        for (String qid : updateQuesIds) {
+            paperDetailUnitService.clearQuestionCache(qid);
+        }
+    }
+
+    private void checkAndSetAnswer(Question question, String answer, Integer subNum, Integer childNum) {
+        String fomatErrMsg = "答案格式错误";
+        if (answer != null) {
+            answer = answer.trim();
+        }
+        if (StringUtils.isBlank(answer)) {
+            return;
+        }
+        if (QuesStructType.SINGLE_ANSWER_QUESTION.equals(question.getQuestionType())
+                || QuesStructType.MULTIPLE_ANSWER_QUESTION.equals(question.getQuestionType())) {
+            answer = answer.replaceAll("\\s*", "");
+            if (QuesStructType.SINGLE_ANSWER_QUESTION.equals(question.getQuestionType())) {
+                if (answer.length() > 1) {
+                    answerFomatErr(subNum, childNum, fomatErrMsg);
+                }
+            }
+            String[] pAnswerArray;
+            if (answer.indexOf(",") != -1) {
+                pAnswerArray = answer.split(",");
+            } else {
+                pAnswerArray = answer.split("");
+            }
+            List<QuesOption> options = question.getQuesOptions();
+            List<String> optionNumList = new ArrayList<>();
+            for (QuesOption quesOption : options) {
+                Integer numInteger = Integer.parseInt(quesOption.getNumber());
+                char word = (char) (numInteger + 64);
+                optionNumList.add(word + "");
+            }
+            for (String option : pAnswerArray) {
+                String pattern = "[A-Z]";
+                if (!Pattern.matches(pattern, option)) {
+                    answerFomatErr(subNum, childNum, fomatErrMsg);
+                }
+                if (!optionNumList.contains(option)) {
+                    answerFomatErr(subNum, childNum, "答案选项不存在");
+                }
+            }
+            if (pAnswerArray.length > 1) {
+                question.setQuesAnswer(StringUtils.join(pAnswerArray, ","));
+            } else {
+                question.setQuesAnswer(answer);
+            }
+            processSelectOption(question);
+        } else if (QuesStructType.BOOL_ANSWER_QUESTION.equals(question.getQuestionType())) {
+            if (!answer.equals("正确") && !answer.equals("错误")) {
+                answerFomatErr(subNum, childNum, fomatErrMsg);
+            }
+            question.setQuesAnswer(answer);
+        } else if (QuesStructType.FILL_BLANK_QUESTION.equals(question.getQuestionType())) {
+            String body = question.getQuesBody();
+            Document bodyDoc = Jsoup.parse(body);
+            String bodyText = bodyDoc.body().html();
+            Document answerDoc = null;
+            try {
+                answerDoc = Jsoup.parse(answer);
+            } catch (Exception e) {
+                answerFomatErr(subNum, childNum, "答案格式html解析错误");
+            }
+            if (answerDoc.body().childrenSize() != 0) {
+                String answerText = answerDoc.body().html();
+                if (StringUtils.isNotBlank(answerText)) {
+                    if (getSubStringCount(bodyText, "###") != answerText.split("##").length) {
+                        answerFomatErr(subNum, childNum, "题干空格数量和答案数量不一致");
+                    }
+                }
+            }
+            question.setQuesAnswer(answer);
+        } else if (QuesStructType.TEXT_ANSWER_QUESTION.equals(question.getQuestionType())) {
+            try {
+                Jsoup.parse(answer);
+            } catch (Exception e) {
+                answerFomatErr(subNum, childNum, "答案格式html解析错误");
+            }
+            question.setQuesAnswer(answer);
+        }
+
+    }
+
+    private int getSubStringCount(String src, String find) {
+        int o = 0;
+        int index = -1;
+        while ((index = src.indexOf(find, index)) > -1) {
+            ++index;
+            ++o;
+        }
+        return o;
+    }
+
+    private void processSelectOption(Question question) {
+        String answer = question.getQuesAnswer();
+        if (StringUtils.isNotBlank(answer)) {
+            String[] answerArray = answer.split(",");
+            for (int i = 0; i < question.getQuesOptions().size(); i++) {
+                QuesOption quesOption = question.getQuesOptions().get(i);
+                char number = (char) (Integer.parseInt(quesOption.getNumber()) + 64);
+                if (ArrayUtils.contains(answerArray, String.valueOf(number))) {
+                    quesOption.setIsCorrect((short) 1);
+                } else {
+                    quesOption.setIsCorrect((short) 0);
+                }
+            }
+        }
+    }
+
+    private void answerFomatErr(Integer subNum, Integer childNum, String msg) {
+        throw new StatusException("500",
+                "导入数据中第" + subNum + "小题" + (childNum != null ? "第" + childNum + "子题" : "") + msg);
+    }
+
+    private String trimAndNullIfBlank(String s) {
+        if (StringUtils.isBlank(s)) {
+            return null;
+        }
+        return s.trim();
+    }
+
+    private Integer getNumber(String s) {
+        if (StringUtils.isBlank(s)) {
+            return null;
+        }
+        return Integer.valueOf(s.trim());
+    }
+
+    @Override
+    public List<String> findPaperId(Long fromRootOrgId) {
+        Query query = new Query();
+        query.addCriteria(Criteria.where("orgId").is(fromRootOrgId.toString()));
+        query.addCriteria(Criteria.where("paperType").is(PaperType.IMPORT));
+        List<PaperId> paperList = this.mongoTemplate.find(query, PaperId.class, "paper");
+        if (CollectionUtils.isEmpty(paperList)) {
+            return null;
+        }
+        List<String> ids = paperList.stream().map(e -> e.getId()).collect(Collectors.toList());
+        return ids;
+    }
 
 }

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

@@ -19,6 +19,7 @@ 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;
@@ -40,7 +41,8 @@ public class QuestionAudioServiceImpl implements QuestionAudioService {
 
     @Override
     public void saveQuestionAudio(QuestionAudio questionAudio, User user) {
-        QuestionAudio existQuestionAudio = this.findByQuestionIdAndFileName(questionAudio.getQuestionId(), questionAudio.getFileName());
+        QuestionAudio existQuestionAudio = this.findByQuestionIdAndFileName(questionAudio.getQuestionId(),
+                questionAudio.getFileName());
         if (existQuestionAudio != null) {
             questionAudio.setId(existQuestionAudio.getId());
 
@@ -82,7 +84,7 @@ public class QuestionAudioServiceImpl implements QuestionAudioService {
                 return -1;
             });
 
-            //取最新的一个
+            // 取最新的一个
             return audioList.get(0);
         }
 
@@ -127,10 +129,10 @@ public class QuestionAudioServiceImpl implements QuestionAudioService {
     @Override
     public void sortAudio(Question question) {
         if (question.getHasAudio() != null && question.getHasAudio()) {
-            //音频顺序改变后,更新bodyHtml
+            // 音频顺序改变后,更新bodyHtml
             String newQusBody = getFileNames(question.getQuesBody(), question);
             question.setQuesBody(newQusBody);
-            //跟新选项中的optionsHtml
+            // 跟新选项中的optionsHtml
             if (question.getQuesOptions() != null && question.getQuesOptions().size() > 0) {
                 for (QuesOption option : question.getQuesOptions()) {
                     String newOptionBody = getFileNames(option.getOptionBody(), question);
@@ -148,6 +150,9 @@ public class QuestionAudioServiceImpl implements QuestionAudioService {
         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));
@@ -165,16 +170,19 @@ public class QuestionAudioServiceImpl implements QuestionAudioService {
                 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);
         }
@@ -183,7 +191,7 @@ public class QuestionAudioServiceImpl implements QuestionAudioService {
 
     @Override
     public void deleteAudio(List<Question> questions) {
-        //筛选有音频的试题
+        // 筛选有音频的试题
         List<String> ids = new ArrayList<String>();
         for (Question question : questions) {
             if (question.getHasAudio() != null && question.getHasAudio()) {
@@ -200,12 +208,12 @@ public class QuestionAudioServiceImpl implements QuestionAudioService {
         }
         questionAudioRepo.deleteAll(questionAudios);
     }
-    
+
     @Override
     public void deleteAudioByQuestionId(List<String> questionIds) {
-    	if(CollectionUtils.isEmpty(questionIds)) {
-    		return;
-    	}
+        if (CollectionUtils.isEmpty(questionIds)) {
+            return;
+        }
         List<QuestionAudio> questionAudios = questionAudioRepo.findByQuestionIdIn(questionIds);
         Iterator<QuestionAudio> audioIterator = questionAudios.iterator();
         while (audioIterator.hasNext()) {
@@ -218,4 +226,3 @@ public class QuestionAudioServiceImpl implements QuestionAudioService {
     }
 
 }
-

+ 34 - 8
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/themispaper/ThemisQuestion.java

@@ -16,20 +16,30 @@ import java.util.Map;
 public class ThemisQuestion {
 
     private String id;
+
     /**
      * 小题号或套题内子题序号
      */
     private Integer number;
 
     private Double score;// 小题分数
+
     /**
      * 1-单选,2-多选,3-判断,4-填空,5-问答,6-套题
      */
     private Long structType;
+
+    // 1-单选,2-多选,3-判断,4-填空,5-问答
+    // 100-阅读理解,101-完形填空,102-段落匹配,103-选词填空
+    // 110-听力理解(主题干带音频的套题结构,子题题型不限,允许子题选择题无题干)
+    // 200-WPS操作题
+    private Long type;
+
     /**
      * 是否客观题
      */
     private Boolean objective;
+
     /**
      * 子题
      */
@@ -47,7 +57,6 @@ public class ThemisQuestion {
 
     private Map<String, Object> param;
 
-
     public ThemisQuestion() {
     }
 
@@ -56,9 +65,14 @@ public class ThemisQuestion {
         this.number = paperDetailUnit.getNumber();
         this.score = paperDetailUnit.getScore();
         this.structType = paperDetailUnit.getQuestionType().getId();
-        if (paperDetailUnit.getQuestionType() == QuesStructType.SINGLE_ANSWER_QUESTION ||
-                paperDetailUnit.getQuestionType() == QuesStructType.MULTIPLE_ANSWER_QUESTION ||
-                paperDetailUnit.getQuestionType() == QuesStructType.BOOL_ANSWER_QUESTION) {
+        if (this.structType == 6) {
+            this.type = 100L;
+        } else {
+            this.type = this.structType;
+        }
+        if (paperDetailUnit.getQuestionType() == QuesStructType.SINGLE_ANSWER_QUESTION
+                || paperDetailUnit.getQuestionType() == QuesStructType.MULTIPLE_ANSWER_QUESTION
+                || paperDetailUnit.getQuestionType() == QuesStructType.BOOL_ANSWER_QUESTION) {
             this.objective = true;
         } else {
             this.objective = false;
@@ -69,9 +83,14 @@ public class ThemisQuestion {
         this.id = question.getId();
         this.score = question.getScore();
         this.structType = question.getQuestionType().getId();
-        if (question.getQuestionType() == QuesStructType.SINGLE_ANSWER_QUESTION ||
-                question.getQuestionType() == QuesStructType.MULTIPLE_ANSWER_QUESTION ||
-                question.getQuestionType() == QuesStructType.BOOL_ANSWER_QUESTION) {
+        if (this.structType == 6) {
+            this.type = 100L;
+        } else {
+            this.type = this.structType;
+        }
+        if (question.getQuestionType() == QuesStructType.SINGLE_ANSWER_QUESTION
+                || question.getQuestionType() == QuesStructType.MULTIPLE_ANSWER_QUESTION
+                || question.getQuestionType() == QuesStructType.BOOL_ANSWER_QUESTION) {
             this.objective = true;
         } else {
             this.objective = false;
@@ -150,5 +169,12 @@ public class ThemisQuestion {
         this.param = param;
     }
 
-}
+    public Long getType() {
+        return type;
+    }
 
+    public void setType(Long type) {
+        this.type = type;
+    }
+
+}

+ 185 - 137
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/util/ExportPaperUtil.java

@@ -9,6 +9,7 @@ import java.io.StringWriter;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Base64;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -16,8 +17,9 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import javax.imageio.ImageIO;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
 
-import cn.com.qmth.examcloud.support.util.FileUtil;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang.StringEscapeUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -45,17 +47,19 @@ import cn.com.qmth.examcloud.core.questions.dao.entity.Question;
 import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperDetailExp;
 import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperDetailUnitExp;
 import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperExp;
+import cn.com.qmth.examcloud.support.util.FileUtil;
 import freemarker.template.Configuration;
 import freemarker.template.Template;
 import sun.misc.BASE64Decoder;
 
+@SuppressWarnings("restriction")
 public class ExportPaperUtil {
 
     private static final Logger log = LoggerFactory.getLogger(ExportPaperUtil.class);
-    
-    private static final String docxBasePath=FileDisposeUtil.getDocxBasePath();
-    
-    private static final int docImageSzie=12700;
+
+    private static final String docxBasePath = FileDisposeUtil.getDocxBasePath();
+
+    private static final int docImageSzie = 12700;
 
     private static final String DOCX_SUFFIX = ".docx";
 
@@ -68,7 +72,7 @@ public class ExportPaperUtil {
     public static final String ELEMENT_TYPE_TEXT = "text";
 
     public static final String ELEMENT_TYPE_IMG = "image";
-    
+
     public static final String ELEMENT_TYPE_DOCTAG = "doctag";
 
     private static final String ENCODING = "UTF-8";
@@ -76,7 +80,7 @@ public class ExportPaperUtil {
     private static Configuration config;
 
     private static Template docSection;
-    
+
     private static Template examReamarkDocument;
 
     private static Template questionSection;
@@ -106,15 +110,16 @@ public class ExportPaperUtil {
             document = config.getTemplate("document.ftl", ENCODING);
             documentRel = config.getTemplate("document_rel.ftl", ENCODING);
             paperQuesOps = config.getTemplate("question_options.ftl", ENCODING);
-            docSection=config.getTemplate("doc_section.ftl", ENCODING);
-            examReamarkDocument=config.getTemplate("exam_reamark_document.ftl", ENCODING);
+            docSection = config.getTemplate("doc_section.ftl", ENCODING);
+            examReamarkDocument = config.getTemplate("exam_reamark_document.ftl", ENCODING);
         } catch (IOException e) {
             log.error(e.getMessage(), e);
         }
     }
-    //考试说明word文件
-    public static File createExamRemarkDocFile(File directory,String fileName,String html) throws IOException {
-     // doc固定源文件目录
+
+    // 考试说明word文件
+    public static File createExamRemarkDocFile(File directory, String fileName, String html) throws IOException {
+        // doc固定源文件目录
         File docxDir = new File(docxBasePath);
         // 将要生成的doc源文件目录
         File docxTargetDir = new File(directory.getAbsolutePath() + "/docx/");
@@ -134,9 +139,10 @@ public class ExportPaperUtil {
         FileUtils.deleteDirectory(docxTargetDir);
         return docfile;
     }
+
     private static void disposeExamRemark(File docxTargetDir, String html) throws IOException {
         ExportTempDataDto dto = new ExportTempDataDto();
-        List<JSection> slist=null;
+        List<JSection> slist = null;
         if (StringUtils.isNotBlank(html)) {
             slist = getSections(html);
             if (slist != null && slist.size() > 0) {
@@ -152,6 +158,7 @@ public class ExportPaperUtil {
         // image file
         writeImage(docxTargetDir, dto);
     }
+
     private static void writeExamRemarkDocument(File docxTargetDir, List<JSection> slist) throws IOException {
         StringWriter result = null;
         try {
@@ -165,6 +172,7 @@ public class ExportPaperUtil {
         File file = new File(docxTargetDir.getAbsolutePath() + "/word/document.xml");
         FileUtils.writeStringToFile(file, result.toString(), "utf-8");
     }
+
     // 考试试卷
     public static File createPaperDocFile(Long rootOrgId, PaperExp paperExp, File directory, String paperfileName,
             ExportTemplateType templateType) throws Exception {
@@ -204,7 +212,7 @@ public class ExportPaperUtil {
                 }
             }
         }
-        
+
         // header
         writePaperHeader(docxTargetDir, paperExp.getCourseName(), docxTemplate);
         // content-type
@@ -216,11 +224,11 @@ public class ExportPaperUtil {
         // image file
         writeImage(docxTargetDir, dto);
     }
-    
+
     private static void writePaperHeader(File docxTargetDir, String courseName, DocxTemplateBean docxTemplate)
             throws IOException {
-        Template head=docxTemplate.getHeader();
-        if(head==null) {
+        Template head = docxTemplate.getHeader();
+        if (head == null) {
             return;
         }
         Map<String, Object> map = new HashMap<String, Object>();
@@ -295,7 +303,7 @@ public class ExportPaperUtil {
     }
 
     // 原始试卷
-    public static File createOriginPaperDocFile(PaperExp paperExp, File directory) throws IOException{
+    public static File createOriginPaperDocFile(PaperExp paperExp, File directory) throws IOException {
         // doc固定源文件目录
         File docxDir = new File(docxBasePath);
         // 将要生成的doc源文件目录
@@ -319,7 +327,6 @@ public class ExportPaperUtil {
 
     }
 
-
     private static List<JSection> getSections(String html) {
         return getSections(html, false);
     }
@@ -349,13 +356,13 @@ public class ExportPaperUtil {
         return ss;
 
     }
-    
-    private static List<JSection> getEmptySections(){
-    	List<JSection> ss = new ArrayList<JSection>();
-    	JSection s = new JSection();
+
+    private static List<JSection> getEmptySections() {
+        List<JSection> ss = new ArrayList<JSection>();
+        JSection s = new JSection();
         List<SectionElement> ses = new ArrayList<SectionElement>();
         s.setElements(ses);
-        SectionElement se=new SectionElement();
+        SectionElement se = new SectionElement();
         se.setType(ELEMENT_TYPE_TEXT);
         se.setValue("");
         ses.add(se);
@@ -370,18 +377,19 @@ public class ExportPaperUtil {
             }
         } else {
             if (ce instanceof TextNode) {
-            	SectionElement se = new SectionElement();
+                SectionElement se = new SectionElement();
                 TextNode tn = (TextNode) ce;
                 se.setType(ELEMENT_TYPE_TEXT);
                 String text = tn.text();
                 if (diposeFillBlank) {
                     text = text.replaceAll("###", "______").replaceAll("##", "______");
                 }
-                text = text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\u0000", " ");
+                text = text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;")
+                        .replaceAll("\u0000", " ");
                 se.setValue(text);
                 ses.add(se);
             } else if (ce instanceof Element) {
-            	SectionElement se = new SectionElement();
+                SectionElement se = new SectionElement();
                 if ("img".equals(ce.nodeName())) {
                     se.setType(ELEMENT_TYPE_IMG);
                     se.setValue(ce.attr("src"));
@@ -403,29 +411,29 @@ public class ExportPaperUtil {
         int n = 0;
         String str = ce.attr("width");
         if (StringUtils.isNotBlank(str)) {
-        	String sizeStr = str.replace("px", "");
-        	if (StringUtils.isNotBlank(sizeStr)) {
-        		try {
-	        		return Integer.valueOf(sizeStr.trim()) * docImageSzie;
-	        	} catch (NumberFormatException e) {
-					log.warn("image width value is invalid");
-					return 0;
-				}
-        	}
+            String sizeStr = str.replace("px", "");
+            if (StringUtils.isNotBlank(sizeStr)) {
+                try {
+                    return Integer.valueOf(sizeStr.trim()) * docImageSzie;
+                } catch (NumberFormatException e) {
+                    log.warn("image width value is invalid");
+                    return 0;
+                }
+            }
         }
         String style = ce.attr("style");
         if (StringUtils.isNotBlank(style)) {
             Matcher m = widthRex.matcher(style);
             if (m.find()) {
-            	String size=m.group(1).trim();
-            	if(StringUtils.isNotBlank(size)) {
-            		try {
-	            		return Integer.valueOf(size) * docImageSzie;
-	            	} catch (NumberFormatException e) {
-						log.warn("image style width value is invalid");
-						return 0;
-					}
-            	}
+                String size = m.group(1).trim();
+                if (StringUtils.isNotBlank(size)) {
+                    try {
+                        return Integer.valueOf(size) * docImageSzie;
+                    } catch (NumberFormatException e) {
+                        log.warn("image style width value is invalid");
+                        return 0;
+                    }
+                }
             }
         }
         return n;
@@ -435,29 +443,29 @@ public class ExportPaperUtil {
         int n = 0;
         String str = ce.attr("height");
         if (StringUtils.isNotBlank(str)) {
-        	String sizeStr = str.replace("px", "");
-        	if (StringUtils.isNotBlank(sizeStr)) {
-        		try {
-					return Integer.valueOf(sizeStr.trim()) * docImageSzie;
-				} catch (NumberFormatException e) {
-					log.error("image height value is invalid");
-					return 0;
-				}
-        	}
+            String sizeStr = str.replace("px", "");
+            if (StringUtils.isNotBlank(sizeStr)) {
+                try {
+                    return Integer.valueOf(sizeStr.trim()) * docImageSzie;
+                } catch (NumberFormatException e) {
+                    log.error("image height value is invalid");
+                    return 0;
+                }
+            }
         }
         String style = ce.attr("style");
         if (StringUtils.isNotBlank(style)) {
             Matcher m = heightRex.matcher(style);
             if (m.find()) {
-            	String size=m.group(1).trim();
-            	if(StringUtils.isNotBlank(size)) {
-            		try {
-	            		return Integer.valueOf(size) * docImageSzie;
-	            	} catch (NumberFormatException e) {
-						log.error("image style height value is invalid");
-						return 0;
-					}
-            	}
+                String size = m.group(1).trim();
+                if (StringUtils.isNotBlank(size)) {
+                    try {
+                        return Integer.valueOf(size) * docImageSzie;
+                    } catch (NumberFormatException e) {
+                        log.error("image style height value is invalid");
+                        return 0;
+                    }
+                }
             }
         }
         return n;
@@ -492,13 +500,13 @@ public class ExportPaperUtil {
                     + se.getParam().getType());
             String src = se.getValue();
             if (src.contains("data:image")) {
-                //base64图片
-            	src = src.substring(src.indexOf(",") + 1);
+                // base64图片
+                src = src.substring(src.indexOf(",") + 1);
                 BASE64Decoder decoder = new BASE64Decoder();
                 byte[] bytes = decoder.decodeBuffer(src);
                 FileUtils.writeByteArrayToFile(file, bytes);
-            }else {
-                //网络图片URL
+            } else {
+                // 网络图片URL
                 FileUtil.saveUrlAs(src, file);
             }
         }
@@ -546,12 +554,12 @@ public class ExportPaperUtil {
 
     private static void disposeQuestion(Question qes, ExportTempDataDto dto) {
         if (qes != null) {
-            //处理题干
-            List<JSection> slist1 = getSections(qes.getQuesBody(),false);
-            if (slist1 == null||slist1.size()==0) {
-                slist1=new ArrayList<JSection>();
-                JSection sec=new JSection();
-                List<SectionElement> ses=new ArrayList<SectionElement>();
+            // 处理题干
+            List<JSection> slist1 = getSections(qes.getQuesBody(), false);
+            if (slist1 == null || slist1.size() == 0) {
+                slist1 = new ArrayList<JSection>();
+                JSection sec = new JSection();
+                List<SectionElement> ses = new ArrayList<SectionElement>();
                 sec.setElements(ses);
                 slist1.add(sec);
             }
@@ -565,7 +573,7 @@ public class ExportPaperUtil {
             htmlToDoc(slist1, dto);
             qes.setQuesBodyWord(getQuestionDoc(slist1));
 
-            //处理选项
+            // 处理选项
             if (qes.getQuesOptions() != null && qes.getQuesOptions().size() > 0) {
                 int index = 0;
                 for (QuesOption qo : qes.getQuesOptions()) {
@@ -582,13 +590,13 @@ public class ExportPaperUtil {
 
                 }
             }
-            
-            //处理答案
+
+            // 处理答案
             List<JSection> slist3 = getSections(qes.getQuesAnswer());
-            if (slist3 == null||slist3.size()==0) {
-                slist3=new ArrayList<JSection>();
-                JSection sec=new JSection();
-                List<SectionElement> ses=new ArrayList<SectionElement>();
+            if (slist3 == null || slist3.size() == 0) {
+                slist3 = new ArrayList<JSection>();
+                JSection sec = new JSection();
+                List<SectionElement> ses = new ArrayList<SectionElement>();
                 sec.setElements(ses);
                 slist3.add(sec);
             }
@@ -615,19 +623,19 @@ public class ExportPaperUtil {
                 paperExp.setExamRemarkWord(getSectionDoc(slist));
             }
         }
-        if(paperExp.getExamRemarkWord()==null) {
+        if (paperExp.getExamRemarkWord() == null) {
             paperExp.setExamRemarkWord("");
         }
     }
 
     private static void disposePaperQuestion(Question qes, ExportTempDataDto dto) {
         if (qes != null) {
-            //处理题干
-            List<JSection> slist1 = getSections(qes.getQuesBody(),true);
-            if (slist1 == null||slist1.size()==0) {
-                slist1=new ArrayList<JSection>();
-                JSection sec=new JSection();
-                List<SectionElement> ses=new ArrayList<SectionElement>();
+            // 处理题干
+            List<JSection> slist1 = getSections(qes.getQuesBody(), true);
+            if (slist1 == null || slist1.size() == 0) {
+                slist1 = new ArrayList<JSection>();
+                JSection sec = new JSection();
+                List<SectionElement> ses = new ArrayList<SectionElement>();
                 sec.setElements(ses);
                 slist1.add(sec);
             }
@@ -641,7 +649,7 @@ public class ExportPaperUtil {
             htmlToDoc(slist1, dto);
             qes.setQuesBodyWord(getQuestionDoc(slist1));
 
-            //处理选项
+            // 处理选项
             if (qes.getQuesOptions() != null && qes.getQuesOptions().size() > 0) {
                 int index = 0;
                 JOptionDto joDto = new JOptionDto();
@@ -664,14 +672,14 @@ public class ExportPaperUtil {
                 disposeQuesOptions(joDto);// 处理选项列数
                 qes.setQuesOptionsWord(getPaperQuestionDoc(joDto.getOptions()));
             }
-            
-            //处理答案
+
+            // 处理答案
             if (qes.getSubQuestions() == null || qes.getSubQuestions().size() == 0) {// 套题不加答案及序号
                 List<JSection> slist3 = getSections(qes.getQuesAnswer());
-                if (slist3 == null||slist3.size()==0) {
-                    slist3=new ArrayList<JSection>();
-                    JSection sec=new JSection();
-                    List<SectionElement> ses=new ArrayList<SectionElement>();
+                if (slist3 == null || slist3.size() == 0) {
+                    slist3 = new ArrayList<JSection>();
+                    JSection sec = new JSection();
+                    List<SectionElement> ses = new ArrayList<SectionElement>();
                     sec.setElements(ses);
                     slist3.add(sec);
                 }
@@ -683,7 +691,6 @@ public class ExportPaperUtil {
                 htmlToDoc(slist3, dto);
                 qes.setQuesAnswerWord(getQuestionDoc(slist3));
             }
-            
 
             if (qes.getSubQuestions() != null && qes.getSubQuestions().size() > 0) {
                 for (Question sunqes : qes.getSubQuestions()) {
@@ -765,18 +772,20 @@ public class ExportPaperUtil {
             }
         }
     }
+
     private static String getImageType(String src) {
-    	if(src.contains("data:image")) {
-    		return src.substring(11, src.indexOf(";"));
-    	}else {
-    		try {
-				URL url=new URL(src);
-				return url.getPath().substring(url.getPath().lastIndexOf(".")+1);
-			} catch (MalformedURLException e) {
-				throw new StatusException("1000", "图片链接格式错误:"+src);
-			}
-    	}
+        if (src.contains("data:image")) {
+            return src.substring(11, src.indexOf(";"));
+        } else {
+            try {
+                URL url = new URL(src);
+                return url.getPath().substring(url.getPath().lastIndexOf(".") + 1);
+            } catch (MalformedURLException e) {
+                throw new StatusException("1000", "图片链接格式错误:" + src);
+            }
+        }
     }
+
     private static String getSectionDoc(List<JSection> sections) {
         Map<String, Object> map = new HashMap<String, Object>();
         map.put("sections", sections);
@@ -815,40 +824,79 @@ public class ExportPaperUtil {
             throw new ExamCloudRuntimeException(e);
         }
     }
-    
-    
-    private static void setImageSize(SectionElement imageEle,Node ce) {
-    	int width=getWidth(ce);
-    	int height=getHeight(ce);
-    	if(width<100||height<100) {
-    		String base64=imageEle.getValue();
-    		if (base64.contains("data:image")) {
-                base64 = base64.substring(base64.indexOf(",") + 1);
-            }
-            BASE64Decoder decoder = new BASE64Decoder();
-    		
-    		InputStream is = null;
-            try {
-            	byte[] bytes = decoder.decodeBuffer(base64);
-                is = new ByteArrayInputStream(bytes);
-                BufferedImage image = ImageIO.read(is);
-                width=image.getWidth()* docImageSzie;
-                height=image.getHeight()* docImageSzie;
-            }catch (IOException e) {
-            	log.error(e.getMessage(), e);
-            } finally {
-                if (is != null) {
+
+    private static void setImageSize(SectionElement imageEle, Node ce) {
+        int width = getWidth(ce);
+        int height = getHeight(ce);
+        if (width < 100 || height < 100) {
+            String base64 = imageEle.getValue();
+            if (base64.contains("data:image")) {
+                String[] ss = base64.split(",");
+                if (ss[0].toLowerCase().contains("image/svg")) {
+                    try {
+                        // Step 1: Base64解码
+                        byte[] decodedBytes = Base64.getDecoder().decode(ss[1]);
+                        InputStream inputStream = new ByteArrayInputStream(decodedBytes);
+
+                        // Step 2: 解析SVG数据
+                        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+                        DocumentBuilder builder = factory.newDocumentBuilder();
+                        org.w3c.dom.Document document = builder.parse(inputStream);
+                        document.getDocumentElement().normalize();
+
+                        // Step 3: 提取宽高信息
+                        org.w3c.dom.Element svgElement = document.getDocumentElement();
+                        String widthStr = svgElement.getAttribute("width");
+                        String heightStr = svgElement.getAttribute("height");
+
+                        if (widthStr.isEmpty() || heightStr.isEmpty()) {
+                            // 如果没有宽高,尝试从viewBox中获取
+                            String viewBox = svgElement.getAttribute("viewBox");
+                            if (!viewBox.isEmpty()) {
+                                String[] viewBoxValues = viewBox.split(" ");
+                                if (viewBoxValues.length == 4) {
+                                    widthStr = viewBoxValues[2];
+                                    heightStr = viewBoxValues[3];
+                                }
+                            }
+                        }
+
+                        double w = Double.valueOf(widthStr.replace("ex", ""));
+                        double h = Double.valueOf(heightStr.replace("ex", ""));
+                        // ex转px参照16px的字体大小,x视为0.6倍
+                        width = (int) (w * 0.6 * 16) * docImageSzie;
+                        height = (int) (h * 0.6 * 16) * docImageSzie;
+
+                    } catch (Exception e) {
+                        throw new StatusException("500", e.getMessage(), e);
+                    }
+                } else {
+                    base64 = ss[1];
+                    BASE64Decoder decoder = new BASE64Decoder();
+
+                    InputStream is = null;
                     try {
-						is.close();
-					} catch (IOException e) {
-						log.error(e.getMessage(), e);
-					}
+                        byte[] bytes = decoder.decodeBuffer(base64);
+                        is = new ByteArrayInputStream(bytes);
+                        BufferedImage image = ImageIO.read(is);
+                        width = image.getWidth() * docImageSzie;
+                        height = image.getHeight() * docImageSzie;
+                    } catch (IOException e) {
+                        log.error(e.getMessage(), e);
+                    } finally {
+                        if (is != null) {
+                            try {
+                                is.close();
+                            } catch (IOException e) {
+                            }
+                        }
+                    }
                 }
             }
-    	}
-    	imageEle.getParam().setHeight(height);
-    	imageEle.getParam().setWidth(width);
-		
-	}
+        }
+        imageEle.getParam().setHeight(height);
+        imageEle.getParam().setWidth(width);
+
+    }
 
 }

+ 1 - 1
examcloud-core-questions-starter/src/main/resources/log4j2.xml

@@ -41,7 +41,7 @@
         <logger name="org.hibernate" level="WARN"/>
         <logger name="org.apache" level="WARN"/>
         <logger name="org.quartz" level="WARN"/>
-        <logger name="org.docx4j" level="WARN"/>
+        <logger name="org.docx4j" level="ERROR"/>
         <logger name="cn.afterturn" level="WARN"/>
         <logger name="com.netflix" level="WARN"/>
         <logger name="com.aliyun" level="WARN"/>

+ 9 - 1
pom.xml

@@ -19,5 +19,13 @@
         <module>examcloud-core-questions-api-provider</module>
         <module>examcloud-core-questions-starter</module>
     </modules>
-
+     <dependencyManagement>
+	        <dependencies>
+				<dependency>
+					<groupId>org.apache.tika</groupId>
+					<artifactId>tika-core</artifactId>
+					<version>1.18</version>
+				</dependency>
+			</dependencies>
+		</dependencyManagement>   
 </project>