Selaa lähdekoodia

小程序作答标记

xiatian 3 kuukautta sitten
vanhempi
commit
8aec97d0e3

+ 129 - 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;
@@ -42,6 +47,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.multipart.MultipartFile;
 
 import com.google.gson.Gson;
+import com.mongodb.client.result.UpdateResult;
 
 import cn.com.qmth.examcloud.api.commons.enums.AdminOperateType;
 import cn.com.qmth.examcloud.api.commons.enums.DataRuleType;
@@ -84,8 +90,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 +102,9 @@ public class PaperController extends ControllerSupport {
 
     private final static String BASE_PAGE = "base_page";
 
+    @Autowired
+    MongoTemplate mongoTemplate;
+
     @Autowired
     PaperService paperService;
 
@@ -120,23 +128,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 +175,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 +218,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 +270,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 +289,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 +328,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 +388,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 +405,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 +423,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 +455,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 +500,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 +598,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 +610,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 +627,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 +646,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 +693,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 +767,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 +814,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 +832,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 +850,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 +860,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 +869,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 +886,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 +895,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 +904,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 +929,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 +943,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 +961,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");
+    }
+
 }

+ 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;
+    }
 
 }

+ 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;
+    }
 
 }