Procházet zdrojové kódy

just format code styles

deason před 1 rokem
rodič
revize
7eebf35eca

+ 470 - 470
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/PaperStructService.java

@@ -18,7 +18,6 @@ import cn.com.qmth.examcloud.core.questions.dao.entity.dto.PaperDetailUnitStruct
 import cn.com.qmth.examcloud.core.questions.service.bean.dto.QuesNameDto;
 import cn.com.qmth.examcloud.support.CacheConstants;
 import cn.com.qmth.examcloud.web.redis.RedisClient;
-
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -41,474 +40,475 @@ import java.util.stream.Collectors;
 @Service
 public class PaperStructService {
 
-	private static int cacheTimeOut = 2 * 60 * 60;
-	@Autowired
-	private RandomPaperService randomPaperService;
-
-	@Autowired
-	private PaperStructRepo paperStructRepo;
-
-	@Autowired
-	private QuesTypeNameRepo quesTypeNameRepo;
-
-	@Autowired
-	private MongoTemplate mongoTemplate;
-
-	@Autowired
-	private CourseCloudService courseCloudService;
-
-	@Autowired
-	private RedisClient redisClient;
-
-	/**
-	 * 获取所有试卷结构(分页)
-	 *
-	 * @param searchInfo
-	 * @param curPage
-	 * @param pageSize
-	 * @return
-	 */
-	public Page<PaperStruct> getPaperStructs(PaperStructSearchInfo searchInfo, int curPage, int pageSize,
-			UserDataRule userDataRule) {
-		if (userDataRule.assertEmptyQueryResult()) {
-			return Page.empty();
-		}
-
-		Query query = new Query();
-		query.addCriteria(Criteria.where("orgId").is(searchInfo.getOrgId()));
-		if (userDataRule.assertNeedQueryRefIds()) {
-			Criteria c1 = Criteria.where("courseId").in(userDataRule.getRefIds());
-			Criteria c2 = Criteria.where("courseId").exists(false);
-			Criteria cr = new Criteria();
-			query.addCriteria(cr.orOperator(c1, c2));
-		}
-		query.addCriteria(Criteria.where("type").is(searchInfo.getType()));
-
-		// 判断试卷结构
-		if (PaperStructType.EXACT.name().equals(searchInfo.getType())) {
-			if (StringUtils.isNotBlank(searchInfo.getCourseNo())) {
-				if (!"ALL".equals(searchInfo.getCourseNo())) {
-					query.addCriteria(Criteria.where("courseNo").is(searchInfo.getCourseNo()));
-				}
-			} else {
-				// “公用”情况
-				query.addCriteria(Criteria.where("courseNo").is(""));
-			}
-		} else {
-			if (StringUtils.isNotBlank(searchInfo.getCourseNo())) {
-				query.addCriteria(Criteria.where("courseNo").is(searchInfo.getCourseNo()));
-			}
-		}
-
-		if (StringUtils.isNotBlank(searchInfo.getName())) {
-			String paperStructName = CommonUtils.escapeExprSpecialWord(searchInfo.getName());
-			query.addCriteria(Criteria.where("name").regex(".*?" + paperStructName + ".*"));
-		}
-
-		if (StringUtils.isNotBlank(searchInfo.getCreator())) {
-			String userName = CommonUtils.escapeExprSpecialWord(searchInfo.getCreator());
-			query.addCriteria(Criteria.where("creator").regex(".*?" + userName + ".*"));
-		}
-
-		long total = this.mongoTemplate.count(query, PaperStruct.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<PaperStruct> paperStructs = this.mongoTemplate.find(query, PaperStruct.class);
-		if (CollectionUtils.isEmpty(paperStructs)) {
-			return Page.empty();
-		}
-
-		Map<String, String> courseNameMaps = new HashMap<>();
-
-		for (PaperStruct paperStruct : paperStructs) {
-			if (StringUtils.isBlank(paperStruct.getCourseNo())) {
-				paperStruct.setCourseName("公用");
-			} else {
-				String courseName = courseNameMaps.get(paperStruct.getCourseNo());
-
-				if (StringUtils.isEmpty(courseName)) {
-					GetCourseReq req = new GetCourseReq();
-					req.setRootOrgId(Long.valueOf(paperStruct.getOrgId()));
-					req.setCode(paperStruct.getCourseNo());
-					GetCourseResp resp = courseCloudService.getCourse(req);
-					courseName = resp.getCourseBean().getName();
-					courseNameMaps.put(paperStruct.getCourseNo(), courseName);
-				}
-
-				paperStruct.setCourseName(courseName);
-			}
-		}
-
-		return new PageImpl<>(paperStructs, pageable, total);
-	}
-
-	/**
-	 * 获取所有试卷结构(分页)
-	 *
-	 * @param searchInfo
-	 * @return
-	 */
-	public List<PaperStruct> getPaperStructs(PaperStructSearchInfo searchInfo, UserDataRule ud) {
-		if (ud.assertEmptyQueryResult()) {
-			return new ArrayList<>();
-		}
-		Query query = new Query();
-		if (StringUtils.isNotBlank(searchInfo.getCourseNo())) {
-			query.addCriteria(Criteria.where("courseNo").in("", searchInfo.getCourseNo()));
-		}
-		query.addCriteria(Criteria.where("orgId").is(searchInfo.getOrgId()));
-		if (ud.assertNeedQueryRefIds()) {
-			Criteria c1 = Criteria.where("courseId").in(ud.getRefIds());
-			Criteria c2 = Criteria.where("courseId").exists(false);
-			Criteria cr = new Criteria();
-			cr.orOperator(c1, c2);
-		}
-		if (StringUtils.isNotBlank(searchInfo.getType())) {
-			query.addCriteria(Criteria.where("type").is(searchInfo.getType()));
-		}
-		query.with(Sort.by(Sort.Order.desc("createTime")));
-		List<PaperStruct> paperList = this.mongoTemplate.find(query, PaperStruct.class);
-		return paperList;
-	}
-
-	public void formatSearchInfo(PaperStructSearchInfo searchInfo) {
-		if (StringUtils.isEmpty(searchInfo.getName())) {
-			searchInfo.setName(null);
-		}
-		if (StringUtils.isEmpty(searchInfo.getCreator())) {
-			searchInfo.setCreator(null);
-		}
-		if (StringUtils.isEmpty(searchInfo.getCourseNo())) {
-			searchInfo.setCourseNo(null);
-		}
-	}
-
-	public void formatPaperStruct(PaperStruct paperStruct) {
-		paperStruct.setCreateTime(null);
-	}
-
-	/**
-	 * 保存试卷结构
-	 *
-	 * @param paperStruct
-	 * @return
-	 */
-	public PaperStruct save(PaperStruct paperStruct, User user) {
-		if (StringUtils.isNotBlank(paperStruct.getCourseNo())) {
-			GetCourseReq req = new GetCourseReq();
-			req.setRootOrgId(Long.valueOf(paperStruct.getOrgId()));
-			req.setCode(paperStruct.getCourseNo());
-			GetCourseResp resp = courseCloudService.getCourse(req);
-			if (resp.getCourseBean() == null) {
-				throw new StatusException("500", "课程不存在");
-			}
-			paperStruct.setCourseId(resp.getCourseBean().getId());
-		} else {
-			paperStruct.setCourseId(null);
-		}
-		if (StringUtils.isNotBlank(paperStruct.getId())) {
-			PaperStruct oldPaperStruct = Model.of(paperStructRepo.findById(paperStruct.getId()));
-			PaperStruct rps = null;
-			if (oldPaperStruct != null && !paperStruct.getName().equals(oldPaperStruct.getName())) {// 那么就是更新操作
-				rps = this.checkNameUnique(paperStruct.getName(), user.getRootOrgId().toString(),
-						oldPaperStruct.getType());
-			}
-			if (rps != null) {
-				return null;
-			}
-		}
-		List<PaperDetailStruct> paperDetailStructs = paperStruct.getPaperDetailStructs();
-		int number = 0;
-		// 新增精确试卷结构
-		if (paperStruct.getType().equals("EXACT")) {
-			for (PaperDetailStruct paperDetailStruct : paperDetailStructs) {
-				List<PaperDetailUnitStruct> oldStructs = paperDetailStruct.getPaperDetailUnitStructs();
-				if (oldStructs != null && oldStructs.size() > 0) {
-					oldStructs.clear();
-				}
-				List<PaperDetailUnitStruct> unitStructs = new ArrayList<>();
-				for (PaperDetailUnitStructDto unitStructDto : paperDetailStruct.getUnitStructs()) {
-					// 公开简单总数
-					for (int i = 0; i < unitStructDto.getPublicSimple(); i++) {
-						++number;
-						PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct();
-						unitStruct.setDifficulty("易");
-						unitStruct.setPublicity(true);
-						unitStruct.setId(String.valueOf(number));
-						unitStruct.setNumber(number);
-						unitStruct.setScore(unitStructDto.getScore());
-						unitStruct.setQuestionType(unitStructDto.getQuestionType());
-						unitStruct.setQuesNames(unitStructDto.getQuesNames());
-						unitStruct.setPropertyGroup(buildGroup(unitStruct));
-						unitStructs.add(unitStruct);
-					}
-					// 公开中等总数
-					for (int i = 0; i < unitStructDto.getPublicMedium(); i++) {
-						++number;
-						PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct();
-						unitStruct.setDifficulty("中");
-						unitStruct.setPublicity(true);
-						unitStruct.setId(String.valueOf(number));
-						unitStruct.setNumber(number);
-						unitStruct.setScore(unitStructDto.getScore());
-						unitStruct.setQuestionType(unitStructDto.getQuestionType());
-						unitStruct.setQuesNames(unitStructDto.getQuesNames());
-						unitStruct.setPropertyGroup(buildGroup(unitStruct));
-						unitStructs.add(unitStruct);
-					}
-					// 公开困难总数
-					for (int i = 0; i < unitStructDto.getPublicDifficulty(); i++) {
-						++number;
-						PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct();
-						unitStruct.setDifficulty("难");
-						unitStruct.setPublicity(true);
-						unitStruct.setId(String.valueOf(number));
-						unitStruct.setNumber(number);
-						unitStruct.setScore(unitStructDto.getScore());
-						unitStruct.setQuestionType(unitStructDto.getQuestionType());
-						unitStruct.setQuesNames(unitStructDto.getQuesNames());
-						unitStruct.setPropertyGroup(buildGroup(unitStruct));
-						unitStructs.add(unitStruct);
-					}
-					// 非公开简单总数
-					for (int i = 0; i < unitStructDto.getNoPublicSimple(); i++) {
-						++number;
-						PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct();
-						unitStruct.setDifficulty("易");
-						unitStruct.setPublicity(false);
-						unitStruct.setId(String.valueOf(number));
-						unitStruct.setNumber(number);
-						unitStruct.setScore(unitStructDto.getScore());
-						unitStruct.setQuestionType(unitStructDto.getQuestionType());
-						unitStruct.setQuesNames(unitStructDto.getQuesNames());
-						unitStruct.setPropertyGroup(buildGroup(unitStruct));
-						unitStructs.add(unitStruct);
-					}
-					// 非公开中等总数
-					for (int i = 0; i < unitStructDto.getNoPublicMedium(); i++) {
-						++number;
-						PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct();
-						unitStruct.setDifficulty("中");
-						unitStruct.setPublicity(false);
-						unitStruct.setId(String.valueOf(number));
-						unitStruct.setNumber(number);
-						unitStruct.setScore(unitStructDto.getScore());
-						unitStruct.setQuestionType(unitStructDto.getQuestionType());
-						unitStruct.setQuesNames(unitStructDto.getQuesNames());
-						unitStruct.setPropertyGroup(buildGroup(unitStruct));
-						unitStructs.add(unitStruct);
-					}
-					// 非公开困难总数
-					for (int i = 0; i < unitStructDto.getNoPublicDifficulty(); i++) {
-						++number;
-						PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct();
-						unitStruct.setDifficulty("难");
-						unitStruct.setPublicity(false);
-						unitStruct.setId(String.valueOf(number));
-						unitStruct.setNumber(number);
-						unitStruct.setScore(unitStructDto.getScore());
-						unitStruct.setQuestionType(unitStructDto.getQuestionType());
-						unitStruct.setQuesNames(unitStructDto.getQuesNames());
-						unitStruct.setPropertyGroup(buildGroup(unitStruct));
-						unitStructs.add(unitStruct);
-					}
-				}
-				paperDetailStruct.setPaperDetailUnitStructs(unitStructs);
-			}
-			paperStruct.setPaperStrucType(PaperStructType.EXACT);
-			paperStruct
-					.setDetailUnitCount(paperDetailStructs.stream().mapToInt(PaperDetailStruct::getDetailCount).sum());
-		} else {
-			// 新增蓝图试卷结构
-			for (PaperDetailStruct paperDetailStruct : paperDetailStructs) {
-				List<PaperDetailUnitStruct> oldStructs = paperDetailStruct.getPaperDetailUnitStructs();
-				if (oldStructs != null && oldStructs.size() > 0) {
-					oldStructs.clear();
-				}
-				List<PaperDetailUnitStruct> unitStructs = new ArrayList<>();
-				for (CoursePropertyNumberDto coursePropertyNumberDto : paperDetailStruct
-						.getCoursePropertyNumberDtos()) {
-					// 取到子节点上的题目
-					if (!coursePropertyNumberDto.getDisable()) {
-						// 公开简单数量
-						for (int i = 0; i < coursePropertyNumberDto.getPublicSimple(); i++) {
-							++number;
-							PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct(paperDetailStruct, number,
-									coursePropertyNumberDto);
-							unitStruct.setDifficulty("易");
-							unitStruct.setPublicity(true);
-							unitStruct.setPropertyGroup(buildPropertyGroup(unitStruct));
-							unitStructs.add(unitStruct);
-						}
-						// 公开中等数量
-						for (int i = 0; i < coursePropertyNumberDto.getPublicMedium(); i++) {
-							++number;
-							PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct(paperDetailStruct, number,
-									coursePropertyNumberDto);
-							unitStruct.setDifficulty("中");
-							unitStruct.setPublicity(true);
-							unitStruct.setPropertyGroup(buildPropertyGroup(unitStruct));
-							unitStructs.add(unitStruct);
-						}
-						// 公开困难数量
-						for (int i = 0; i < coursePropertyNumberDto.getPublicDifficulty(); i++) {
-							++number;
-							PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct(paperDetailStruct, number,
-									coursePropertyNumberDto);
-							unitStruct.setDifficulty("难");
-							unitStruct.setPublicity(true);
-							unitStruct.setPropertyGroup(buildPropertyGroup(unitStruct));
-							unitStructs.add(unitStruct);
-						}
-						// 非公开简单数量
-						for (int i = 0; i < coursePropertyNumberDto.getNoPublicSimple(); i++) {
-							++number;
-							PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct(paperDetailStruct, number,
-									coursePropertyNumberDto);
-							unitStruct.setDifficulty("易");
-							unitStruct.setPublicity(false);
-							unitStruct.setPropertyGroup(buildPropertyGroup(unitStruct));
-							unitStructs.add(unitStruct);
-						}
-						// 非公开中等数量
-						for (int i = 0; i < coursePropertyNumberDto.getNoPublicMedium(); i++) {
-							++number;
-							PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct(paperDetailStruct, number,
-									coursePropertyNumberDto);
-							unitStruct.setDifficulty("中");
-							unitStruct.setPublicity(false);
-							unitStruct.setPropertyGroup(buildPropertyGroup(unitStruct));
-							unitStructs.add(unitStruct);
-						}
-						// 非公开困难
-						for (int i = 0; i < coursePropertyNumberDto.getNoPublicDifficulty(); i++) {
-							++number;
-							PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct(paperDetailStruct, number,
-									coursePropertyNumberDto);
-							unitStruct.setDifficulty("难");
-							unitStruct.setPublicity(false);
-							unitStruct.setPropertyGroup(buildPropertyGroup(unitStruct));
-							unitStructs.add(unitStruct);
-						}
-					}
-				}
-				paperDetailStruct.setPaperDetailUnitStructs(unitStructs);
-			}
-			paperStruct.setPaperStrucType(PaperStructType.BLUEPRINT);
-			// 计算试卷结构难度
-			Double difficulty = getDifficulty(paperDetailStructs, paperStruct.getTotalScore());
-			paperStruct.setDifficulty(difficulty);
-		}
-		paperStruct.setOrgId(user.getRootOrgId().toString());
-		paperStruct.setCreator(user.getDisplayName());
-		paperStruct.setCreateTime(CommonUtils.getCurDateTime());
-		paperStruct.setDetailCount(paperDetailStructs.size());
-		PaperStruct ret = paperStructRepo.save(paperStruct);
-		String key = CacheConstants.CACHE_Q_PAPER_STRUCT + paperStruct.getId();
-		redisClient.delete(key);
-		return ret;
-	}
-
-	/**
-	 * 构建精确组建筛选条件
-	 *
-	 * @param unitStruct
-	 * @return
-	 */
-	private String buildGroup(PaperDetailUnitStruct unitStruct) {
-		return String.valueOf(unitStruct.getPublicity()) + "-" + unitStruct.getDifficulty();
-	}
-
-	/**
-	 * 构建单个属性组(用来筛选题目)
-	 *
-	 * @param unitStruct
-	 */
-	private String buildPropertyGroup(PaperDetailUnitStruct unitStruct) {
-		return unitStruct.getPropertyId() + "-" + String.valueOf(unitStruct.getPublicity()) + "-"
-				+ unitStruct.getDifficulty();
-	}
-
-	public Double getDifficulty(List<PaperDetailStruct> paperDetailStructs, Double totalScore) {
-		Double sum = 0.0;
-		if (paperDetailStructs != null && paperDetailStructs.size() > 0) {
-			Integer simpleCount = 0;
-			Integer mediumCount = 0;
-			Integer difficultyCount = 0;
-			for (PaperDetailStruct paperDetailStruct : paperDetailStructs) {
-				simpleCount = paperDetailStruct.getPublicSimpleCount() + paperDetailStruct.getNoPublicSimpleCount();
-				mediumCount = paperDetailStruct.getPublicMediumCount() + paperDetailStruct.getNoPublicMediumCount();
-				difficultyCount = paperDetailStruct.getPublicDifficultyCount()
-						+ paperDetailStruct.getNoPublicDifficultyCount();
-				sum = simpleCount * paperDetailStruct.getScore() * 0.8
-						+ mediumCount * paperDetailStruct.getScore() * 0.5
-						+ difficultyCount * paperDetailStruct.getScore() * 0.2 + sum;
-			}
-
-			Double dif = sum / totalScore;
-			BigDecimal b = BigDecimal.valueOf(dif);
-			Double difficulty = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
-			return difficulty;
-		}
-		return (double) 0;
-	}
-
-	public PaperStruct checkNameUnique(String name, String orgId, String type) {
-		Query query = new Query();
-		query.addCriteria(Criteria.where("orgId").is(orgId));
-		query.addCriteria(Criteria.where("name").is(name.trim()));
-		query.addCriteria(Criteria.where("type").is(type));
-		PaperStruct paperStruct = this.mongoTemplate.findOne(query, PaperStruct.class);
-		return paperStruct;
-	}
-
-	public List<QuesNameDto> getQuesNameList(String orgId, String courseNo, QuesStructType quesType) {
-		List<QuesNameDto> quesNameList = new ArrayList<>();
-		List<QuesTypeName> quesTypeNames = new ArrayList<>();
-		if (StringUtils.isEmpty(courseNo)) {
-			quesTypeNames = quesTypeNameRepo.findQuesName(orgId, quesType);
-		} else {
-			quesTypeNames = quesTypeNameRepo.findQuesName(orgId, courseNo, quesType);
-		}
-		quesNameList = quesTypeNames.stream().map(QuesTypeName::getQuesNames).flatMap(Collection::stream).distinct()
-				.map(this::getQuesName).collect(Collectors.toList());
-		return quesNameList;
-	}
-
-	private QuesNameDto getQuesName(String name) {
-		return new QuesNameDto(name, name);
-	}
-
-	public PaperStruct getByCache(String id) {
-		String key = CacheConstants.CACHE_Q_PAPER_STRUCT + id;
-		PaperStruct ps = redisClient.get(key, PaperStruct.class, cacheTimeOut);
-		if (ps == null) {
-			ps = Model.of(paperStructRepo.findById(id));
-			if (ps == null) {
-				throw new StatusException("未找到试卷结构:" + id);
-			}
-			redisClient.set(key, ps, cacheTimeOut);
-		}
-		return ps;
-	}
-
-	public void removePaperStruct(List<String> ids) {
-		for (String id : ids) {
-			if (randomPaperService.existStruct(id)) {
-				PaperStruct ps = Model.of(paperStructRepo.findById(id));
-				throw new StatusException(ps.getName()+"已被抽题模板使用,不能删除");
-			}
-			paperStructRepo.deleteById(id);
-			String key = CacheConstants.CACHE_Q_PAPER_STRUCT + id;
-			redisClient.delete(key);
-		}
-	}
+    private static int cacheTimeOut = 2 * 60 * 60;
+
+    @Autowired
+    private RandomPaperService randomPaperService;
+
+    @Autowired
+    private PaperStructRepo paperStructRepo;
+
+    @Autowired
+    private QuesTypeNameRepo quesTypeNameRepo;
+
+    @Autowired
+    private MongoTemplate mongoTemplate;
+
+    @Autowired
+    private CourseCloudService courseCloudService;
+
+    @Autowired
+    private RedisClient redisClient;
+
+    /**
+     * 获取所有试卷结构(分页)
+     *
+     * @param searchInfo
+     * @param curPage
+     * @param pageSize
+     * @return
+     */
+    public Page<PaperStruct> getPaperStructs(PaperStructSearchInfo searchInfo, int curPage, int pageSize,
+                                             UserDataRule userDataRule) {
+        if (userDataRule.assertEmptyQueryResult()) {
+            return Page.empty();
+        }
+
+        Query query = new Query();
+        query.addCriteria(Criteria.where("orgId").is(searchInfo.getOrgId()));
+        if (userDataRule.assertNeedQueryRefIds()) {
+            Criteria c1 = Criteria.where("courseId").in(userDataRule.getRefIds());
+            Criteria c2 = Criteria.where("courseId").exists(false);
+            Criteria cr = new Criteria();
+            query.addCriteria(cr.orOperator(c1, c2));
+        }
+        query.addCriteria(Criteria.where("type").is(searchInfo.getType()));
+
+        // 判断试卷结构
+        if (PaperStructType.EXACT.name().equals(searchInfo.getType())) {
+            if (StringUtils.isNotBlank(searchInfo.getCourseNo())) {
+                if (!"ALL".equals(searchInfo.getCourseNo())) {
+                    query.addCriteria(Criteria.where("courseNo").is(searchInfo.getCourseNo()));
+                }
+            } else {
+                // “公用”情况
+                query.addCriteria(Criteria.where("courseNo").is(""));
+            }
+        } else {
+            if (StringUtils.isNotBlank(searchInfo.getCourseNo())) {
+                query.addCriteria(Criteria.where("courseNo").is(searchInfo.getCourseNo()));
+            }
+        }
+
+        if (StringUtils.isNotBlank(searchInfo.getName())) {
+            String paperStructName = CommonUtils.escapeExprSpecialWord(searchInfo.getName());
+            query.addCriteria(Criteria.where("name").regex(".*?" + paperStructName + ".*"));
+        }
+
+        if (StringUtils.isNotBlank(searchInfo.getCreator())) {
+            String userName = CommonUtils.escapeExprSpecialWord(searchInfo.getCreator());
+            query.addCriteria(Criteria.where("creator").regex(".*?" + userName + ".*"));
+        }
+
+        long total = this.mongoTemplate.count(query, PaperStruct.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<PaperStruct> paperStructs = this.mongoTemplate.find(query, PaperStruct.class);
+        if (CollectionUtils.isEmpty(paperStructs)) {
+            return Page.empty();
+        }
+
+        Map<String, String> courseNameMaps = new HashMap<>();
+
+        for (PaperStruct paperStruct : paperStructs) {
+            if (StringUtils.isBlank(paperStruct.getCourseNo())) {
+                paperStruct.setCourseName("公用");
+            } else {
+                String courseName = courseNameMaps.get(paperStruct.getCourseNo());
+
+                if (StringUtils.isEmpty(courseName)) {
+                    GetCourseReq req = new GetCourseReq();
+                    req.setRootOrgId(Long.valueOf(paperStruct.getOrgId()));
+                    req.setCode(paperStruct.getCourseNo());
+                    GetCourseResp resp = courseCloudService.getCourse(req);
+                    courseName = resp.getCourseBean().getName();
+                    courseNameMaps.put(paperStruct.getCourseNo(), courseName);
+                }
+
+                paperStruct.setCourseName(courseName);
+            }
+        }
+
+        return new PageImpl<>(paperStructs, pageable, total);
+    }
+
+    /**
+     * 获取所有试卷结构(分页)
+     *
+     * @param searchInfo
+     * @return
+     */
+    public List<PaperStruct> getPaperStructs(PaperStructSearchInfo searchInfo, UserDataRule ud) {
+        if (ud.assertEmptyQueryResult()) {
+            return new ArrayList<>();
+        }
+        Query query = new Query();
+        if (StringUtils.isNotBlank(searchInfo.getCourseNo())) {
+            query.addCriteria(Criteria.where("courseNo").in("", searchInfo.getCourseNo()));
+        }
+        query.addCriteria(Criteria.where("orgId").is(searchInfo.getOrgId()));
+        if (ud.assertNeedQueryRefIds()) {
+            Criteria c1 = Criteria.where("courseId").in(ud.getRefIds());
+            Criteria c2 = Criteria.where("courseId").exists(false);
+            Criteria cr = new Criteria();
+            cr.orOperator(c1, c2);
+        }
+        if (StringUtils.isNotBlank(searchInfo.getType())) {
+            query.addCriteria(Criteria.where("type").is(searchInfo.getType()));
+        }
+        query.with(Sort.by(Sort.Order.desc("createTime")));
+        List<PaperStruct> paperList = this.mongoTemplate.find(query, PaperStruct.class);
+        return paperList;
+    }
+
+    public void formatSearchInfo(PaperStructSearchInfo searchInfo) {
+        if (StringUtils.isEmpty(searchInfo.getName())) {
+            searchInfo.setName(null);
+        }
+        if (StringUtils.isEmpty(searchInfo.getCreator())) {
+            searchInfo.setCreator(null);
+        }
+        if (StringUtils.isEmpty(searchInfo.getCourseNo())) {
+            searchInfo.setCourseNo(null);
+        }
+    }
+
+    public void formatPaperStruct(PaperStruct paperStruct) {
+        paperStruct.setCreateTime(null);
+    }
+
+    /**
+     * 保存试卷结构
+     *
+     * @param paperStruct
+     * @return
+     */
+    public PaperStruct save(PaperStruct paperStruct, User user) {
+        if (StringUtils.isNotBlank(paperStruct.getCourseNo())) {
+            GetCourseReq req = new GetCourseReq();
+            req.setRootOrgId(Long.valueOf(paperStruct.getOrgId()));
+            req.setCode(paperStruct.getCourseNo());
+            GetCourseResp resp = courseCloudService.getCourse(req);
+            if (resp.getCourseBean() == null) {
+                throw new StatusException("500", "课程不存在");
+            }
+            paperStruct.setCourseId(resp.getCourseBean().getId());
+        } else {
+            paperStruct.setCourseId(null);
+        }
+        if (StringUtils.isNotBlank(paperStruct.getId())) {
+            PaperStruct oldPaperStruct = Model.of(paperStructRepo.findById(paperStruct.getId()));
+            PaperStruct rps = null;
+            if (oldPaperStruct != null && !paperStruct.getName().equals(oldPaperStruct.getName())) {// 那么就是更新操作
+                rps = this.checkNameUnique(paperStruct.getName(), user.getRootOrgId().toString(),
+                        oldPaperStruct.getType());
+            }
+            if (rps != null) {
+                return null;
+            }
+        }
+        List<PaperDetailStruct> paperDetailStructs = paperStruct.getPaperDetailStructs();
+        int number = 0;
+        // 新增精确试卷结构
+        if (paperStruct.getType().equals("EXACT")) {
+            for (PaperDetailStruct paperDetailStruct : paperDetailStructs) {
+                List<PaperDetailUnitStruct> oldStructs = paperDetailStruct.getPaperDetailUnitStructs();
+                if (oldStructs != null && oldStructs.size() > 0) {
+                    oldStructs.clear();
+                }
+                List<PaperDetailUnitStruct> unitStructs = new ArrayList<>();
+                for (PaperDetailUnitStructDto unitStructDto : paperDetailStruct.getUnitStructs()) {
+                    // 公开简单总数
+                    for (int i = 0; i < unitStructDto.getPublicSimple(); i++) {
+                        ++number;
+                        PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct();
+                        unitStruct.setDifficulty("易");
+                        unitStruct.setPublicity(true);
+                        unitStruct.setId(String.valueOf(number));
+                        unitStruct.setNumber(number);
+                        unitStruct.setScore(unitStructDto.getScore());
+                        unitStruct.setQuestionType(unitStructDto.getQuestionType());
+                        unitStruct.setQuesNames(unitStructDto.getQuesNames());
+                        unitStruct.setPropertyGroup(buildGroup(unitStruct));
+                        unitStructs.add(unitStruct);
+                    }
+                    // 公开中等总数
+                    for (int i = 0; i < unitStructDto.getPublicMedium(); i++) {
+                        ++number;
+                        PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct();
+                        unitStruct.setDifficulty("中");
+                        unitStruct.setPublicity(true);
+                        unitStruct.setId(String.valueOf(number));
+                        unitStruct.setNumber(number);
+                        unitStruct.setScore(unitStructDto.getScore());
+                        unitStruct.setQuestionType(unitStructDto.getQuestionType());
+                        unitStruct.setQuesNames(unitStructDto.getQuesNames());
+                        unitStruct.setPropertyGroup(buildGroup(unitStruct));
+                        unitStructs.add(unitStruct);
+                    }
+                    // 公开困难总数
+                    for (int i = 0; i < unitStructDto.getPublicDifficulty(); i++) {
+                        ++number;
+                        PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct();
+                        unitStruct.setDifficulty("难");
+                        unitStruct.setPublicity(true);
+                        unitStruct.setId(String.valueOf(number));
+                        unitStruct.setNumber(number);
+                        unitStruct.setScore(unitStructDto.getScore());
+                        unitStruct.setQuestionType(unitStructDto.getQuestionType());
+                        unitStruct.setQuesNames(unitStructDto.getQuesNames());
+                        unitStruct.setPropertyGroup(buildGroup(unitStruct));
+                        unitStructs.add(unitStruct);
+                    }
+                    // 非公开简单总数
+                    for (int i = 0; i < unitStructDto.getNoPublicSimple(); i++) {
+                        ++number;
+                        PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct();
+                        unitStruct.setDifficulty("易");
+                        unitStruct.setPublicity(false);
+                        unitStruct.setId(String.valueOf(number));
+                        unitStruct.setNumber(number);
+                        unitStruct.setScore(unitStructDto.getScore());
+                        unitStruct.setQuestionType(unitStructDto.getQuestionType());
+                        unitStruct.setQuesNames(unitStructDto.getQuesNames());
+                        unitStruct.setPropertyGroup(buildGroup(unitStruct));
+                        unitStructs.add(unitStruct);
+                    }
+                    // 非公开中等总数
+                    for (int i = 0; i < unitStructDto.getNoPublicMedium(); i++) {
+                        ++number;
+                        PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct();
+                        unitStruct.setDifficulty("中");
+                        unitStruct.setPublicity(false);
+                        unitStruct.setId(String.valueOf(number));
+                        unitStruct.setNumber(number);
+                        unitStruct.setScore(unitStructDto.getScore());
+                        unitStruct.setQuestionType(unitStructDto.getQuestionType());
+                        unitStruct.setQuesNames(unitStructDto.getQuesNames());
+                        unitStruct.setPropertyGroup(buildGroup(unitStruct));
+                        unitStructs.add(unitStruct);
+                    }
+                    // 非公开困难总数
+                    for (int i = 0; i < unitStructDto.getNoPublicDifficulty(); i++) {
+                        ++number;
+                        PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct();
+                        unitStruct.setDifficulty("难");
+                        unitStruct.setPublicity(false);
+                        unitStruct.setId(String.valueOf(number));
+                        unitStruct.setNumber(number);
+                        unitStruct.setScore(unitStructDto.getScore());
+                        unitStruct.setQuestionType(unitStructDto.getQuestionType());
+                        unitStruct.setQuesNames(unitStructDto.getQuesNames());
+                        unitStruct.setPropertyGroup(buildGroup(unitStruct));
+                        unitStructs.add(unitStruct);
+                    }
+                }
+                paperDetailStruct.setPaperDetailUnitStructs(unitStructs);
+            }
+            paperStruct.setPaperStrucType(PaperStructType.EXACT);
+            paperStruct
+                    .setDetailUnitCount(paperDetailStructs.stream().mapToInt(PaperDetailStruct::getDetailCount).sum());
+        } else {
+            // 新增蓝图试卷结构
+            for (PaperDetailStruct paperDetailStruct : paperDetailStructs) {
+                List<PaperDetailUnitStruct> oldStructs = paperDetailStruct.getPaperDetailUnitStructs();
+                if (oldStructs != null && oldStructs.size() > 0) {
+                    oldStructs.clear();
+                }
+                List<PaperDetailUnitStruct> unitStructs = new ArrayList<>();
+                for (CoursePropertyNumberDto coursePropertyNumberDto : paperDetailStruct
+                        .getCoursePropertyNumberDtos()) {
+                    // 取到子节点上的题目
+                    if (!coursePropertyNumberDto.getDisable()) {
+                        // 公开简单数量
+                        for (int i = 0; i < coursePropertyNumberDto.getPublicSimple(); i++) {
+                            ++number;
+                            PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct(paperDetailStruct, number,
+                                    coursePropertyNumberDto);
+                            unitStruct.setDifficulty("易");
+                            unitStruct.setPublicity(true);
+                            unitStruct.setPropertyGroup(buildPropertyGroup(unitStruct));
+                            unitStructs.add(unitStruct);
+                        }
+                        // 公开中等数量
+                        for (int i = 0; i < coursePropertyNumberDto.getPublicMedium(); i++) {
+                            ++number;
+                            PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct(paperDetailStruct, number,
+                                    coursePropertyNumberDto);
+                            unitStruct.setDifficulty("中");
+                            unitStruct.setPublicity(true);
+                            unitStruct.setPropertyGroup(buildPropertyGroup(unitStruct));
+                            unitStructs.add(unitStruct);
+                        }
+                        // 公开困难数量
+                        for (int i = 0; i < coursePropertyNumberDto.getPublicDifficulty(); i++) {
+                            ++number;
+                            PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct(paperDetailStruct, number,
+                                    coursePropertyNumberDto);
+                            unitStruct.setDifficulty("难");
+                            unitStruct.setPublicity(true);
+                            unitStruct.setPropertyGroup(buildPropertyGroup(unitStruct));
+                            unitStructs.add(unitStruct);
+                        }
+                        // 非公开简单数量
+                        for (int i = 0; i < coursePropertyNumberDto.getNoPublicSimple(); i++) {
+                            ++number;
+                            PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct(paperDetailStruct, number,
+                                    coursePropertyNumberDto);
+                            unitStruct.setDifficulty("易");
+                            unitStruct.setPublicity(false);
+                            unitStruct.setPropertyGroup(buildPropertyGroup(unitStruct));
+                            unitStructs.add(unitStruct);
+                        }
+                        // 非公开中等数量
+                        for (int i = 0; i < coursePropertyNumberDto.getNoPublicMedium(); i++) {
+                            ++number;
+                            PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct(paperDetailStruct, number,
+                                    coursePropertyNumberDto);
+                            unitStruct.setDifficulty("中");
+                            unitStruct.setPublicity(false);
+                            unitStruct.setPropertyGroup(buildPropertyGroup(unitStruct));
+                            unitStructs.add(unitStruct);
+                        }
+                        // 非公开困难
+                        for (int i = 0; i < coursePropertyNumberDto.getNoPublicDifficulty(); i++) {
+                            ++number;
+                            PaperDetailUnitStruct unitStruct = new PaperDetailUnitStruct(paperDetailStruct, number,
+                                    coursePropertyNumberDto);
+                            unitStruct.setDifficulty("难");
+                            unitStruct.setPublicity(false);
+                            unitStruct.setPropertyGroup(buildPropertyGroup(unitStruct));
+                            unitStructs.add(unitStruct);
+                        }
+                    }
+                }
+                paperDetailStruct.setPaperDetailUnitStructs(unitStructs);
+            }
+            paperStruct.setPaperStrucType(PaperStructType.BLUEPRINT);
+            // 计算试卷结构难度
+            Double difficulty = getDifficulty(paperDetailStructs, paperStruct.getTotalScore());
+            paperStruct.setDifficulty(difficulty);
+        }
+        paperStruct.setOrgId(user.getRootOrgId().toString());
+        paperStruct.setCreator(user.getDisplayName());
+        paperStruct.setCreateTime(CommonUtils.getCurDateTime());
+        paperStruct.setDetailCount(paperDetailStructs.size());
+        PaperStruct ret = paperStructRepo.save(paperStruct);
+        String key = CacheConstants.CACHE_Q_PAPER_STRUCT + paperStruct.getId();
+        redisClient.delete(key);
+        return ret;
+    }
+
+    /**
+     * 构建精确组建筛选条件
+     *
+     * @param unitStruct
+     * @return
+     */
+    private String buildGroup(PaperDetailUnitStruct unitStruct) {
+        return String.valueOf(unitStruct.getPublicity()) + "-" + unitStruct.getDifficulty();
+    }
+
+    /**
+     * 构建单个属性组(用来筛选题目)
+     *
+     * @param unitStruct
+     */
+    private String buildPropertyGroup(PaperDetailUnitStruct unitStruct) {
+        return unitStruct.getPropertyId() + "-" + String.valueOf(unitStruct.getPublicity()) + "-"
+                + unitStruct.getDifficulty();
+    }
+
+    public Double getDifficulty(List<PaperDetailStruct> paperDetailStructs, Double totalScore) {
+        Double sum = 0.0;
+        if (paperDetailStructs != null && paperDetailStructs.size() > 0) {
+            Integer simpleCount = 0;
+            Integer mediumCount = 0;
+            Integer difficultyCount = 0;
+            for (PaperDetailStruct paperDetailStruct : paperDetailStructs) {
+                simpleCount = paperDetailStruct.getPublicSimpleCount() + paperDetailStruct.getNoPublicSimpleCount();
+                mediumCount = paperDetailStruct.getPublicMediumCount() + paperDetailStruct.getNoPublicMediumCount();
+                difficultyCount = paperDetailStruct.getPublicDifficultyCount()
+                        + paperDetailStruct.getNoPublicDifficultyCount();
+                sum = simpleCount * paperDetailStruct.getScore() * 0.8
+                        + mediumCount * paperDetailStruct.getScore() * 0.5
+                        + difficultyCount * paperDetailStruct.getScore() * 0.2 + sum;
+            }
+
+            Double dif = sum / totalScore;
+            BigDecimal b = BigDecimal.valueOf(dif);
+            Double difficulty = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
+            return difficulty;
+        }
+        return (double) 0;
+    }
+
+    public PaperStruct checkNameUnique(String name, String orgId, String type) {
+        Query query = new Query();
+        query.addCriteria(Criteria.where("orgId").is(orgId));
+        query.addCriteria(Criteria.where("name").is(name.trim()));
+        query.addCriteria(Criteria.where("type").is(type));
+        PaperStruct paperStruct = this.mongoTemplate.findOne(query, PaperStruct.class);
+        return paperStruct;
+    }
+
+    public List<QuesNameDto> getQuesNameList(String orgId, String courseNo, QuesStructType quesType) {
+        List<QuesNameDto> quesNameList = new ArrayList<>();
+        List<QuesTypeName> quesTypeNames = new ArrayList<>();
+        if (StringUtils.isEmpty(courseNo)) {
+            quesTypeNames = quesTypeNameRepo.findQuesName(orgId, quesType);
+        } else {
+            quesTypeNames = quesTypeNameRepo.findQuesName(orgId, courseNo, quesType);
+        }
+        quesNameList = quesTypeNames.stream().map(QuesTypeName::getQuesNames).flatMap(Collection::stream).distinct()
+                .map(this::getQuesName).collect(Collectors.toList());
+        return quesNameList;
+    }
+
+    private QuesNameDto getQuesName(String name) {
+        return new QuesNameDto(name, name);
+    }
+
+    public PaperStruct getByCache(String id) {
+        String key = CacheConstants.CACHE_Q_PAPER_STRUCT + id;
+        PaperStruct ps = redisClient.get(key, PaperStruct.class, cacheTimeOut);
+        if (ps == null) {
+            ps = Model.of(paperStructRepo.findById(id));
+            if (ps == null) {
+                throw new StatusException("未找到试卷结构:" + id);
+            }
+            redisClient.set(key, ps, cacheTimeOut);
+        }
+        return ps;
+    }
+
+    public void removePaperStruct(List<String> ids) {
+        for (String id : ids) {
+            if (randomPaperService.existStruct(id)) {
+                PaperStruct ps = Model.of(paperStructRepo.findById(id));
+                throw new StatusException(ps.getName() + "已被抽题模板使用,不能删除");
+            }
+            paperStructRepo.deleteById(id);
+            String key = CacheConstants.CACHE_Q_PAPER_STRUCT + id;
+            redisClient.delete(key);
+        }
+    }
 
 }

+ 1123 - 1137
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/impl/RandomPaperServiceImpl.java

@@ -1,32 +1,5 @@
 package cn.com.qmth.examcloud.core.questions.service.impl;
 
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-import javax.annotation.Resource;
-
-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.Page;
-import org.springframework.data.domain.PageImpl;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Sort;
-import org.springframework.data.mongodb.core.MongoTemplate;
-import org.springframework.data.mongodb.core.query.Criteria;
-import org.springframework.data.mongodb.core.query.Query;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.core.basic.api.UserCloudService;
@@ -44,30 +17,12 @@ import cn.com.qmth.examcloud.core.questions.dao.PaperStructRepo;
 import cn.com.qmth.examcloud.core.questions.dao.PropertyRepo;
 import cn.com.qmth.examcloud.core.questions.dao.RandomPaperQuestionRepo;
 import cn.com.qmth.examcloud.core.questions.dao.RandomPaperRepo;
-import cn.com.qmth.examcloud.core.questions.dao.entity.PaperDetailStruct;
-import cn.com.qmth.examcloud.core.questions.dao.entity.PaperStruct;
-import cn.com.qmth.examcloud.core.questions.dao.entity.Property;
-import cn.com.qmth.examcloud.core.questions.dao.entity.QuesProperty;
-import cn.com.qmth.examcloud.core.questions.dao.entity.RandomPaper;
-import cn.com.qmth.examcloud.core.questions.dao.entity.RandomPaperQuestion;
+import cn.com.qmth.examcloud.core.questions.dao.entity.*;
 import cn.com.qmth.examcloud.core.questions.dao.entity.dto.CoursePropertyNumberDto;
 import cn.com.qmth.examcloud.core.questions.dao.entity.dto.PaperDetailUnitStructDto;
 import cn.com.qmth.examcloud.core.questions.service.PaperStructService;
 import cn.com.qmth.examcloud.core.questions.service.RandomPaperService;
-import cn.com.qmth.examcloud.core.questions.service.bean.randompaper.CreateDefaultPaperParam;
-import cn.com.qmth.examcloud.core.questions.service.bean.randompaper.PaperDetailDto;
-import cn.com.qmth.examcloud.core.questions.service.bean.randompaper.PaperDetailUnitDto;
-import cn.com.qmth.examcloud.core.questions.service.bean.randompaper.PaperQuestionViewQuery;
-import cn.com.qmth.examcloud.core.questions.service.bean.randompaper.PaperVo;
-import cn.com.qmth.examcloud.core.questions.service.bean.randompaper.QuestionDto;
-import cn.com.qmth.examcloud.core.questions.service.bean.randompaper.RandomPaperDomain;
-import cn.com.qmth.examcloud.core.questions.service.bean.randompaper.RandomPaperListVo;
-import cn.com.qmth.examcloud.core.questions.service.bean.randompaper.RandomPaperQuery;
-import cn.com.qmth.examcloud.core.questions.service.bean.randompaper.RandomPaperQuestionDto;
-import cn.com.qmth.examcloud.core.questions.service.bean.randompaper.StructInfo;
-import cn.com.qmth.examcloud.core.questions.service.bean.randompaper.StructQuestionCheckDto;
-import cn.com.qmth.examcloud.core.questions.service.bean.randompaper.StructQuestionCountInfo;
-import cn.com.qmth.examcloud.core.questions.service.bean.randompaper.StructQuestionInfo;
+import cn.com.qmth.examcloud.core.questions.service.bean.randompaper.*;
 import cn.com.qmth.examcloud.core.questions.service.cache.RandomPaperCache;
 import cn.com.qmth.examcloud.core.questions.service.util.BatchGetDataUtil;
 import cn.com.qmth.examcloud.core.questions.service.util.BatchSetDataUtil;
@@ -81,306 +36,337 @@ import cn.com.qmth.examcloud.support.CacheConstants;
 import cn.com.qmth.examcloud.support.cache.CacheHelper;
 import cn.com.qmth.examcloud.support.cache.bean.CourseCacheBean;
 import cn.com.qmth.examcloud.web.redis.RedisClient;
+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.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
 
 @Service
 public class RandomPaperServiceImpl implements RandomPaperService {
-	private static final Logger log = LoggerFactory.getLogger(RandomPaperService.class);
-	private static int cacheTimeOut = 2 * 60 * 60;
-	@Autowired
-	private MongoTemplate mongoTemplate;
-	@Resource(name="mongoTemplate2")
-	private MongoTemplate mongoTemplate2;
-	@Autowired
-	private PaperStructService paperStructService;
-	@Autowired
-	private PaperStructRepo paperStructRepo;
-	@Autowired
-	private RedisClient redisClient;
-	@Autowired
-	private PropertyRepo propertyRepo;
-	@Autowired
-	private RandomPaperRepo randomPaperRepo;
-	@Autowired
-	private RandomPaperQuestionRepo randomPaperQuestionRepo;
-	@Autowired
-	private UserCloudService userCloudService;
-
-	@Override
-	public Page<RandomPaperListVo> getPage(RandomPaperQuery req) {
-		if (req.getUd().assertEmptyQueryResult()) {
-			return Page.empty();
-		}
-		Query query;
-		List<Criteria> cs = new ArrayList<>();
-		cs.add(Criteria.where("rootOrgId").is(req.getRootOrgId()));
-
-		if (req.getUd().assertNeedQueryRefIds()) {
-			cs.add(Criteria.where("courseId").in(req.getUd().getRefIds()));
-		}
-
-		if (req.getEnable() != null) {
-			cs.add(Criteria.where("enable").is(req.getEnable()));
-		}
-
-		if (req.getCourseId() != null) {
-			cs.add(Criteria.where("courseId").is(req.getCourseId()));
-		}
-		if (StringUtils.isNotBlank(req.getName())) {
-			String paperName = CommonUtils.escapeExprSpecialWord(req.getName());
-			cs.add(Criteria.where("name").regex(".*?\\.*" + paperName + ".*"));
-		}
-		Criteria and = new Criteria();
-		Criteria[] cas = new Criteria[cs.size()];
-		if (StringUtils.isNotBlank(req.getId())) {
-			and.andOperator(cs.toArray(cas));
-			query = Query.query(new Criteria().orOperator(and, Criteria.where("id").is(req.getId())));
-		} else {
-			and.andOperator(cs.toArray(cas));
-			query = Query.query(and);
-		}
-
-		long total = this.mongoTemplate.count(query, RandomPaper.class);
-		if (total == 0) {
-			return Page.empty();
-		}
-
-		PageRequest pageable = PageRequest.of(req.getPageNumber() - 1, req.getPageSize());
-		query.with(Sort.by(Sort.Order.desc("creationDate")));
-		query.skip(pageable.getOffset());
-		query.limit(pageable.getPageSize());
-
-		List<RandomPaperListVo> paperList = this.mongoTemplate.find(query, RandomPaperListVo.class, "randomPaper");
-		if (CollectionUtils.isEmpty(paperList)) {
-			return Page.empty();
-		}
-
-		for (RandomPaperListVo vo : paperList) {
-			CourseCacheBean course = CacheHelper.getCourse(vo.getCourseId());
-			vo.setCourseCode(course.getCode());
-			vo.setCourseName(course.getName());
-			vo.setPaperStructTypeStr(vo.getPaperStructType().getName());
-			PaperStruct paperStruct = Model.of(paperStructRepo.findById(vo.getPaperStructId()));
-			vo.setPaperStructName(paperStruct.getName());
-			vo.setEnableStr(vo.getEnable() ? "启用" : "禁用");
-		}
-		fillUserName(paperList, req.getRootOrgId());
-
-		return new PageImpl<>(paperList, pageable, total);
-	}
-
-	private void fillUserName(List<RandomPaperListVo> dtos, Long rootOrgId) {
-		if (dtos != null && dtos.size() > 0) {
-			List<Long> ids = dtos.stream().map(dto -> dto.getUpdateBy()).distinct().collect(Collectors.toList());
-			List<UserBean> userList = new ArrayList<UserBean>();
-			GetUserListByIdsReq req = new GetUserListByIdsReq();
-			BatchGetDataUtil<UserBean, Long> tool = new BatchGetDataUtil<UserBean, Long>() {
-				@Override
-				public List<UserBean> getData(List<Long> paramList) {
-					req.setRootOrgId(rootOrgId);
-					req.setUserIdList(paramList);
-					GetUserListByIdsResp resp = userCloudService.getUserListByIds(req);
-					return resp.getUserBeanList();
-				}
-
-			};
-			tool.getDataForBatch(userList, ids, 100);
-			Map<Long, UserBean> map = userList.stream()
-					.collect(Collectors.toMap(UserBean::getUserId, account -> account, (key1, key2) -> key2));
-			for (RandomPaperListVo markerBean : dtos) {
-				UserBean userBean = map.get(markerBean.getUpdateBy());
-				markerBean.setUpdateByName(userBean.getDisplayName());
-			}
-		}
-	}
-
-	@Transactional
-	@Override
-	public void toggle(String id, Boolean enable, User user) {
-		RandomPaper paperStruct = Model.of(randomPaperRepo.findById(id));
-		if (paperStruct == null) {
-			throw new StatusException("未找到模板");
-		}
-		if (!paperStruct.getRootOrgId().equals(user.getRootOrgId())) {
-			throw new StatusException("非法操作");
-		}
-		paperStruct.setEnable(enable);
-		randomPaperRepo.save(paperStruct);
-	}
-
-	@Override
-	public StructInfo getStructQuestionInfo(String structId) {
-		StructInfo ret = new StructInfo();
-		PaperStruct ps = Model.of(paperStructRepo.findById(structId));
-		ret.setTotalScore(ps.getTotalScore());
-		if (PaperStructType.BLUEPRINT.equals(ps.getPaperStrucType())) {
-			ret.setDifficultyDegree(ps.getDifficulty());
-			if (CollectionUtils.isNotEmpty(ps.getPaperDetailStructs())) {
-				List<StructQuestionInfo> sqinfos = new ArrayList<>();
-				ret.setStructQuestionInfo(sqinfos);
-				for (PaperDetailStruct paperDetailStruct : ps.getPaperDetailStructs()) {
-					StructQuestionInfo sqinfo = new StructQuestionInfo();
-					sqinfos.add(sqinfo);
-					sqinfo.setDetailName(paperDetailStruct.getName());
-					sqinfo.setTotalCount(paperDetailStruct.getDetailCount());
-					sqinfo.setTotalScore(paperDetailStruct.getTotalScore());
-					Integer simpleCount = 0;
-					Integer mediumCount = 0;
-					Integer difficultyCount = 0;
-					simpleCount = paperDetailStruct.getPublicSimpleCount() + paperDetailStruct.getNoPublicSimpleCount();
-					mediumCount = paperDetailStruct.getPublicMediumCount() + paperDetailStruct.getNoPublicMediumCount();
-					difficultyCount = paperDetailStruct.getPublicDifficultyCount()
-							+ paperDetailStruct.getNoPublicDifficultyCount();
-					sqinfo.setHardInfo(new StructQuestionCountInfo(difficultyCount, true));
-					sqinfo.setMediumInfo(new StructQuestionCountInfo(mediumCount, true));
-					sqinfo.setEasyInfo(new StructQuestionCountInfo(simpleCount, true));
-				}
-			}
-		} else if (PaperStructType.EXACT.equals(ps.getPaperStrucType())) {
-			ret.setDifficultyDegree(getExactDifficulty(ps));
-			if (CollectionUtils.isNotEmpty(ps.getPaperDetailStructs())) {
-				List<StructQuestionInfo> sqinfos = new ArrayList<>();
-				ret.setStructQuestionInfo(sqinfos);
-				for (PaperDetailStruct paperDetailStruct : ps.getPaperDetailStructs()) {
-					StructQuestionInfo sqinfo = new StructQuestionInfo();
-					sqinfos.add(sqinfo);
-					sqinfo.setDetailName(paperDetailStruct.getName());
-					sqinfo.setTotalCount(paperDetailStruct.getDetailCount());
-					sqinfo.setTotalScore(paperDetailStruct.getTotalScore());
-					Integer simpleCount = 0;
-					Integer mediumCount = 0;
-					Integer difficultyCount = 0;
-					if (CollectionUtils.isNotEmpty(paperDetailStruct.getUnitStructs())) {
-						for (PaperDetailUnitStructDto unitStruct : paperDetailStruct.getUnitStructs()) {
-							simpleCount = simpleCount + unitStruct.getPublicSimple() + unitStruct.getNoPublicSimple();
-							mediumCount = mediumCount + unitStruct.getPublicMedium() + unitStruct.getNoPublicMedium();
-							difficultyCount = difficultyCount + unitStruct.getPublicDifficulty()
-									+ unitStruct.getNoPublicDifficulty();
-						}
-					}
-					sqinfo.setHardInfo(new StructQuestionCountInfo(difficultyCount, true));
-					sqinfo.setMediumInfo(new StructQuestionCountInfo(mediumCount, true));
-					sqinfo.setEasyInfo(new StructQuestionCountInfo(simpleCount, true));
-				}
-			}
-		}
-		return ret;
-	}
-
-	private Double getExactDifficulty(PaperStruct ps) {
-		Double sum = 0.0;
-		Double totalScore = ps.getTotalScore();
-		if (CollectionUtils.isNotEmpty(ps.getPaperDetailStructs())) {
-			Integer simpleCount = 0;
-			Integer mediumCount = 0;
-			Integer difficultyCount = 0;
-			for (PaperDetailStruct paperDetailStruct : ps.getPaperDetailStructs()) {
-				if (CollectionUtils.isNotEmpty(paperDetailStruct.getUnitStructs())) {
-					for (PaperDetailUnitStructDto unitStruct : paperDetailStruct.getUnitStructs()) {
-						simpleCount = unitStruct.getPublicSimple() + unitStruct.getNoPublicSimple();
-						mediumCount = unitStruct.getPublicMedium() + unitStruct.getNoPublicMedium();
-						difficultyCount = unitStruct.getPublicDifficulty() + unitStruct.getNoPublicDifficulty();
-						sum = simpleCount * unitStruct.getScore() * 0.8 + mediumCount * unitStruct.getScore() * 0.5
-								+ difficultyCount * unitStruct.getScore() * 0.2 + sum;
-					}
-				}
-			}
-
-			Double dif = sum / totalScore;
-			BigDecimal b = BigDecimal.valueOf(dif);
-			Double difficulty = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
-			return difficulty;
-		}
-		return (double) 0;
-	}
-
-	@Override
-	public StructInfo getPaperQuestionViewInfo(PaperQuestionViewQuery query) {
-		String structId = query.getStructId();
-		List<String> paperIds = query.getPaperIds();
-		if (StringUtils.isBlank(structId)) {
-			throw new StatusException("structId不能为空");
-		}
-		if (CollectionUtils.isEmpty(paperIds)) {
-			throw new StatusException("paperIds不能为空");
-		}
-		StructInfo ret = getPaperQuestionInfo(structId, paperIds);
-		clearQuestionIds(ret);
-		return ret;
-	}
-
-	private StructInfo getPaperQuestionInfo(String structId, List<String> paperIds) {
-		StructInfo ret = new StructInfo();
-		ret.setValid(true);
-		PaperStruct ps = Model.of(paperStructRepo.findById(structId));
-		List<QuestionDto> questionList = new ArrayList<>();
-		List<PaperDetailUnitDto> unitList=findUnitByPaperIds(paperIds);
-		fillQuestionAndDetail(unitList);
-		StructQuestionCheckDto cd = new StructQuestionCheckDto();
-		cd.setQuestionList(questionList);
-		if (PaperStructType.BLUEPRINT.equals(ps.getPaperStrucType())) {
-			for (PaperDetailUnitDto unit : unitList) {
-				unit.getQuestion().setQuesName(unit.getPaperDetail().getName());
-				unit.getQuestion().setPropertyGroup(bulidPropertyGroup(unit.getQuestion()));
-				questionList.add(unit.getQuestion());
-			}
-			if (CollectionUtils.isNotEmpty(ps.getPaperDetailStructs())) {
-				List<StructQuestionInfo> sqinfos = new ArrayList<>();
-				ret.setStructQuestionInfo(sqinfos);
-				int detailNumber = 0;
-				for (PaperDetailStruct ds : ps.getPaperDetailStructs()) {
-					detailNumber++;
-					StructQuestionInfo sqinfo = new StructQuestionInfo();
-					sqinfos.add(sqinfo);
-					sqinfo.setDetailName(ds.getName());
-					cd.setDetailNumber(detailNumber);
-					cd.setDs(ds);
-					cd.setSqinfo(sqinfo);
-					cd.setUnitScore(ds.getScore());
-					for (CoursePropertyNumberDto cp : ds.getCoursePropertyNumberDtos()) {
-						if (!cp.getDisable()) {
-							cd.setCp(cp);
-							setQuestionInfoByBlue(cd);
-						}
-					}
-					sqinfo.setTotalCount(sqinfo.getHardInfo().getCount() + sqinfo.getMediumInfo().getCount()
-							+ sqinfo.getEasyInfo().getCount());
-				}
-			}
-		} else if (PaperStructType.EXACT.equals(ps.getPaperStrucType())) {
-			for (PaperDetailUnitDto unit : unitList) {
-				unit.getQuestion().setQuesName(unit.getPaperDetail().getName());
-				questionList.add(unit.getQuestion());
-			}
-			if (CollectionUtils.isNotEmpty(ps.getPaperDetailStructs())) {
-				List<StructQuestionInfo> sqinfos = new ArrayList<>();
-				ret.setStructQuestionInfo(sqinfos);
-				int detailNumber = 0;
-				for (PaperDetailStruct ds : ps.getPaperDetailStructs()) {
-					detailNumber++;
-					StructQuestionInfo sqinfo = new StructQuestionInfo();
-					sqinfos.add(sqinfo);
-					sqinfo.setDetailName(ds.getName());
-					cd.setDetailNumber(detailNumber);
-					cd.setSqinfo(sqinfo);
-					int index = 0;
-					for (PaperDetailUnitStructDto us : ds.getUnitStructs()) {
-						index++;
-						cd.setUnitScore(us.getScore());
-						cd.setIndex(index);
-						cd.setUs(us);
-						setQuestionInfoByExact(cd);
-					}
-					sqinfo.setTotalCount(sqinfo.getHardInfo().getCount() + sqinfo.getMediumInfo().getCount()
-							+ sqinfo.getEasyInfo().getCount());
-				}
-			}
-		}
-		fillValid(ret);
-		return ret;
-	}
-	
-	private void fillQuestionAndDetail(List<PaperDetailUnitDto> units) {
-		if (CollectionUtils.isNotEmpty(units)) {
+
+    private static final Logger log = LoggerFactory.getLogger(RandomPaperService.class);
+
+    private static int cacheTimeOut = 2 * 60 * 60;
+
+    @Autowired
+    private MongoTemplate mongoTemplate;
+
+    @Resource(name = "mongoTemplate2")
+    private MongoTemplate mongoTemplate2;
+
+    @Autowired
+    private PaperStructService paperStructService;
+
+    @Autowired
+    private PaperStructRepo paperStructRepo;
+
+    @Autowired
+    private RedisClient redisClient;
+
+    @Autowired
+    private PropertyRepo propertyRepo;
+
+    @Autowired
+    private RandomPaperRepo randomPaperRepo;
+
+    @Autowired
+    private RandomPaperQuestionRepo randomPaperQuestionRepo;
+
+    @Autowired
+    private UserCloudService userCloudService;
+
+    @Override
+    public Page<RandomPaperListVo> getPage(RandomPaperQuery req) {
+        if (req.getUd().assertEmptyQueryResult()) {
+            return Page.empty();
+        }
+        Query query;
+        List<Criteria> cs = new ArrayList<>();
+        cs.add(Criteria.where("rootOrgId").is(req.getRootOrgId()));
+
+        if (req.getUd().assertNeedQueryRefIds()) {
+            cs.add(Criteria.where("courseId").in(req.getUd().getRefIds()));
+        }
+
+        if (req.getEnable() != null) {
+            cs.add(Criteria.where("enable").is(req.getEnable()));
+        }
+
+        if (req.getCourseId() != null) {
+            cs.add(Criteria.where("courseId").is(req.getCourseId()));
+        }
+        if (StringUtils.isNotBlank(req.getName())) {
+            String paperName = CommonUtils.escapeExprSpecialWord(req.getName());
+            cs.add(Criteria.where("name").regex(".*?\\.*" + paperName + ".*"));
+        }
+        Criteria and = new Criteria();
+        Criteria[] cas = new Criteria[cs.size()];
+        if (StringUtils.isNotBlank(req.getId())) {
+            and.andOperator(cs.toArray(cas));
+            query = Query.query(new Criteria().orOperator(and, Criteria.where("id").is(req.getId())));
+        } else {
+            and.andOperator(cs.toArray(cas));
+            query = Query.query(and);
+        }
+
+        long total = this.mongoTemplate.count(query, RandomPaper.class);
+        if (total == 0) {
+            return Page.empty();
+        }
+
+        PageRequest pageable = PageRequest.of(req.getPageNumber() - 1, req.getPageSize());
+        query.with(Sort.by(Sort.Order.desc("creationDate")));
+        query.skip(pageable.getOffset());
+        query.limit(pageable.getPageSize());
+
+        List<RandomPaperListVo> paperList = this.mongoTemplate.find(query, RandomPaperListVo.class, "randomPaper");
+        if (CollectionUtils.isEmpty(paperList)) {
+            return Page.empty();
+        }
+
+        for (RandomPaperListVo vo : paperList) {
+            CourseCacheBean course = CacheHelper.getCourse(vo.getCourseId());
+            vo.setCourseCode(course.getCode());
+            vo.setCourseName(course.getName());
+            vo.setPaperStructTypeStr(vo.getPaperStructType().getName());
+            PaperStruct paperStruct = Model.of(paperStructRepo.findById(vo.getPaperStructId()));
+            vo.setPaperStructName(paperStruct.getName());
+            vo.setEnableStr(vo.getEnable() ? "启用" : "禁用");
+        }
+        fillUserName(paperList, req.getRootOrgId());
+
+        return new PageImpl<>(paperList, pageable, total);
+    }
+
+    private void fillUserName(List<RandomPaperListVo> dtos, Long rootOrgId) {
+        if (dtos != null && dtos.size() > 0) {
+            List<Long> ids = dtos.stream().map(dto -> dto.getUpdateBy()).distinct().collect(Collectors.toList());
+            List<UserBean> userList = new ArrayList<UserBean>();
+            GetUserListByIdsReq req = new GetUserListByIdsReq();
+            BatchGetDataUtil<UserBean, Long> tool = new BatchGetDataUtil<UserBean, Long>() {
+                @Override
+                public List<UserBean> getData(List<Long> paramList) {
+                    req.setRootOrgId(rootOrgId);
+                    req.setUserIdList(paramList);
+                    GetUserListByIdsResp resp = userCloudService.getUserListByIds(req);
+                    return resp.getUserBeanList();
+                }
+
+            };
+            tool.getDataForBatch(userList, ids, 100);
+            Map<Long, UserBean> map = userList.stream()
+                    .collect(Collectors.toMap(UserBean::getUserId, account -> account, (key1, key2) -> key2));
+            for (RandomPaperListVo markerBean : dtos) {
+                UserBean userBean = map.get(markerBean.getUpdateBy());
+                markerBean.setUpdateByName(userBean.getDisplayName());
+            }
+        }
+    }
+
+    @Transactional
+    @Override
+    public void toggle(String id, Boolean enable, User user) {
+        RandomPaper paperStruct = Model.of(randomPaperRepo.findById(id));
+        if (paperStruct == null) {
+            throw new StatusException("未找到模板");
+        }
+        if (!paperStruct.getRootOrgId().equals(user.getRootOrgId())) {
+            throw new StatusException("非法操作");
+        }
+        paperStruct.setEnable(enable);
+        randomPaperRepo.save(paperStruct);
+    }
+
+    @Override
+    public StructInfo getStructQuestionInfo(String structId) {
+        StructInfo ret = new StructInfo();
+        PaperStruct ps = Model.of(paperStructRepo.findById(structId));
+        ret.setTotalScore(ps.getTotalScore());
+        if (PaperStructType.BLUEPRINT.equals(ps.getPaperStrucType())) {
+            ret.setDifficultyDegree(ps.getDifficulty());
+            if (CollectionUtils.isNotEmpty(ps.getPaperDetailStructs())) {
+                List<StructQuestionInfo> sqinfos = new ArrayList<>();
+                ret.setStructQuestionInfo(sqinfos);
+                for (PaperDetailStruct paperDetailStruct : ps.getPaperDetailStructs()) {
+                    StructQuestionInfo sqinfo = new StructQuestionInfo();
+                    sqinfos.add(sqinfo);
+                    sqinfo.setDetailName(paperDetailStruct.getName());
+                    sqinfo.setTotalCount(paperDetailStruct.getDetailCount());
+                    sqinfo.setTotalScore(paperDetailStruct.getTotalScore());
+                    Integer simpleCount = 0;
+                    Integer mediumCount = 0;
+                    Integer difficultyCount = 0;
+                    simpleCount = paperDetailStruct.getPublicSimpleCount() + paperDetailStruct.getNoPublicSimpleCount();
+                    mediumCount = paperDetailStruct.getPublicMediumCount() + paperDetailStruct.getNoPublicMediumCount();
+                    difficultyCount = paperDetailStruct.getPublicDifficultyCount()
+                            + paperDetailStruct.getNoPublicDifficultyCount();
+                    sqinfo.setHardInfo(new StructQuestionCountInfo(difficultyCount, true));
+                    sqinfo.setMediumInfo(new StructQuestionCountInfo(mediumCount, true));
+                    sqinfo.setEasyInfo(new StructQuestionCountInfo(simpleCount, true));
+                }
+            }
+        } else if (PaperStructType.EXACT.equals(ps.getPaperStrucType())) {
+            ret.setDifficultyDegree(getExactDifficulty(ps));
+            if (CollectionUtils.isNotEmpty(ps.getPaperDetailStructs())) {
+                List<StructQuestionInfo> sqinfos = new ArrayList<>();
+                ret.setStructQuestionInfo(sqinfos);
+                for (PaperDetailStruct paperDetailStruct : ps.getPaperDetailStructs()) {
+                    StructQuestionInfo sqinfo = new StructQuestionInfo();
+                    sqinfos.add(sqinfo);
+                    sqinfo.setDetailName(paperDetailStruct.getName());
+                    sqinfo.setTotalCount(paperDetailStruct.getDetailCount());
+                    sqinfo.setTotalScore(paperDetailStruct.getTotalScore());
+                    Integer simpleCount = 0;
+                    Integer mediumCount = 0;
+                    Integer difficultyCount = 0;
+                    if (CollectionUtils.isNotEmpty(paperDetailStruct.getUnitStructs())) {
+                        for (PaperDetailUnitStructDto unitStruct : paperDetailStruct.getUnitStructs()) {
+                            simpleCount = simpleCount + unitStruct.getPublicSimple() + unitStruct.getNoPublicSimple();
+                            mediumCount = mediumCount + unitStruct.getPublicMedium() + unitStruct.getNoPublicMedium();
+                            difficultyCount = difficultyCount + unitStruct.getPublicDifficulty()
+                                    + unitStruct.getNoPublicDifficulty();
+                        }
+                    }
+                    sqinfo.setHardInfo(new StructQuestionCountInfo(difficultyCount, true));
+                    sqinfo.setMediumInfo(new StructQuestionCountInfo(mediumCount, true));
+                    sqinfo.setEasyInfo(new StructQuestionCountInfo(simpleCount, true));
+                }
+            }
+        }
+        return ret;
+    }
+
+    private Double getExactDifficulty(PaperStruct ps) {
+        Double sum = 0.0;
+        Double totalScore = ps.getTotalScore();
+        if (CollectionUtils.isNotEmpty(ps.getPaperDetailStructs())) {
+            Integer simpleCount = 0;
+            Integer mediumCount = 0;
+            Integer difficultyCount = 0;
+            for (PaperDetailStruct paperDetailStruct : ps.getPaperDetailStructs()) {
+                if (CollectionUtils.isNotEmpty(paperDetailStruct.getUnitStructs())) {
+                    for (PaperDetailUnitStructDto unitStruct : paperDetailStruct.getUnitStructs()) {
+                        simpleCount = unitStruct.getPublicSimple() + unitStruct.getNoPublicSimple();
+                        mediumCount = unitStruct.getPublicMedium() + unitStruct.getNoPublicMedium();
+                        difficultyCount = unitStruct.getPublicDifficulty() + unitStruct.getNoPublicDifficulty();
+                        sum = simpleCount * unitStruct.getScore() * 0.8 + mediumCount * unitStruct.getScore() * 0.5
+                                + difficultyCount * unitStruct.getScore() * 0.2 + sum;
+                    }
+                }
+            }
+
+            Double dif = sum / totalScore;
+            BigDecimal b = BigDecimal.valueOf(dif);
+            Double difficulty = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
+            return difficulty;
+        }
+        return (double) 0;
+    }
+
+    @Override
+    public StructInfo getPaperQuestionViewInfo(PaperQuestionViewQuery query) {
+        String structId = query.getStructId();
+        List<String> paperIds = query.getPaperIds();
+        if (StringUtils.isBlank(structId)) {
+            throw new StatusException("structId不能为空");
+        }
+        if (CollectionUtils.isEmpty(paperIds)) {
+            throw new StatusException("paperIds不能为空");
+        }
+        StructInfo ret = getPaperQuestionInfo(structId, paperIds);
+        clearQuestionIds(ret);
+        return ret;
+    }
+
+    private StructInfo getPaperQuestionInfo(String structId, List<String> paperIds) {
+        StructInfo ret = new StructInfo();
+        ret.setValid(true);
+        PaperStruct ps = Model.of(paperStructRepo.findById(structId));
+        List<QuestionDto> questionList = new ArrayList<>();
+        List<PaperDetailUnitDto> unitList = findUnitByPaperIds(paperIds);
+        fillQuestionAndDetail(unitList);
+        StructQuestionCheckDto cd = new StructQuestionCheckDto();
+        cd.setQuestionList(questionList);
+        if (PaperStructType.BLUEPRINT.equals(ps.getPaperStrucType())) {
+            for (PaperDetailUnitDto unit : unitList) {
+                unit.getQuestion().setQuesName(unit.getPaperDetail().getName());
+                unit.getQuestion().setPropertyGroup(bulidPropertyGroup(unit.getQuestion()));
+                questionList.add(unit.getQuestion());
+            }
+            if (CollectionUtils.isNotEmpty(ps.getPaperDetailStructs())) {
+                List<StructQuestionInfo> sqinfos = new ArrayList<>();
+                ret.setStructQuestionInfo(sqinfos);
+                int detailNumber = 0;
+                for (PaperDetailStruct ds : ps.getPaperDetailStructs()) {
+                    detailNumber++;
+                    StructQuestionInfo sqinfo = new StructQuestionInfo();
+                    sqinfos.add(sqinfo);
+                    sqinfo.setDetailName(ds.getName());
+                    cd.setDetailNumber(detailNumber);
+                    cd.setDs(ds);
+                    cd.setSqinfo(sqinfo);
+                    cd.setUnitScore(ds.getScore());
+                    for (CoursePropertyNumberDto cp : ds.getCoursePropertyNumberDtos()) {
+                        if (!cp.getDisable()) {
+                            cd.setCp(cp);
+                            setQuestionInfoByBlue(cd);
+                        }
+                    }
+                    sqinfo.setTotalCount(sqinfo.getHardInfo().getCount() + sqinfo.getMediumInfo().getCount()
+                            + sqinfo.getEasyInfo().getCount());
+                }
+            }
+        } else if (PaperStructType.EXACT.equals(ps.getPaperStrucType())) {
+            for (PaperDetailUnitDto unit : unitList) {
+                unit.getQuestion().setQuesName(unit.getPaperDetail().getName());
+                questionList.add(unit.getQuestion());
+            }
+            if (CollectionUtils.isNotEmpty(ps.getPaperDetailStructs())) {
+                List<StructQuestionInfo> sqinfos = new ArrayList<>();
+                ret.setStructQuestionInfo(sqinfos);
+                int detailNumber = 0;
+                for (PaperDetailStruct ds : ps.getPaperDetailStructs()) {
+                    detailNumber++;
+                    StructQuestionInfo sqinfo = new StructQuestionInfo();
+                    sqinfos.add(sqinfo);
+                    sqinfo.setDetailName(ds.getName());
+                    cd.setDetailNumber(detailNumber);
+                    cd.setSqinfo(sqinfo);
+                    int index = 0;
+                    for (PaperDetailUnitStructDto us : ds.getUnitStructs()) {
+                        index++;
+                        cd.setUnitScore(us.getScore());
+                        cd.setIndex(index);
+                        cd.setUs(us);
+                        setQuestionInfoByExact(cd);
+                    }
+                    sqinfo.setTotalCount(sqinfo.getHardInfo().getCount() + sqinfo.getMediumInfo().getCount()
+                            + sqinfo.getEasyInfo().getCount());
+                }
+            }
+        }
+        fillValid(ret);
+        return ret;
+    }
+
+    private void fillQuestionAndDetail(List<PaperDetailUnitDto> units) {
+        if (CollectionUtils.isNotEmpty(units)) {
             new BatchSetDataUtil<PaperDetailUnitDto>() {
 
                 @Override
@@ -393,812 +379,812 @@ public class RandomPaperServiceImpl implements RandomPaperService {
                             map.put(vo.getId(), vo);
                         }
                         for (PaperDetailUnitDto dto : dataList) {
-                        	dto.setQuestion(map.get(dto.getQuestion().getId()));
+                            dto.setQuestion(map.get(dto.getQuestion().getId()));
                         }
                     }
                     ids = dataList.stream().map(p -> p.getPaperDetail().getId()).collect(Collectors.toList());
-                    List<PaperDetailDto> details=findDetailByIds(ids);
+                    List<PaperDetailDto> details = findDetailByIds(ids);
                     if (CollectionUtils.isNotEmpty(temList)) {
                         Map<String, PaperDetailDto> map = new HashMap<>();
                         for (PaperDetailDto vo : details) {
                             map.put(vo.getId(), vo);
                         }
                         for (PaperDetailUnitDto dto : dataList) {
-                        	dto.setPaperDetail(map.get(dto.getPaperDetail().getId()));
+                            dto.setPaperDetail(map.get(dto.getPaperDetail().getId()));
                         }
                     }
                 }
             }.setDataForBatch(units, 1000);
         }
-	}
-	
-	private List<QuestionDto> findQuestionByIds(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("id").in(ids));
-		List<QuestionDto> units = this.mongoTemplate.find(query, QuestionDto.class, "question");
-		return units;
-	}
-	
-	private List<PaperDetailDto> findDetailByIds(List<String> detailIds) {
-		List<Object> ids = new ArrayList<>();
-		for (String pid : detailIds) {
-			if (pid.length() > 24) {
-				ids.add(pid);
-			} else {
-				ids.add(new ObjectId(pid));
-			}
-		}
-		Query query = new Query();
-		query.addCriteria(Criteria.where("id").in(ids));
-		List<PaperDetailDto> units = this.mongoTemplate.find(query, PaperDetailDto.class, "paperDetail");
-		return units;
-	}
-
-	private void fillValid(StructInfo ret) {
-		if (CollectionUtils.isEmpty(ret.getStructQuestionInfo())) {
-			ret.setValid(false);
-			return;
-		}
-		for (StructQuestionInfo si : ret.getStructQuestionInfo()) {
-			if (!si.getHardInfo().getValid()) {
-				ret.setValid(false);
-			}
-			if (!si.getMediumInfo().getValid()) {
-				ret.setValid(false);
-			}
-			if (!si.getEasyInfo().getValid()) {
-				ret.setValid(false);
-			}
-		}
-	}
-
-	private void clearQuestionIds(StructInfo ret) {
-		if (CollectionUtils.isEmpty(ret.getStructQuestionInfo())) {
-			ret.setValid(false);
-			return;
-		}
-		for (StructQuestionInfo si : ret.getStructQuestionInfo()) {
-			if (!si.getHardInfo().getValid()) {
-				ret.setValid(false);
-			}
-			if (!si.getMediumInfo().getValid()) {
-				ret.setValid(false);
-			}
-			if (!si.getEasyInfo().getValid()) {
-				ret.setValid(false);
-			}
-			for (RandomPaperQuestionDto dto : si.getHardInfo().getQuestionInfo()) {
-				dto.setQuestionDtos(new ArrayList<>());
-			}
-			for (RandomPaperQuestionDto dto : si.getMediumInfo().getQuestionInfo()) {
-				dto.setQuestionDtos(new ArrayList<>());
-			}
-			for (RandomPaperQuestionDto dto : si.getEasyInfo().getQuestionInfo()) {
-				dto.setQuestionDtos(new ArrayList<>());
-			}
-		}
-	}
-
-	private void setQuestionInfoByExact(StructQuestionCheckDto cd) {
-		PaperDetailUnitStructDto us = cd.getUs();
-		StructQuestionInfo sqinfo = cd.getSqinfo();
-		if (us.getNoPublicDifficulty() > 0) {
-			cd.setSi(sqinfo.getHardInfo());
-			cd.setPub(false);
-			cd.setDifficulty(QuestionDifficulty.HARD.getName());
-			cd.setNeedCount(us.getNoPublicDifficulty());
-			setQuestionInfoByExactItem(cd);
-		}
-		if (us.getPublicDifficulty() > 0) {
-			cd.setSi(sqinfo.getHardInfo());
-			cd.setPub(true);
-			cd.setDifficulty(QuestionDifficulty.HARD.getName());
-			cd.setNeedCount(us.getPublicDifficulty());
-			setQuestionInfoByExactItem(cd);
-		}
-
-		if (us.getNoPublicMedium() > 0) {
-			cd.setSi(sqinfo.getMediumInfo());
-			cd.setPub(false);
-			cd.setDifficulty(QuestionDifficulty.MEDIUM.getName());
-			cd.setNeedCount(us.getNoPublicMedium());
-			setQuestionInfoByExactItem(cd);
-		}
-		if (us.getPublicMedium() > 0) {
-			cd.setSi(sqinfo.getMediumInfo());
-			cd.setPub(true);
-			cd.setDifficulty(QuestionDifficulty.MEDIUM.getName());
-			cd.setNeedCount(us.getPublicMedium());
-			setQuestionInfoByExactItem(cd);
-		}
-		if (us.getNoPublicSimple() > 0) {
-			cd.setSi(sqinfo.getEasyInfo());
-			cd.setPub(false);
-			cd.setDifficulty(QuestionDifficulty.EASY.getName());
-			cd.setNeedCount(us.getNoPublicSimple());
-			setQuestionInfoByExactItem(cd);
-		}
-		if (us.getPublicSimple() > 0) {
-			cd.setSi(sqinfo.getEasyInfo());
-			cd.setPub(true);
-			cd.setDifficulty(QuestionDifficulty.EASY.getName());
-			cd.setNeedCount(us.getPublicSimple());
-			setQuestionInfoByExactItem(cd);
-		}
-	}
-
-	private void setQuestionInfoByExactItem(StructQuestionCheckDto cd) {
-		StructQuestionCountInfo si = cd.getSi();
-		RandomPaperQuestionDto rq = new RandomPaperQuestionDto();
-		rq.setUnitScore(cd.getUnitScore());
-		rq.setDetailNumber(cd.getDetailNumber());
-		rq.setKey(cd.getIndex() + "-" + cd.getPub() + "-" + cd.getDifficulty());
-		si.getQuestionInfo().add(rq);
-		if (CollectionUtils.isNotEmpty(cd.getQuestionList())) {
-			Iterator<QuestionDto> it = cd.getQuestionList().iterator();
-			while (it.hasNext()) {
-				QuestionDto q = it.next();
-				if (cd.getUsedQuesIds().contains(q.getId())) {
-					it.remove();
-				} else {
-					if (checkExactQuesType(cd.getUs().getQuesNames(), cd.getUs().getQuestionType(), cd.getPub(),
-							cd.getDifficulty(), q)) {
-						rq.getQuestionDtos().add(q);
-						cd.getUsedQuesIds().add(q.getId());
-						it.remove();
-					}
-				}
-			}
-		}
-		si.setCount(si.getCount() + rq.getQuestionDtos().size());
-		if (si.getValid() && cd.getNeedCount() > rq.getQuestionDtos().size()) {
-			si.setValid(false);
-			si.setInvalidMsg(getExactErrmsg(cd.getIndex(), cd.getDetailNumber(), cd.getPub(), cd.getDifficulty()));
-		}
-	}
-
-	private void setQuestionInfoByBlue(StructQuestionCheckDto cd) {
-		StructQuestionInfo sqinfo = cd.getSqinfo();
-		CoursePropertyNumberDto cp = cd.getCp();
-		if (cp.getNoPublicDifficulty() > 0) {
-			cd.setSi(sqinfo.getHardInfo());
-			cd.setPub(false);
-			cd.setDifficulty(QuestionDifficulty.HARD.getName());
-			cd.setNeedCount(cp.getNoPublicDifficulty());
-			setQuestionInfoByBlueProp(cd);
-		}
-		if (cp.getPublicDifficulty() > 0) {
-			cd.setSi(sqinfo.getHardInfo());
-			cd.setPub(true);
-			cd.setDifficulty(QuestionDifficulty.HARD.getName());
-			cd.setNeedCount(cp.getPublicDifficulty());
-			setQuestionInfoByBlueProp(cd);
-		}
-
-		if (cp.getNoPublicMedium() > 0) {
-			cd.setSi(sqinfo.getMediumInfo());
-			cd.setPub(false);
-			cd.setDifficulty(QuestionDifficulty.MEDIUM.getName());
-			cd.setNeedCount(cp.getNoPublicMedium());
-			setQuestionInfoByBlueProp(cd);
-		}
-		if (cp.getPublicMedium() > 0) {
-			cd.setSi(sqinfo.getMediumInfo());
-			cd.setPub(true);
-			cd.setDifficulty(QuestionDifficulty.MEDIUM.getName());
-			cd.setNeedCount(cp.getPublicMedium());
-			setQuestionInfoByBlueProp(cd);
-		}
-		if (cp.getNoPublicSimple() > 0) {
-			cd.setSi(sqinfo.getEasyInfo());
-			cd.setPub(false);
-			cd.setDifficulty(QuestionDifficulty.EASY.getName());
-			cd.setNeedCount(cp.getNoPublicSimple());
-			setQuestionInfoByBlueProp(cd);
-		}
-		if (cp.getPublicSimple() > 0) {
-			cd.setSi(sqinfo.getEasyInfo());
-			cd.setPub(true);
-			cd.setDifficulty(QuestionDifficulty.EASY.getName());
-			cd.setNeedCount(cp.getPublicSimple());
-			setQuestionInfoByBlueProp(cd);
-		}
-	}
-
-	private void setQuestionInfoByBlueProp(StructQuestionCheckDto cd) {
-		StructQuestionCountInfo si = cd.getSi();
-		RandomPaperQuestionDto rq = new RandomPaperQuestionDto();
-		rq.setUnitScore(cd.getUnitScore());
-		rq.setDetailNumber(cd.getDetailNumber());
-		rq.setKey(bulidPropertyGroupByBlueStruct(cd.getCp().getPropertyParentId(), cd.getCp().getPropertyId(),
-				cd.getPub(), cd.getDifficulty()));
-		si.getQuestionInfo().add(rq);
-		if (CollectionUtils.isNotEmpty(cd.getQuestionList())) {
-			Iterator<QuestionDto> it = cd.getQuestionList().iterator();
-			while (it.hasNext()) {
-				QuestionDto q = it.next();
-				if (cd.getUsedQuesIds().contains(q.getId())) {
-					it.remove();
-				} else {
-					if (checkBlueQuesType(cd.getDs().getQuesNames(), cd.getDs().getQuestionType(), rq.getKey(), q)) {
-						rq.getQuestionDtos().add(q);
-						cd.getUsedQuesIds().add(q.getId());
-						it.remove();
-					}
-				}
-			}
-		}
-		si.setCount(si.getCount() + rq.getQuestionDtos().size());
-		if (si.getValid() && cd.getNeedCount() > rq.getQuestionDtos().size()) {
-			si.setValid(false);
-			si.setInvalidMsg(getBlueErrmsg(cd.getDetailNumber(), cd.getCp().getPropertyParentId(),
-					cd.getCp().getPropertyId(), cd.getPub(), cd.getDifficulty()));
-		}
-	}
-
-	private String getExactErrmsg(Integer index, Integer detailNumber, Boolean pub, String difficulty) {
-		String pubstr;
-		if (pub) {
-			pubstr = "公开";
-		} else {
-			pubstr = "非公开";
-		}
-		return "第" + detailNumber + "大题 " + "第" + index + "题型结构 " + pubstr + "-" + difficulty + "题源数量不满足";
-	}
-
-	private String getBlueErrmsg(Integer detailNumber, String pproid, String proid, Boolean pub, String difficulty) {
-		String pubstr;
-		if (pub) {
-			pubstr = "公开";
-		} else {
-			pubstr = "非公开";
-		}
-		if (StringUtils.isNotBlank(pproid) && !"0".equals(pproid)) {
-			// 有一级 和 二级
-			Property fp = Model.of(propertyRepo.findById(pproid));
-			Property sp = Model.of(propertyRepo.findById(proid));
-			return "第" + detailNumber + "大题 " + fp.getName() + "-" + sp.getName() + "-" + pubstr + "-" + difficulty
-					+ "题源数量不满足";
-		} else {
-			// 有一级 无 二级
-			Property fp = Model.of(propertyRepo.findById(proid));
-			return "第" + detailNumber + "大题 " + fp.getName() + "-" + pubstr + "-" + difficulty + "题源数量不满足";
-		}
-	}
-
-	private boolean checkExactQuesType(List<String> quesNames, QuesStructType st, Boolean pub, String difficulty,
-			QuestionDto question) {
-		if (CollectionUtils.isNotEmpty(quesNames)) {
-			if (quesNames.contains(question.getQuesName()) && st.equals(question.getQuestionType())) {
-				if (question.getPublicity().equals(pub) && question.getDifficulty().equals(difficulty)) {
-					return true;
-				}
-			}
-		}
-		return false;
-	}
-
-	private boolean checkBlueQuesType(List<String> quesNames, QuesStructType st, String propertyGroup,
-			QuestionDto question) {
-		if (CollectionUtils.isNotEmpty(quesNames)) {
-			if (quesNames.contains(question.getQuesName()) && st.equals(question.getQuestionType())) {
-				if (question.getPropertyGroup() != null) {
-					if (question.getPropertyGroup().contains(propertyGroup)) {
-						return true;
-					}
-				}
-			}
-		}
-		return false;
-	}
-
-	private List<PaperDetailUnitDto> findUnitByPaperIds(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));
-		List<PaperDetailUnitDto> units = this.mongoTemplate2.find(query, PaperDetailUnitDto.class, "paperDetailUnit");
-		return units;
-	}
-
-	private String bulidPropertyGroupByBlueStruct(String pproid, String proid, Boolean pub, String difficulty) {
-		String propertyGroup = null;
-		// 获取试题关联的多组属性
-		if (StringUtils.isNotBlank(pproid) && !"0".equals(pproid)) {
-			// 有一级 和 二级
-			propertyGroup = pproid + "-" + proid + "-" + pub + "-" + difficulty;
-		} else {
-			// 有一级 无 二级
-			propertyGroup = proid + "-" + pub + "-" + difficulty;
-		}
-		return propertyGroup;
-	}
-
-	private List<String> bulidPropertyGroup(QuestionDto question) {
-		String propertyGroup = null;
-		List<String> propertyGroups = new ArrayList<>();
-		// 获取试题关联的多组属性
-		List<QuesProperty> quesProperties = question.getQuesProperties();
-		if (quesProperties != null && quesProperties.size() > 0) {
-			for (QuesProperty quesProperty : quesProperties) {
-				if (quesProperty.getSecondProperty() != null) {
-					// 有一级 和 二级
-					if (quesProperty.getSecondProperty().getId() == null
-							|| StringUtils.isBlank(String.valueOf(quesProperty.getSecondProperty().getId()))) {
-						propertyGroup = String.valueOf(quesProperty.getFirstProperty().getId()) + "-"
-								+ String.valueOf(question.getPublicity()) + "-" + question.getDifficulty();
-					} else {
-						propertyGroup = String.valueOf(quesProperty.getFirstProperty().getId()) + "-"
-								+ String.valueOf(quesProperty.getSecondProperty().getId()) + "-"
-								+ String.valueOf(question.getPublicity()) + "-" + question.getDifficulty();
-					}
-					propertyGroups.add(propertyGroup);
-				} else {
-					// 有一级 无 二级
-					propertyGroup = String.valueOf(quesProperty.getFirstProperty().getId()) + "-"
-							+ String.valueOf(question.getPublicity()) + "-" + question.getDifficulty();
-					propertyGroups.add(propertyGroup);
-				}
-			}
-			return propertyGroups;
-		}
-		return null;
-	}
-
-	@Transactional
-	@Override
-	public StructInfo saveRandomPaper(RandomPaperDomain domain) {
-		if (domain.getCourseId() == null) {
-			throw new StatusException("课程id不能为空");
-		}
-		if (StringUtils.isBlank(domain.getName())) {
-			throw new StatusException("模板名称不能为空");
-		}
-		if (domain.getPaperStructType() == null) {
-			throw new StatusException("组卷模式不能为空");
-		}
-		if (domain.getPaperStructId() == null) {
-			throw new StatusException("组卷结构不能为空");
-		}
-		if (domain.getPaperType() == null) {
-			throw new StatusException("题源范围不能为空");
-		}
-		if (CollectionUtils.isEmpty(domain.getPaperIds())) {
-			throw new StatusException("试卷id不能为空");
-		}
-		RandomPaper rp = randomPaperRepo.findByRootOrgIdAndName(domain.getRootOrgId(), domain.getName());
-		if (rp != null && !rp.getId().equals(domain.getId())) {
-			throw new StatusException("模板名称已存在");
-		}
-		StructInfo ret = getPaperQuestionInfo(domain.getPaperStructId(), domain.getPaperIds());
-		if (ret.getValid()) {
-			RandomPaper e;
-			if (StringUtils.isNotBlank(domain.getId())) {
-				e = Model.of(randomPaperRepo.findById(domain.getId()));
-			} else {
-				e = new RandomPaper();
-				e.setCourseId(domain.getCourseId());
-				e.setEnable(true);
-				e.setRootOrgId(domain.getRootOrgId());
-			}
-			e.setName(domain.getName());
-			e.setPaperIds(domain.getPaperIds());
-			e.setPaperStructType(domain.getPaperStructType());
-			e.setPaperStructId(domain.getPaperStructId());
-			e.setPaperType(domain.getPaperType());
-			randomPaperRepo.save(e);
-			randomPaperQuestionRepo.deleteByRandomPaperId(e.getId());
-			List<RandomPaperQuestion> rqs = new ArrayList<>();
-			for (StructQuestionInfo si : ret.getStructQuestionInfo()) {
-				for (RandomPaperQuestionDto dto : si.getHardInfo().getQuestionInfo()) {
-					addRqs(rqs, dto, e);
-				}
-				for (RandomPaperQuestionDto dto : si.getMediumInfo().getQuestionInfo()) {
-					addRqs(rqs, dto, e);
-				}
-				for (RandomPaperQuestionDto dto : si.getEasyInfo().getQuestionInfo()) {
-					addRqs(rqs, dto, e);
-				}
-			}
-			randomPaperQuestionRepo.saveAll(rqs);
-			String key = CacheConstants.CACHE_Q_RANDOM_PAPER + e.getId();
-			redisClient.delete(key);
-		}
-		clearQuestionIds(ret);
-		return ret;
-	}
-
-	private void addRqs(List<RandomPaperQuestion> rqs, RandomPaperQuestionDto dto, RandomPaper e) {
-		if (CollectionUtils.isNotEmpty(dto.getQuestionDtos())) {
-			for (QuestionDto qdto : dto.getQuestionDtos()) {
-				RandomPaperQuestion rq = new RandomPaperQuestion();
-				rqs.add(rq);
-				rq.setCourseId(e.getCourseId());
-				rq.setKey(dto.getDetailNumber() + "-" + dto.getKey());
-				rq.setQuestionId(qdto.getId());
-				rq.setRandomPaperId(e.getId());
-				rq.setRootOrgId(e.getRootOrgId());
-				rq.setScore(dto.getUnitScore());
-				rq.setQuestionType(qdto.getQuestionType());
-				rq.setAnswerType(qdto.getAnswerType());
-				if (CollectionUtils.isNotEmpty(qdto.getQuesOptions())) {
-					rq.setOptionCount(qdto.getQuesOptions().size());
-				}
-				if (QuesStructType.NESTED_ANSWER_QUESTION.equals(rq.getQuestionType())
-						&& CollectionUtils.isNotEmpty(qdto.getSubQuestions())) {
-					List<RandomPaperQuestion> subQuestion = new ArrayList<>();
-					rq.setSubQuestions(subQuestion);
-					List<Double> subScores = getSubScoreList(rq.getScore(), qdto.getSubQuestions().size());
-					int i = 0;
-					for (QuestionDto subQd : qdto.getSubQuestions()) {
-						RandomPaperQuestion subrq = new RandomPaperQuestion();
-						subQuestion.add(subrq);
-						subrq.setCourseId(e.getCourseId());
-						subrq.setScore(subScores.get(i));
-						i++;
-						subrq.setQuestionType(subQd.getQuestionType());
-						subrq.setAnswerType(subQd.getAnswerType());
-						if (CollectionUtils.isNotEmpty(subQd.getQuesOptions())) {
-							subrq.setOptionCount(subQd.getQuesOptions().size());
-						}
-					}
-				}
-			}
-		}
-	}
-
-	private List<Double> getSubScoreList(double totalScore, int count) {
-		List<Double> scoreList = new ArrayList<>();
-		if (count > 0) {
-			int baseScore = (int) (totalScore / count);
-			double leftScore = totalScore;
-			for (int i = 0; i < count; i++) {
-				scoreList.add((double) baseScore);
-				leftScore -= baseScore;
-			}
-			if (leftScore > 0) {
-				scoreList.set(count - 1, baseScore + leftScore);
-			}
-			return scoreList;
-		}
-		return null;
-	}
-
-	@Override
-	public RandomPaperListVo getInfo(String id) {
-		RandomPaperListVo vo = this.mongoTemplate.findById(id, RandomPaperListVo.class, "randomPaper");
-		CourseCacheBean course = CacheHelper.getCourse(vo.getCourseId());
-		vo.setCourseCode(course.getCode());
-		vo.setCourseName(course.getName());
-		vo.setPaperStructTypeStr(vo.getPaperStructType().getName());
-		PaperStruct paperStruct = Model.of(paperStructRepo.findById(vo.getPaperStructId()));
-		vo.setPaperStructName(paperStruct.getName());
-		vo.setEnableStr(vo.getEnable() ? "启用" : "禁用");
-		GetUserReq ureq = new GetUserReq();
-		ureq.setUserId(vo.getUpdateBy());
-		GetUserResp ures = userCloudService.getUser(ureq);
-		vo.setUpdateByName(ures.getUserBean().getDisplayName());
-		Query query = new Query();
-		List<Object> ids = new ArrayList<>();
-		for (String pid : vo.getPaperIds()) {
-			if (pid.length() > 24) {
-				ids.add(pid);
-			} else {
-				ids.add(new ObjectId(pid));
-			}
-		}
-		query.addCriteria(Criteria.where("id").in(ids));
-		List<PaperVo> papers = this.mongoTemplate.find(query, PaperVo.class, "paper");
-		vo.setPapers(papers);
-		return vo;
-	}
-
-	@Override
-	public DefaultPaper getRandomPaper(String randomPaperId, Integer playTime) {
-		log.warn("开始抽卷");
-		long d1=System.currentTimeMillis();
-		RandomPaperCache rp = getByCache(randomPaperId);
-		long d2=System.currentTimeMillis();
-		log.warn("获取抽卷模板耗时(ms):"+(d2-d1));
-		PaperStruct ps = paperStructService.getByCache(rp.getPaperStructId());
-		long d3=System.currentTimeMillis();
-		log.warn("获取组卷结构耗时(ms):"+(d3-d2));
-		CreateDefaultPaperParam param = new CreateDefaultPaperParam();
-		param.setFullyObjective(true);
-		param.setRp(rp);
-		param.setPlayTime(playTime);
-		DefaultPaper paper = new DefaultPaper();
-		paper.setName(rp.getName());
-		List<DefaultQuestionGroup> details = new ArrayList<>();
-		paper.setQuestionGroupList(details);
-		if (PaperStructType.BLUEPRINT.equals(ps.getPaperStrucType())) {
-			if (CollectionUtils.isNotEmpty(ps.getPaperDetailStructs())) {
-				int detailNumber = 0;
-				for (PaperDetailStruct ds : ps.getPaperDetailStructs()) {
-					long f1=System.currentTimeMillis();
-					DefaultQuestionGroup detail = new DefaultQuestionGroup();
-					details.add(detail);
-					detail.setGroupName(ds.getName());
-					detail.setGroupScore(ds.getTotalScore());
-					List<DefaultQuestionStructureWrapper> units = new ArrayList<>();
-					detail.setQuestionWrapperList(units);
-					detailNumber++;
-					param.setUnits(units);
-					param.setDetailNumber(detailNumber);
-					for (CoursePropertyNumberDto cp : ds.getCoursePropertyNumberDtos()) {
-						if (!cp.getDisable()) {
-							param.setCp(cp);
-							createUnitByBlueProp(param);
-						}
-					}
-					long f2=System.currentTimeMillis();
-					log.warn("蓝图抽卷一个大题耗时(ms):"+(f2-f1));
-				}
-			}
-			long d4=System.currentTimeMillis();
-			log.warn("蓝图抽卷耗时(ms):"+(d4-d3));
-		} else if (PaperStructType.EXACT.equals(ps.getPaperStrucType())) {
-			if (CollectionUtils.isNotEmpty(ps.getPaperDetailStructs())) {
-				int detailNumber = 0;
-				for (PaperDetailStruct ds : ps.getPaperDetailStructs()) {
-					long f1=System.currentTimeMillis();
-					DefaultQuestionGroup detail = new DefaultQuestionGroup();
-					details.add(detail);
-					detail.setGroupName(ds.getName());
-					detail.setGroupScore(ds.getTotalScore());
-					List<DefaultQuestionStructureWrapper> units = new ArrayList<>();
-					detail.setQuestionWrapperList(units);
-					detailNumber++;
-					param.setUnits(units);
-					param.setDetailNumber(detailNumber);
-					int index = 0;
-					for (PaperDetailUnitStructDto us : ds.getUnitStructs()) {
-						index++;
-						param.setIndex(index);
-						param.setUs(us);
-						createUnitByExact(param);
-					}
-					long f2=System.currentTimeMillis();
-					log.warn("精确抽卷一个大题耗时(ms):"+(f2-f1));
-				}
-			}
-			long d4=System.currentTimeMillis();
-			log.warn("精确抽卷耗时(ms):"+(d4-d3));
-		}
-		paper.setFullyObjective(param.getFullyObjective());
-		log.warn("结束抽卷");
-		return paper;
-	}
-
-	private void createUnitByExact(CreateDefaultPaperParam param) {
-		PaperDetailUnitStructDto us = param.getUs();
-		if (us.getNoPublicDifficulty() > 0) {
-			param.setUnitCount(us.getNoPublicDifficulty());
-			String key = param.getDetailNumber() + "-" + param.getIndex() + "-" + false + "-"
-					+ QuestionDifficulty.HARD.getName();
-			param.setKey(key);
-			createUnit(param);
-		}
-		if (us.getPublicDifficulty() > 0) {
-			param.setUnitCount(us.getPublicDifficulty());
-			String key = param.getDetailNumber() + "-" + param.getIndex() + "-" + true + "-"
-					+ QuestionDifficulty.HARD.getName();
-			param.setKey(key);
-			createUnit(param);
-		}
-
-		if (us.getNoPublicMedium() > 0) {
-			param.setUnitCount(us.getNoPublicMedium());
-			String key = param.getDetailNumber() + "-" + param.getIndex() + "-" + false + "-"
-					+ QuestionDifficulty.MEDIUM.getName();
-			param.setKey(key);
-			createUnit(param);
-		}
-		if (us.getPublicMedium() > 0) {
-			param.setUnitCount(us.getPublicMedium());
-			String key = param.getDetailNumber() + "-" + param.getIndex() + "-" + true + "-"
-					+ QuestionDifficulty.MEDIUM.getName();
-			param.setKey(key);
-			createUnit(param);
-		}
-		if (us.getNoPublicSimple() > 0) {
-			param.setUnitCount(us.getNoPublicSimple());
-			String key = param.getDetailNumber() + "-" + param.getIndex() + "-" + false + "-"
-					+ QuestionDifficulty.EASY.getName();
-			param.setKey(key);
-			createUnit(param);
-		}
-		if (us.getPublicSimple() > 0) {
-			param.setUnitCount(us.getPublicSimple());
-			String key = param.getDetailNumber() + "-" + param.getIndex() + "-" + true + "-"
-					+ QuestionDifficulty.EASY.getName();
-			param.setKey(key);
-			createUnit(param);
-		}
-	}
-
-	private void createUnitByBlueProp(CreateDefaultPaperParam param) {
-		CoursePropertyNumberDto cp = param.getCp();
-		if (cp.getNoPublicDifficulty() > 0) {
-			String key = param.getDetailNumber() + "-" + bulidPropertyGroupByBlueStruct(cp.getPropertyParentId(),
-					cp.getPropertyId(), false, QuestionDifficulty.HARD.getName());
-			param.setKey(key);
-			param.setUnitCount(cp.getNoPublicDifficulty());
-			createUnit(param);
-		}
-		if (cp.getPublicDifficulty() > 0) {
-			String key = param.getDetailNumber() + "-" + bulidPropertyGroupByBlueStruct(cp.getPropertyParentId(),
-					cp.getPropertyId(), true, QuestionDifficulty.HARD.getName());
-			param.setKey(key);
-			param.setUnitCount(cp.getPublicDifficulty());
-			createUnit(param);
-		}
-
-		if (cp.getNoPublicMedium() > 0) {
-			String key = param.getDetailNumber() + "-" + bulidPropertyGroupByBlueStruct(cp.getPropertyParentId(),
-					cp.getPropertyId(), false, QuestionDifficulty.MEDIUM.getName());
-			param.setKey(key);
-			param.setUnitCount(cp.getNoPublicMedium());
-			createUnit(param);
-		}
-		if (cp.getPublicMedium() > 0) {
-			String key = param.getDetailNumber() + "-" + bulidPropertyGroupByBlueStruct(cp.getPropertyParentId(),
-					cp.getPropertyId(), true, QuestionDifficulty.MEDIUM.getName());
-			param.setKey(key);
-			param.setUnitCount(cp.getPublicMedium());
-			createUnit(param);
-		}
-		if (cp.getNoPublicSimple() > 0) {
-			String key = param.getDetailNumber() + "-" + bulidPropertyGroupByBlueStruct(cp.getPropertyParentId(),
-					cp.getPropertyId(), false, QuestionDifficulty.EASY.getName());
-			param.setKey(key);
-			param.setUnitCount(cp.getNoPublicSimple());
-			createUnit(param);
-		}
-		if (cp.getPublicSimple() > 0) {
-			String key = param.getDetailNumber() + "-" + bulidPropertyGroupByBlueStruct(cp.getPropertyParentId(),
-					cp.getPropertyId(), true, QuestionDifficulty.EASY.getName());
-			param.setKey(key);
-			param.setUnitCount(cp.getPublicSimple());
-			createUnit(param);
-		}
-	}
-
-	private void createUnit(CreateDefaultPaperParam param) {
-		List<RandomPaperQuestion> rpqs = param.getRp().getQuestionMap().get(param.getKey());
-		Collections.shuffle(rpqs);
-		for (int i = 0; i < param.getUnitCount(); i++) {
-			RandomPaperQuestion rpq = rpqs.get(i);
-			DefaultQuestionStructureWrapper qw = new DefaultQuestionStructureWrapper();
-			param.getUnits().add(qw);
-			qw.setLimitedPlayTimes(param.getPlayTime());
-			qw.setPlayedTimes(0);
-			qw.setQuestionId(rpq.getQuestionId());
-			qw.setQuestionScore(rpq.getScore());
-			List<DefaultQuestionUnitWrapper> qList = new ArrayList<>();
-			qw.setQuestionUnitWrapperList(qList);
-			if (QuesStructType.NESTED_ANSWER_QUESTION.equals(rpq.getQuestionType())) {
-				for (RandomPaperQuestion sub : rpq.getSubQuestions()) {
-					DefaultQuestionUnitWrapper q = new DefaultQuestionUnitWrapper();
-					qList.add(q);
-					q.setAnswerType(sub.getAnswerType());
-					q.setOptionPermutation(getOption(sub.getOptionCount()));
-					q.setQuestionScore(sub.getScore());
-					q.setQuestionType(getByOldType(sub.getQuestionType()));
-					if (!PaperUtil.isObjecttive(sub.getQuestionType())) {
-						param.setFullyObjective(false);
-					}
-				}
-			} else {
-				DefaultQuestionUnitWrapper q = new DefaultQuestionUnitWrapper();
-				qList.add(q);
-				q.setAnswerType(rpq.getAnswerType());
-				q.setOptionPermutation(getOption(rpq.getOptionCount()));
-				q.setQuestionScore(rpq.getScore());
-				q.setQuestionType(getByOldType(rpq.getQuestionType()));
-				if (!PaperUtil.isObjecttive(rpq.getQuestionType())) {
-					param.setFullyObjective(false);
-				}
-			}
-		}
-	}
-
-	private QuestionType getByOldType(QuesStructType quesStructType) {
-		if (quesStructType == QuesStructType.BOOL_ANSWER_QUESTION) {
-			return QuestionType.TRUE_OR_FALSE;
-		}
-		if (quesStructType == QuesStructType.FILL_BLANK_QUESTION) {
-			return QuestionType.FILL_UP;
-		}
-		if (quesStructType == QuesStructType.MULTIPLE_ANSWER_QUESTION) {
-			return QuestionType.MULTIPLE_CHOICE;
-		}
-		if (quesStructType == QuesStructType.SINGLE_ANSWER_QUESTION) {
-			return QuestionType.SINGLE_CHOICE;
-		}
-		if (quesStructType == QuesStructType.TEXT_ANSWER_QUESTION) {
-			return QuestionType.ESSAY;
-		}
-		return null;
-	}
-
-	private Integer[] getOption(Integer count) {
-		if (count == null) {
-			return null;
-		}
-		Integer[] ret = new Integer[count];
-		for (int i = 0; i < count; i++) {
-			ret[i] = i;
-		}
-		return ret;
-	}
-
-	private RandomPaperCache getByCache(String id) {
-		String key = CacheConstants.CACHE_Q_RANDOM_PAPER + id;
-		RandomPaperCache rp = redisClient.get(key, RandomPaperCache.class, cacheTimeOut);
-		if (rp == null) {
-			rp = new RandomPaperCache();
-			RandomPaper e = Model.of(randomPaperRepo.findById(id));
-			if (e == null) {
-				throw new StatusException("未找到随机模板:" + id);
-			}
-			rp.setName(e.getName());
-			rp.setPaperStructId(e.getPaperStructId());
-			List<RandomPaperQuestion> rpqs = randomPaperQuestionRepo.findByRandomPaperId(id);
-			if (CollectionUtils.isEmpty(rpqs)) {
-				throw new StatusException("随机模板试题库为空:" + id);
-			}
-			Map<String, List<RandomPaperQuestion>> map = new HashMap<>();
-			for (RandomPaperQuestion rpq : rpqs) {
-				List<RandomPaperQuestion> list = map.get(rpq.getKey());
-				if (list == null) {
-					list = new ArrayList<>();
-					map.put(rpq.getKey(), list);
-				}
-				list.add(rpq);
-			}
-			rp.setQuestionMap(map);
-			redisClient.set(key, rp, cacheTimeOut);
-		}
-		return rp;
-	}
-
-	@Override
-	public boolean existStruct(String paperStructId) {
-		Query query = new Query();
-		query.addCriteria(Criteria.where("paperStructId").is(paperStructId));
-		RandomPaper rp = mongoTemplate.findOne(query, RandomPaper.class);
-		return rp != null;
-	}
-
-	@Override
-	public boolean existPaper(Long courseId, String paperId) {
-		Query query = new Query();
-		query.addCriteria(Criteria.where("courseId").is(courseId));
-		List<RandomPaper> rps = mongoTemplate.find(query, RandomPaper.class);
-		if (CollectionUtils.isEmpty(rps)) {
-			return false;
-		}
-		for (RandomPaper rp : rps) {
-			if (rp.getPaperIds().contains(paperId)) {
-				return true;
-			}
-		}
-		return false;
-	}
+    }
+
+    private List<QuestionDto> findQuestionByIds(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("id").in(ids));
+        List<QuestionDto> units = this.mongoTemplate.find(query, QuestionDto.class, "question");
+        return units;
+    }
+
+    private List<PaperDetailDto> findDetailByIds(List<String> detailIds) {
+        List<Object> ids = new ArrayList<>();
+        for (String pid : detailIds) {
+            if (pid.length() > 24) {
+                ids.add(pid);
+            } else {
+                ids.add(new ObjectId(pid));
+            }
+        }
+        Query query = new Query();
+        query.addCriteria(Criteria.where("id").in(ids));
+        List<PaperDetailDto> units = this.mongoTemplate.find(query, PaperDetailDto.class, "paperDetail");
+        return units;
+    }
+
+    private void fillValid(StructInfo ret) {
+        if (CollectionUtils.isEmpty(ret.getStructQuestionInfo())) {
+            ret.setValid(false);
+            return;
+        }
+        for (StructQuestionInfo si : ret.getStructQuestionInfo()) {
+            if (!si.getHardInfo().getValid()) {
+                ret.setValid(false);
+            }
+            if (!si.getMediumInfo().getValid()) {
+                ret.setValid(false);
+            }
+            if (!si.getEasyInfo().getValid()) {
+                ret.setValid(false);
+            }
+        }
+    }
+
+    private void clearQuestionIds(StructInfo ret) {
+        if (CollectionUtils.isEmpty(ret.getStructQuestionInfo())) {
+            ret.setValid(false);
+            return;
+        }
+        for (StructQuestionInfo si : ret.getStructQuestionInfo()) {
+            if (!si.getHardInfo().getValid()) {
+                ret.setValid(false);
+            }
+            if (!si.getMediumInfo().getValid()) {
+                ret.setValid(false);
+            }
+            if (!si.getEasyInfo().getValid()) {
+                ret.setValid(false);
+            }
+            for (RandomPaperQuestionDto dto : si.getHardInfo().getQuestionInfo()) {
+                dto.setQuestionDtos(new ArrayList<>());
+            }
+            for (RandomPaperQuestionDto dto : si.getMediumInfo().getQuestionInfo()) {
+                dto.setQuestionDtos(new ArrayList<>());
+            }
+            for (RandomPaperQuestionDto dto : si.getEasyInfo().getQuestionInfo()) {
+                dto.setQuestionDtos(new ArrayList<>());
+            }
+        }
+    }
+
+    private void setQuestionInfoByExact(StructQuestionCheckDto cd) {
+        PaperDetailUnitStructDto us = cd.getUs();
+        StructQuestionInfo sqinfo = cd.getSqinfo();
+        if (us.getNoPublicDifficulty() > 0) {
+            cd.setSi(sqinfo.getHardInfo());
+            cd.setPub(false);
+            cd.setDifficulty(QuestionDifficulty.HARD.getName());
+            cd.setNeedCount(us.getNoPublicDifficulty());
+            setQuestionInfoByExactItem(cd);
+        }
+        if (us.getPublicDifficulty() > 0) {
+            cd.setSi(sqinfo.getHardInfo());
+            cd.setPub(true);
+            cd.setDifficulty(QuestionDifficulty.HARD.getName());
+            cd.setNeedCount(us.getPublicDifficulty());
+            setQuestionInfoByExactItem(cd);
+        }
+
+        if (us.getNoPublicMedium() > 0) {
+            cd.setSi(sqinfo.getMediumInfo());
+            cd.setPub(false);
+            cd.setDifficulty(QuestionDifficulty.MEDIUM.getName());
+            cd.setNeedCount(us.getNoPublicMedium());
+            setQuestionInfoByExactItem(cd);
+        }
+        if (us.getPublicMedium() > 0) {
+            cd.setSi(sqinfo.getMediumInfo());
+            cd.setPub(true);
+            cd.setDifficulty(QuestionDifficulty.MEDIUM.getName());
+            cd.setNeedCount(us.getPublicMedium());
+            setQuestionInfoByExactItem(cd);
+        }
+        if (us.getNoPublicSimple() > 0) {
+            cd.setSi(sqinfo.getEasyInfo());
+            cd.setPub(false);
+            cd.setDifficulty(QuestionDifficulty.EASY.getName());
+            cd.setNeedCount(us.getNoPublicSimple());
+            setQuestionInfoByExactItem(cd);
+        }
+        if (us.getPublicSimple() > 0) {
+            cd.setSi(sqinfo.getEasyInfo());
+            cd.setPub(true);
+            cd.setDifficulty(QuestionDifficulty.EASY.getName());
+            cd.setNeedCount(us.getPublicSimple());
+            setQuestionInfoByExactItem(cd);
+        }
+    }
+
+    private void setQuestionInfoByExactItem(StructQuestionCheckDto cd) {
+        StructQuestionCountInfo si = cd.getSi();
+        RandomPaperQuestionDto rq = new RandomPaperQuestionDto();
+        rq.setUnitScore(cd.getUnitScore());
+        rq.setDetailNumber(cd.getDetailNumber());
+        rq.setKey(cd.getIndex() + "-" + cd.getPub() + "-" + cd.getDifficulty());
+        si.getQuestionInfo().add(rq);
+        if (CollectionUtils.isNotEmpty(cd.getQuestionList())) {
+            Iterator<QuestionDto> it = cd.getQuestionList().iterator();
+            while (it.hasNext()) {
+                QuestionDto q = it.next();
+                if (cd.getUsedQuesIds().contains(q.getId())) {
+                    it.remove();
+                } else {
+                    if (checkExactQuesType(cd.getUs().getQuesNames(), cd.getUs().getQuestionType(), cd.getPub(),
+                            cd.getDifficulty(), q)) {
+                        rq.getQuestionDtos().add(q);
+                        cd.getUsedQuesIds().add(q.getId());
+                        it.remove();
+                    }
+                }
+            }
+        }
+        si.setCount(si.getCount() + rq.getQuestionDtos().size());
+        if (si.getValid() && cd.getNeedCount() > rq.getQuestionDtos().size()) {
+            si.setValid(false);
+            si.setInvalidMsg(getExactErrmsg(cd.getIndex(), cd.getDetailNumber(), cd.getPub(), cd.getDifficulty()));
+        }
+    }
+
+    private void setQuestionInfoByBlue(StructQuestionCheckDto cd) {
+        StructQuestionInfo sqinfo = cd.getSqinfo();
+        CoursePropertyNumberDto cp = cd.getCp();
+        if (cp.getNoPublicDifficulty() > 0) {
+            cd.setSi(sqinfo.getHardInfo());
+            cd.setPub(false);
+            cd.setDifficulty(QuestionDifficulty.HARD.getName());
+            cd.setNeedCount(cp.getNoPublicDifficulty());
+            setQuestionInfoByBlueProp(cd);
+        }
+        if (cp.getPublicDifficulty() > 0) {
+            cd.setSi(sqinfo.getHardInfo());
+            cd.setPub(true);
+            cd.setDifficulty(QuestionDifficulty.HARD.getName());
+            cd.setNeedCount(cp.getPublicDifficulty());
+            setQuestionInfoByBlueProp(cd);
+        }
+
+        if (cp.getNoPublicMedium() > 0) {
+            cd.setSi(sqinfo.getMediumInfo());
+            cd.setPub(false);
+            cd.setDifficulty(QuestionDifficulty.MEDIUM.getName());
+            cd.setNeedCount(cp.getNoPublicMedium());
+            setQuestionInfoByBlueProp(cd);
+        }
+        if (cp.getPublicMedium() > 0) {
+            cd.setSi(sqinfo.getMediumInfo());
+            cd.setPub(true);
+            cd.setDifficulty(QuestionDifficulty.MEDIUM.getName());
+            cd.setNeedCount(cp.getPublicMedium());
+            setQuestionInfoByBlueProp(cd);
+        }
+        if (cp.getNoPublicSimple() > 0) {
+            cd.setSi(sqinfo.getEasyInfo());
+            cd.setPub(false);
+            cd.setDifficulty(QuestionDifficulty.EASY.getName());
+            cd.setNeedCount(cp.getNoPublicSimple());
+            setQuestionInfoByBlueProp(cd);
+        }
+        if (cp.getPublicSimple() > 0) {
+            cd.setSi(sqinfo.getEasyInfo());
+            cd.setPub(true);
+            cd.setDifficulty(QuestionDifficulty.EASY.getName());
+            cd.setNeedCount(cp.getPublicSimple());
+            setQuestionInfoByBlueProp(cd);
+        }
+    }
+
+    private void setQuestionInfoByBlueProp(StructQuestionCheckDto cd) {
+        StructQuestionCountInfo si = cd.getSi();
+        RandomPaperQuestionDto rq = new RandomPaperQuestionDto();
+        rq.setUnitScore(cd.getUnitScore());
+        rq.setDetailNumber(cd.getDetailNumber());
+        rq.setKey(bulidPropertyGroupByBlueStruct(cd.getCp().getPropertyParentId(), cd.getCp().getPropertyId(),
+                cd.getPub(), cd.getDifficulty()));
+        si.getQuestionInfo().add(rq);
+        if (CollectionUtils.isNotEmpty(cd.getQuestionList())) {
+            Iterator<QuestionDto> it = cd.getQuestionList().iterator();
+            while (it.hasNext()) {
+                QuestionDto q = it.next();
+                if (cd.getUsedQuesIds().contains(q.getId())) {
+                    it.remove();
+                } else {
+                    if (checkBlueQuesType(cd.getDs().getQuesNames(), cd.getDs().getQuestionType(), rq.getKey(), q)) {
+                        rq.getQuestionDtos().add(q);
+                        cd.getUsedQuesIds().add(q.getId());
+                        it.remove();
+                    }
+                }
+            }
+        }
+        si.setCount(si.getCount() + rq.getQuestionDtos().size());
+        if (si.getValid() && cd.getNeedCount() > rq.getQuestionDtos().size()) {
+            si.setValid(false);
+            si.setInvalidMsg(getBlueErrmsg(cd.getDetailNumber(), cd.getCp().getPropertyParentId(),
+                    cd.getCp().getPropertyId(), cd.getPub(), cd.getDifficulty()));
+        }
+    }
+
+    private String getExactErrmsg(Integer index, Integer detailNumber, Boolean pub, String difficulty) {
+        String pubstr;
+        if (pub) {
+            pubstr = "公开";
+        } else {
+            pubstr = "非公开";
+        }
+        return "第" + detailNumber + "大题 " + "第" + index + "题型结构 " + pubstr + "-" + difficulty + "题源数量不满足";
+    }
+
+    private String getBlueErrmsg(Integer detailNumber, String pproid, String proid, Boolean pub, String difficulty) {
+        String pubstr;
+        if (pub) {
+            pubstr = "公开";
+        } else {
+            pubstr = "非公开";
+        }
+        if (StringUtils.isNotBlank(pproid) && !"0".equals(pproid)) {
+            // 有一级 和 二级
+            Property fp = Model.of(propertyRepo.findById(pproid));
+            Property sp = Model.of(propertyRepo.findById(proid));
+            return "第" + detailNumber + "大题 " + fp.getName() + "-" + sp.getName() + "-" + pubstr + "-" + difficulty
+                    + "题源数量不满足";
+        } else {
+            // 有一级 无 二级
+            Property fp = Model.of(propertyRepo.findById(proid));
+            return "第" + detailNumber + "大题 " + fp.getName() + "-" + pubstr + "-" + difficulty + "题源数量不满足";
+        }
+    }
+
+    private boolean checkExactQuesType(List<String> quesNames, QuesStructType st, Boolean pub, String difficulty,
+                                       QuestionDto question) {
+        if (CollectionUtils.isNotEmpty(quesNames)) {
+            if (quesNames.contains(question.getQuesName()) && st.equals(question.getQuestionType())) {
+                if (question.getPublicity().equals(pub) && question.getDifficulty().equals(difficulty)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private boolean checkBlueQuesType(List<String> quesNames, QuesStructType st, String propertyGroup,
+                                      QuestionDto question) {
+        if (CollectionUtils.isNotEmpty(quesNames)) {
+            if (quesNames.contains(question.getQuesName()) && st.equals(question.getQuestionType())) {
+                if (question.getPropertyGroup() != null) {
+                    if (question.getPropertyGroup().contains(propertyGroup)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    private List<PaperDetailUnitDto> findUnitByPaperIds(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));
+        List<PaperDetailUnitDto> units = this.mongoTemplate2.find(query, PaperDetailUnitDto.class, "paperDetailUnit");
+        return units;
+    }
+
+    private String bulidPropertyGroupByBlueStruct(String pproid, String proid, Boolean pub, String difficulty) {
+        String propertyGroup = null;
+        // 获取试题关联的多组属性
+        if (StringUtils.isNotBlank(pproid) && !"0".equals(pproid)) {
+            // 有一级 和 二级
+            propertyGroup = pproid + "-" + proid + "-" + pub + "-" + difficulty;
+        } else {
+            // 有一级 无 二级
+            propertyGroup = proid + "-" + pub + "-" + difficulty;
+        }
+        return propertyGroup;
+    }
+
+    private List<String> bulidPropertyGroup(QuestionDto question) {
+        String propertyGroup = null;
+        List<String> propertyGroups = new ArrayList<>();
+        // 获取试题关联的多组属性
+        List<QuesProperty> quesProperties = question.getQuesProperties();
+        if (quesProperties != null && quesProperties.size() > 0) {
+            for (QuesProperty quesProperty : quesProperties) {
+                if (quesProperty.getSecondProperty() != null) {
+                    // 有一级 和 二级
+                    if (quesProperty.getSecondProperty().getId() == null
+                            || StringUtils.isBlank(String.valueOf(quesProperty.getSecondProperty().getId()))) {
+                        propertyGroup = String.valueOf(quesProperty.getFirstProperty().getId()) + "-"
+                                + String.valueOf(question.getPublicity()) + "-" + question.getDifficulty();
+                    } else {
+                        propertyGroup = String.valueOf(quesProperty.getFirstProperty().getId()) + "-"
+                                + String.valueOf(quesProperty.getSecondProperty().getId()) + "-"
+                                + String.valueOf(question.getPublicity()) + "-" + question.getDifficulty();
+                    }
+                    propertyGroups.add(propertyGroup);
+                } else {
+                    // 有一级 无 二级
+                    propertyGroup = String.valueOf(quesProperty.getFirstProperty().getId()) + "-"
+                            + String.valueOf(question.getPublicity()) + "-" + question.getDifficulty();
+                    propertyGroups.add(propertyGroup);
+                }
+            }
+            return propertyGroups;
+        }
+        return null;
+    }
+
+    @Transactional
+    @Override
+    public StructInfo saveRandomPaper(RandomPaperDomain domain) {
+        if (domain.getCourseId() == null) {
+            throw new StatusException("课程id不能为空");
+        }
+        if (StringUtils.isBlank(domain.getName())) {
+            throw new StatusException("模板名称不能为空");
+        }
+        if (domain.getPaperStructType() == null) {
+            throw new StatusException("组卷模式不能为空");
+        }
+        if (domain.getPaperStructId() == null) {
+            throw new StatusException("组卷结构不能为空");
+        }
+        if (domain.getPaperType() == null) {
+            throw new StatusException("题源范围不能为空");
+        }
+        if (CollectionUtils.isEmpty(domain.getPaperIds())) {
+            throw new StatusException("试卷id不能为空");
+        }
+        RandomPaper rp = randomPaperRepo.findByRootOrgIdAndName(domain.getRootOrgId(), domain.getName());
+        if (rp != null && !rp.getId().equals(domain.getId())) {
+            throw new StatusException("模板名称已存在");
+        }
+        StructInfo ret = getPaperQuestionInfo(domain.getPaperStructId(), domain.getPaperIds());
+        if (ret.getValid()) {
+            RandomPaper e;
+            if (StringUtils.isNotBlank(domain.getId())) {
+                e = Model.of(randomPaperRepo.findById(domain.getId()));
+            } else {
+                e = new RandomPaper();
+                e.setCourseId(domain.getCourseId());
+                e.setEnable(true);
+                e.setRootOrgId(domain.getRootOrgId());
+            }
+            e.setName(domain.getName());
+            e.setPaperIds(domain.getPaperIds());
+            e.setPaperStructType(domain.getPaperStructType());
+            e.setPaperStructId(domain.getPaperStructId());
+            e.setPaperType(domain.getPaperType());
+            randomPaperRepo.save(e);
+            randomPaperQuestionRepo.deleteByRandomPaperId(e.getId());
+            List<RandomPaperQuestion> rqs = new ArrayList<>();
+            for (StructQuestionInfo si : ret.getStructQuestionInfo()) {
+                for (RandomPaperQuestionDto dto : si.getHardInfo().getQuestionInfo()) {
+                    addRqs(rqs, dto, e);
+                }
+                for (RandomPaperQuestionDto dto : si.getMediumInfo().getQuestionInfo()) {
+                    addRqs(rqs, dto, e);
+                }
+                for (RandomPaperQuestionDto dto : si.getEasyInfo().getQuestionInfo()) {
+                    addRqs(rqs, dto, e);
+                }
+            }
+            randomPaperQuestionRepo.saveAll(rqs);
+            String key = CacheConstants.CACHE_Q_RANDOM_PAPER + e.getId();
+            redisClient.delete(key);
+        }
+        clearQuestionIds(ret);
+        return ret;
+    }
+
+    private void addRqs(List<RandomPaperQuestion> rqs, RandomPaperQuestionDto dto, RandomPaper e) {
+        if (CollectionUtils.isNotEmpty(dto.getQuestionDtos())) {
+            for (QuestionDto qdto : dto.getQuestionDtos()) {
+                RandomPaperQuestion rq = new RandomPaperQuestion();
+                rqs.add(rq);
+                rq.setCourseId(e.getCourseId());
+                rq.setKey(dto.getDetailNumber() + "-" + dto.getKey());
+                rq.setQuestionId(qdto.getId());
+                rq.setRandomPaperId(e.getId());
+                rq.setRootOrgId(e.getRootOrgId());
+                rq.setScore(dto.getUnitScore());
+                rq.setQuestionType(qdto.getQuestionType());
+                rq.setAnswerType(qdto.getAnswerType());
+                if (CollectionUtils.isNotEmpty(qdto.getQuesOptions())) {
+                    rq.setOptionCount(qdto.getQuesOptions().size());
+                }
+                if (QuesStructType.NESTED_ANSWER_QUESTION.equals(rq.getQuestionType())
+                        && CollectionUtils.isNotEmpty(qdto.getSubQuestions())) {
+                    List<RandomPaperQuestion> subQuestion = new ArrayList<>();
+                    rq.setSubQuestions(subQuestion);
+                    List<Double> subScores = getSubScoreList(rq.getScore(), qdto.getSubQuestions().size());
+                    int i = 0;
+                    for (QuestionDto subQd : qdto.getSubQuestions()) {
+                        RandomPaperQuestion subrq = new RandomPaperQuestion();
+                        subQuestion.add(subrq);
+                        subrq.setCourseId(e.getCourseId());
+                        subrq.setScore(subScores.get(i));
+                        i++;
+                        subrq.setQuestionType(subQd.getQuestionType());
+                        subrq.setAnswerType(subQd.getAnswerType());
+                        if (CollectionUtils.isNotEmpty(subQd.getQuesOptions())) {
+                            subrq.setOptionCount(subQd.getQuesOptions().size());
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private List<Double> getSubScoreList(double totalScore, int count) {
+        List<Double> scoreList = new ArrayList<>();
+        if (count > 0) {
+            int baseScore = (int) (totalScore / count);
+            double leftScore = totalScore;
+            for (int i = 0; i < count; i++) {
+                scoreList.add((double) baseScore);
+                leftScore -= baseScore;
+            }
+            if (leftScore > 0) {
+                scoreList.set(count - 1, baseScore + leftScore);
+            }
+            return scoreList;
+        }
+        return null;
+    }
+
+    @Override
+    public RandomPaperListVo getInfo(String id) {
+        RandomPaperListVo vo = this.mongoTemplate.findById(id, RandomPaperListVo.class, "randomPaper");
+        CourseCacheBean course = CacheHelper.getCourse(vo.getCourseId());
+        vo.setCourseCode(course.getCode());
+        vo.setCourseName(course.getName());
+        vo.setPaperStructTypeStr(vo.getPaperStructType().getName());
+        PaperStruct paperStruct = Model.of(paperStructRepo.findById(vo.getPaperStructId()));
+        vo.setPaperStructName(paperStruct.getName());
+        vo.setEnableStr(vo.getEnable() ? "启用" : "禁用");
+        GetUserReq ureq = new GetUserReq();
+        ureq.setUserId(vo.getUpdateBy());
+        GetUserResp ures = userCloudService.getUser(ureq);
+        vo.setUpdateByName(ures.getUserBean().getDisplayName());
+        Query query = new Query();
+        List<Object> ids = new ArrayList<>();
+        for (String pid : vo.getPaperIds()) {
+            if (pid.length() > 24) {
+                ids.add(pid);
+            } else {
+                ids.add(new ObjectId(pid));
+            }
+        }
+        query.addCriteria(Criteria.where("id").in(ids));
+        List<PaperVo> papers = this.mongoTemplate.find(query, PaperVo.class, "paper");
+        vo.setPapers(papers);
+        return vo;
+    }
+
+    @Override
+    public DefaultPaper getRandomPaper(String randomPaperId, Integer playTime) {
+        log.warn("开始抽卷");
+        long d1 = System.currentTimeMillis();
+        RandomPaperCache rp = getByCache(randomPaperId);
+        long d2 = System.currentTimeMillis();
+        log.warn("获取抽卷模板耗时(ms):" + (d2 - d1));
+        PaperStruct ps = paperStructService.getByCache(rp.getPaperStructId());
+        long d3 = System.currentTimeMillis();
+        log.warn("获取组卷结构耗时(ms):" + (d3 - d2));
+        CreateDefaultPaperParam param = new CreateDefaultPaperParam();
+        param.setFullyObjective(true);
+        param.setRp(rp);
+        param.setPlayTime(playTime);
+        DefaultPaper paper = new DefaultPaper();
+        paper.setName(rp.getName());
+        List<DefaultQuestionGroup> details = new ArrayList<>();
+        paper.setQuestionGroupList(details);
+        if (PaperStructType.BLUEPRINT.equals(ps.getPaperStrucType())) {
+            if (CollectionUtils.isNotEmpty(ps.getPaperDetailStructs())) {
+                int detailNumber = 0;
+                for (PaperDetailStruct ds : ps.getPaperDetailStructs()) {
+                    long f1 = System.currentTimeMillis();
+                    DefaultQuestionGroup detail = new DefaultQuestionGroup();
+                    details.add(detail);
+                    detail.setGroupName(ds.getName());
+                    detail.setGroupScore(ds.getTotalScore());
+                    List<DefaultQuestionStructureWrapper> units = new ArrayList<>();
+                    detail.setQuestionWrapperList(units);
+                    detailNumber++;
+                    param.setUnits(units);
+                    param.setDetailNumber(detailNumber);
+                    for (CoursePropertyNumberDto cp : ds.getCoursePropertyNumberDtos()) {
+                        if (!cp.getDisable()) {
+                            param.setCp(cp);
+                            createUnitByBlueProp(param);
+                        }
+                    }
+                    long f2 = System.currentTimeMillis();
+                    log.warn("蓝图抽卷一个大题耗时(ms):" + (f2 - f1));
+                }
+            }
+            long d4 = System.currentTimeMillis();
+            log.warn("蓝图抽卷耗时(ms):" + (d4 - d3));
+        } else if (PaperStructType.EXACT.equals(ps.getPaperStrucType())) {
+            if (CollectionUtils.isNotEmpty(ps.getPaperDetailStructs())) {
+                int detailNumber = 0;
+                for (PaperDetailStruct ds : ps.getPaperDetailStructs()) {
+                    long f1 = System.currentTimeMillis();
+                    DefaultQuestionGroup detail = new DefaultQuestionGroup();
+                    details.add(detail);
+                    detail.setGroupName(ds.getName());
+                    detail.setGroupScore(ds.getTotalScore());
+                    List<DefaultQuestionStructureWrapper> units = new ArrayList<>();
+                    detail.setQuestionWrapperList(units);
+                    detailNumber++;
+                    param.setUnits(units);
+                    param.setDetailNumber(detailNumber);
+                    int index = 0;
+                    for (PaperDetailUnitStructDto us : ds.getUnitStructs()) {
+                        index++;
+                        param.setIndex(index);
+                        param.setUs(us);
+                        createUnitByExact(param);
+                    }
+                    long f2 = System.currentTimeMillis();
+                    log.warn("精确抽卷一个大题耗时(ms):" + (f2 - f1));
+                }
+            }
+            long d4 = System.currentTimeMillis();
+            log.warn("精确抽卷耗时(ms):" + (d4 - d3));
+        }
+        paper.setFullyObjective(param.getFullyObjective());
+        log.warn("结束抽卷");
+        return paper;
+    }
+
+    private void createUnitByExact(CreateDefaultPaperParam param) {
+        PaperDetailUnitStructDto us = param.getUs();
+        if (us.getNoPublicDifficulty() > 0) {
+            param.setUnitCount(us.getNoPublicDifficulty());
+            String key = param.getDetailNumber() + "-" + param.getIndex() + "-" + false + "-"
+                    + QuestionDifficulty.HARD.getName();
+            param.setKey(key);
+            createUnit(param);
+        }
+        if (us.getPublicDifficulty() > 0) {
+            param.setUnitCount(us.getPublicDifficulty());
+            String key = param.getDetailNumber() + "-" + param.getIndex() + "-" + true + "-"
+                    + QuestionDifficulty.HARD.getName();
+            param.setKey(key);
+            createUnit(param);
+        }
+
+        if (us.getNoPublicMedium() > 0) {
+            param.setUnitCount(us.getNoPublicMedium());
+            String key = param.getDetailNumber() + "-" + param.getIndex() + "-" + false + "-"
+                    + QuestionDifficulty.MEDIUM.getName();
+            param.setKey(key);
+            createUnit(param);
+        }
+        if (us.getPublicMedium() > 0) {
+            param.setUnitCount(us.getPublicMedium());
+            String key = param.getDetailNumber() + "-" + param.getIndex() + "-" + true + "-"
+                    + QuestionDifficulty.MEDIUM.getName();
+            param.setKey(key);
+            createUnit(param);
+        }
+        if (us.getNoPublicSimple() > 0) {
+            param.setUnitCount(us.getNoPublicSimple());
+            String key = param.getDetailNumber() + "-" + param.getIndex() + "-" + false + "-"
+                    + QuestionDifficulty.EASY.getName();
+            param.setKey(key);
+            createUnit(param);
+        }
+        if (us.getPublicSimple() > 0) {
+            param.setUnitCount(us.getPublicSimple());
+            String key = param.getDetailNumber() + "-" + param.getIndex() + "-" + true + "-"
+                    + QuestionDifficulty.EASY.getName();
+            param.setKey(key);
+            createUnit(param);
+        }
+    }
+
+    private void createUnitByBlueProp(CreateDefaultPaperParam param) {
+        CoursePropertyNumberDto cp = param.getCp();
+        if (cp.getNoPublicDifficulty() > 0) {
+            String key = param.getDetailNumber() + "-" + bulidPropertyGroupByBlueStruct(cp.getPropertyParentId(),
+                    cp.getPropertyId(), false, QuestionDifficulty.HARD.getName());
+            param.setKey(key);
+            param.setUnitCount(cp.getNoPublicDifficulty());
+            createUnit(param);
+        }
+        if (cp.getPublicDifficulty() > 0) {
+            String key = param.getDetailNumber() + "-" + bulidPropertyGroupByBlueStruct(cp.getPropertyParentId(),
+                    cp.getPropertyId(), true, QuestionDifficulty.HARD.getName());
+            param.setKey(key);
+            param.setUnitCount(cp.getPublicDifficulty());
+            createUnit(param);
+        }
+
+        if (cp.getNoPublicMedium() > 0) {
+            String key = param.getDetailNumber() + "-" + bulidPropertyGroupByBlueStruct(cp.getPropertyParentId(),
+                    cp.getPropertyId(), false, QuestionDifficulty.MEDIUM.getName());
+            param.setKey(key);
+            param.setUnitCount(cp.getNoPublicMedium());
+            createUnit(param);
+        }
+        if (cp.getPublicMedium() > 0) {
+            String key = param.getDetailNumber() + "-" + bulidPropertyGroupByBlueStruct(cp.getPropertyParentId(),
+                    cp.getPropertyId(), true, QuestionDifficulty.MEDIUM.getName());
+            param.setKey(key);
+            param.setUnitCount(cp.getPublicMedium());
+            createUnit(param);
+        }
+        if (cp.getNoPublicSimple() > 0) {
+            String key = param.getDetailNumber() + "-" + bulidPropertyGroupByBlueStruct(cp.getPropertyParentId(),
+                    cp.getPropertyId(), false, QuestionDifficulty.EASY.getName());
+            param.setKey(key);
+            param.setUnitCount(cp.getNoPublicSimple());
+            createUnit(param);
+        }
+        if (cp.getPublicSimple() > 0) {
+            String key = param.getDetailNumber() + "-" + bulidPropertyGroupByBlueStruct(cp.getPropertyParentId(),
+                    cp.getPropertyId(), true, QuestionDifficulty.EASY.getName());
+            param.setKey(key);
+            param.setUnitCount(cp.getPublicSimple());
+            createUnit(param);
+        }
+    }
+
+    private void createUnit(CreateDefaultPaperParam param) {
+        List<RandomPaperQuestion> rpqs = param.getRp().getQuestionMap().get(param.getKey());
+        Collections.shuffle(rpqs);
+        for (int i = 0; i < param.getUnitCount(); i++) {
+            RandomPaperQuestion rpq = rpqs.get(i);
+            DefaultQuestionStructureWrapper qw = new DefaultQuestionStructureWrapper();
+            param.getUnits().add(qw);
+            qw.setLimitedPlayTimes(param.getPlayTime());
+            qw.setPlayedTimes(0);
+            qw.setQuestionId(rpq.getQuestionId());
+            qw.setQuestionScore(rpq.getScore());
+            List<DefaultQuestionUnitWrapper> qList = new ArrayList<>();
+            qw.setQuestionUnitWrapperList(qList);
+            if (QuesStructType.NESTED_ANSWER_QUESTION.equals(rpq.getQuestionType())) {
+                for (RandomPaperQuestion sub : rpq.getSubQuestions()) {
+                    DefaultQuestionUnitWrapper q = new DefaultQuestionUnitWrapper();
+                    qList.add(q);
+                    q.setAnswerType(sub.getAnswerType());
+                    q.setOptionPermutation(getOption(sub.getOptionCount()));
+                    q.setQuestionScore(sub.getScore());
+                    q.setQuestionType(getByOldType(sub.getQuestionType()));
+                    if (!PaperUtil.isObjecttive(sub.getQuestionType())) {
+                        param.setFullyObjective(false);
+                    }
+                }
+            } else {
+                DefaultQuestionUnitWrapper q = new DefaultQuestionUnitWrapper();
+                qList.add(q);
+                q.setAnswerType(rpq.getAnswerType());
+                q.setOptionPermutation(getOption(rpq.getOptionCount()));
+                q.setQuestionScore(rpq.getScore());
+                q.setQuestionType(getByOldType(rpq.getQuestionType()));
+                if (!PaperUtil.isObjecttive(rpq.getQuestionType())) {
+                    param.setFullyObjective(false);
+                }
+            }
+        }
+    }
+
+    private QuestionType getByOldType(QuesStructType quesStructType) {
+        if (quesStructType == QuesStructType.BOOL_ANSWER_QUESTION) {
+            return QuestionType.TRUE_OR_FALSE;
+        }
+        if (quesStructType == QuesStructType.FILL_BLANK_QUESTION) {
+            return QuestionType.FILL_UP;
+        }
+        if (quesStructType == QuesStructType.MULTIPLE_ANSWER_QUESTION) {
+            return QuestionType.MULTIPLE_CHOICE;
+        }
+        if (quesStructType == QuesStructType.SINGLE_ANSWER_QUESTION) {
+            return QuestionType.SINGLE_CHOICE;
+        }
+        if (quesStructType == QuesStructType.TEXT_ANSWER_QUESTION) {
+            return QuestionType.ESSAY;
+        }
+        return null;
+    }
+
+    private Integer[] getOption(Integer count) {
+        if (count == null) {
+            return null;
+        }
+        Integer[] ret = new Integer[count];
+        for (int i = 0; i < count; i++) {
+            ret[i] = i;
+        }
+        return ret;
+    }
+
+    private RandomPaperCache getByCache(String id) {
+        String key = CacheConstants.CACHE_Q_RANDOM_PAPER + id;
+        RandomPaperCache rp = redisClient.get(key, RandomPaperCache.class, cacheTimeOut);
+        if (rp == null) {
+            rp = new RandomPaperCache();
+            RandomPaper e = Model.of(randomPaperRepo.findById(id));
+            if (e == null) {
+                throw new StatusException("未找到随机模板:" + id);
+            }
+            rp.setName(e.getName());
+            rp.setPaperStructId(e.getPaperStructId());
+            List<RandomPaperQuestion> rpqs = randomPaperQuestionRepo.findByRandomPaperId(id);
+            if (CollectionUtils.isEmpty(rpqs)) {
+                throw new StatusException("随机模板试题库为空:" + id);
+            }
+            Map<String, List<RandomPaperQuestion>> map = new HashMap<>();
+            for (RandomPaperQuestion rpq : rpqs) {
+                List<RandomPaperQuestion> list = map.get(rpq.getKey());
+                if (list == null) {
+                    list = new ArrayList<>();
+                    map.put(rpq.getKey(), list);
+                }
+                list.add(rpq);
+            }
+            rp.setQuestionMap(map);
+            redisClient.set(key, rp, cacheTimeOut);
+        }
+        return rp;
+    }
+
+    @Override
+    public boolean existStruct(String paperStructId) {
+        Query query = new Query();
+        query.addCriteria(Criteria.where("paperStructId").is(paperStructId));
+        RandomPaper rp = mongoTemplate.findOne(query, RandomPaper.class);
+        return rp != null;
+    }
+
+    @Override
+    public boolean existPaper(Long courseId, String paperId) {
+        Query query = new Query();
+        query.addCriteria(Criteria.where("courseId").is(courseId));
+        List<RandomPaper> rps = mongoTemplate.find(query, RandomPaper.class);
+        if (CollectionUtils.isEmpty(rps)) {
+            return false;
+        }
+        for (RandomPaper rp : rps) {
+            if (rp.getPaperIds().contains(paperId)) {
+                return true;
+            }
+        }
+        return false;
+    }
 
 }