123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685 |
- package com.qxgmat.service.extend;
- import com.alibaba.fastjson.JSONObject;
- import com.github.pagehelper.Page;
- import com.nuliji.tools.AbstractService;
- import com.nuliji.tools.PageResult;
- import com.nuliji.tools.Tools;
- import com.nuliji.tools.Transform;
- import com.nuliji.tools.exception.ParameterException;
- import com.nuliji.tools.exception.SystemException;
- import com.qxgmat.data.constants.enums.QuestionSubject;
- import com.qxgmat.data.constants.enums.QuestionType;
- import com.qxgmat.data.constants.enums.ServiceKey;
- import com.qxgmat.data.constants.enums.module.PaperOrigin;
- import com.qxgmat.data.constants.enums.status.DirectionStatus;
- import com.qxgmat.data.dao.entity.*;
- import com.qxgmat.data.relation.ExaminationPaperRelationMapper;
- import com.qxgmat.data.relation.QuestionNoRelationMapper;
- import com.qxgmat.data.relation.UserPaperRelationMapper;
- import com.qxgmat.data.relation.UserReportRelationMapper;
- import com.qxgmat.data.relation.entity.QuestionDifficultRelation;
- import com.qxgmat.data.relation.entity.QuestionNoRelation;
- import com.qxgmat.service.UserPaperService;
- import com.qxgmat.service.UsersService;
- import com.qxgmat.service.inline.*;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Transactional;
- import javax.annotation.Resource;
- import java.util.*;
- @Service
- public class ExaminationService extends AbstractService {
- private static Random rand = new Random();
- @Resource
- private QuestionService questionService;
- @Resource
- private QuestionNoService questionNoService;
- @Resource
- private QuestionNoRelationMapper questionNoRelationMapper;
- @Resource
- private ExaminationStructService examinationStructService;
- @Resource
- private ExaminationPaperService examinationPaperService;
- @Resource
- private UserPaperRelationMapper userPaperRelationMapper;
- @Resource
- private UserPaperService userPaperService;
- @Resource
- private UserReportRelationMapper userReportRelationMapper;
- @Resource
- private UserReportService userReportService;
- @Resource
- private UsersService usersService;
- @Resource
- private ExaminationPaperRelationMapper examinationPaperRelationMapper;
- /**
- * verbal考试相关设置
- */
- final public Integer verbalMaxLevel = 27;
- final public Integer verbalMinLevel = 9;
- final public Integer verbalInitLevel = 13;
- final public Integer verbalPre = 9;
- final public Integer verbalSC = 14;
- final public Integer verbalCR = 9;
- final public Integer verbalRC = 13;
- // 出RC阅读题的题号
- final public Integer[] verbalRCPosition = new Integer[]{5, 15, 24, 33};
- /**
- * quant考试相关设置
- */
- final public Integer[] quantBaseLevel = new Integer[]{8, 8, 8, 7};
- // 阶段的最大题目数
- final public Integer[] quantNumber = new Integer[]{0, 8, 16, 24, 31};
- final public Integer quantMinRatio = 1;
- final public Integer quantMaxRatio = 3;
- final public Integer quantInitLevel = 11;
- final public Integer quantPS = 17;
- final public Integer quantDS = 14;
- /**
- * 根据第三层结构建立paper
- * @param entity
- * @return
- */
- @Transactional
- public ExaminationStruct addPaper(ExaminationStruct entity){
- entity = examinationStructService.add(entity);
- if (entity.getLevel() == 3){
- // 添加2份paper
- ExaminationPaper paper = examinationPaperService.add(ExaminationPaper.builder()
- .isAdapt(entity.getIsAdapt())
- .structTwo(entity.getParentId())
- .structThree(entity.getId())
- .title(entity.getTitleZh())
- .build()
- );
- }
- return entity;
- }
- @Transactional
- public ExaminationStruct editPaper(ExaminationStruct entity){
- entity = examinationStructService.edit(entity);
- if (entity.getLevel() == 3){
- ExaminationPaper paper = examinationPaperService.getByThree(entity.getId());
- if(paper == null){
- paper = examinationPaperService.add(ExaminationPaper.builder()
- .isAdapt(entity.getIsAdapt())
- .structTwo(entity.getParentId())
- .structThree(entity.getId())
- .title(entity.getTitleZh())
- .build()
- );
- }else{
- examinationPaperService.edit(ExaminationPaper.builder()
- .id(paper.getId())
- .isAdapt(entity.getIsAdapt())
- .structTwo(entity.getParentId())
- .structThree(entity.getId())
- .title(entity.getTitleZh())
- .build()
- );
- }
- }
- return entity;
- }
- @Transactional
- public Boolean deletePaper(Integer id){
- Boolean result = examinationStructService.delete(id);
- ExaminationPaper paper = examinationPaperService.getByThree(id);
- if(paper != null){
- examinationPaperService.delete(paper.getId());
- }
- return result;
- }
- private Map<String, String> adminMap = new HashMap<String, String>(){{
- put("updateTime", "q");
- put("", "qn");
- }};
- /**
- *
- * @param page
- * @param pageSize
- * @param questionType
- * @param structId
- * @param questionNo
- * @param paperId
- * @param place
- * @param difficult
- * @param order
- * @param direction
- * @return
- */
- public Page<QuestionNoRelation> listAdmin(int page, int pageSize, String questionType, Number structId, Number questionNo, Number paperId, String place, String difficult, String order, DirectionStatus direction){
- if(order == null || order.isEmpty()){
- order = "id";
- }
- if(adminMap.containsKey(order)){
- order = adminMap.get(order)+".`"+Tools.underscoreName(order)+"`";
- }else{
- order = adminMap.get("")+".`"+Tools.underscoreName(order)+"`";
- }
- if (direction == null){
- direction = DirectionStatus.DESC;
- }
- String finalOrder = order;
- DirectionStatus finalDirection = direction;
- Page<QuestionNoRelation> p = page(() -> {
- questionNoRelationMapper.listExaminationAdmin(questionType, structId, questionNo, paperId, place, difficult, finalOrder, finalDirection.key);
- }, page, pageSize);
- Collection ids = Transform.getIds(p, QuestionNoRelation.class, "id");
- // 获取详细数据
- List<QuestionNoRelation> list = questionNoService.relation(questionNoService.select(ids));
- Transform.replace(p, list, QuestionNoRelation.class, "id");
- return p;
- }
- /**
- * 查找模考组卷
- * @param page
- * @param size
- * @param structId
- * @param userId
- * @param times
- * @return
- */
- public PageResult<ExaminationPaper> list(int page, int size, Number structId, Number userId, Integer qxCatNo, Integer times){
- Page<ExaminationPaper> p = page(()->{
- examinationPaperRelationMapper.listWithUser(structId, userId, qxCatNo, times);
- },page, size);
- Collection ids = Transform.getIds(p, ExaminationPaper.class, "id");
- // 获取详细数据
- List<ExaminationPaper> list = examinationPaperService.select(ids);
- return new PageResult<>(list, p.getTotal());
- }
- /**
- * cat模考是否已经完成
- * @param userId
- * @return
- */
- public boolean isFinishCat(Integer userId){
- ExaminationStruct struct = getCat();
- List<ExaminationPaper> paperList = examinationPaperService.listByTwo(struct.getId());
- Collection ids = Transform.getIds(paperList, ExaminationPaper.class, "id");
- List<UserPaper> userPaperList = userPaperService.listWithOrigin(userId, PaperOrigin.EXAMINATION, ids, null);
- if (paperList.size() != userPaperList.size()){
- return false;
- }
- Collection paperIds = Transform.getIds(userPaperList, UserPaper.class, "id");
- List<UserReport> reportList = userReportService.listWithLast(paperIds);
- for(UserReport report: reportList){
- if(report.getIsFinish() == 0){
- return false;
- }
- }
- return true;
- }
- /**
- * 重置Cat模考系列
- * @param userId
- * @return
- */
- @Transactional
- public Boolean resetCat(Integer userId, boolean force){
- ExaminationStruct struct = getCat();
- List<ExaminationPaper> paperList = examinationPaperService.listByTwo(struct.getId());
- Collection ids = Transform.getIds(paperList, ExaminationPaper.class, "id");
- List<UserPaper> userPaperList = userPaperService.listWithOrigin(userId, PaperOrigin.EXAMINATION, ids, null);
- if (!force && paperList.size() != userPaperList.size()){
- throw new ParameterException("未完成所有");
- }
- Collection paperIds = Transform.getIds(userPaperList, UserPaper.class, "id");
- if(!force){
- List<UserReport> reportList = userReportService.listWithLast(paperIds);
- for(UserReport report: reportList){
- if(report.getIsFinish() == 0){
- throw new ParameterException("未完成所有");
- }
- }
- }
- // 增加用户cat计数
- User user = usersService.get(userId);
- usersService.edit(User.builder().id(userId).qxCat(user.getQxCat() + 1).build());
- return userPaperService.reset(paperIds, userId);
- }
- public ExaminationStruct getCat(){
- List<ExaminationStruct> list = examinationStructService.main();
- for (ExaminationStruct struct : list){
- if (struct.getLevel() == 1) continue;
- if (struct.getExtend().equals(ServiceKey.QX_CAT.key)) return struct;
- }
- throw new SystemException("没有找到cat模考节点");
- }
- public boolean isCat(ExaminationPaper paper){
- ExaminationStruct struct = examinationStructService.get(paper.getStructTwo());
- return struct.getExtend().equals(ServiceKey.QX_CAT.key);
- }
- /**
- * 获取下一阶段难度分
- * @param currentLevel
- * @param number
- * @param correct
- * @return
- */
- public Integer verbalNextLevel(Integer currentLevel, Integer number, long correct){
- long correctRate = correct * 100 / number;
- if (correctRate < 60){
- currentLevel -= 5;
- if (currentLevel < verbalMinLevel) return verbalMinLevel;
- }else if(correctRate > 80){
- currentLevel += 5;
- if (currentLevel > verbalMaxLevel) return verbalMaxLevel;
- }
- return currentLevel;
- }
- /**
- * 获取下一阶段难度分
- * @param currentLevel
- * @param number
- * @param correct
- * @param step
- * @return
- */
- public Integer quantNextLevel(Integer currentLevel, Integer number, long correct, Integer step){
- long correctRate = correct * 100 / number;
- Integer max = quantMaxRatio * quantBaseLevel[step];
- Integer min = quantMinRatio * quantBaseLevel[step];
- if (correctRate < 60){
- currentLevel -= 4;
- if (currentLevel < min) return min;
- }else if(correctRate > 80){
- currentLevel += 4;
- if (currentLevel > max) return max;
- }
- return currentLevel;
- }
- /**
- * 分组统计不同题型的数量
- * @param userQuestionList
- * @return
- */
- public Map<String, Integer> statTypeNumber(List<UserQuestion> userQuestionList){
- Map<String, Integer> result = new HashMap<>();
- for(UserQuestion question : userQuestionList){
- String type = question.getQuestionType();
- if (!result.containsKey(type)){
- result.put(type, 0);
- }
- result.put(type, result.get(type) + 1);
- }
- return result;
- }
- /**
- * 返回还需的题目类型
- * @param typeNumber
- * @param questionTypes
- * @return
- */
- public List<String> needQuestionTypes(Map<String, Integer> typeNumber, List<String> questionTypes){
- List<String> targetTypes = new ArrayList<>();
- for(String type : questionTypes){
- int target = 0;
- switch(type){
- case "sc":
- target = verbalSC;
- break;
- case "cr":
- target = verbalCR;
- break;
- case "rc":
- target = verbalRC;
- break;
- case "ps":
- target = quantPS;
- break;
- case "ds":
- target = quantDS;
- break;
- }
- if (target == 0 || target > typeNumber.get(type)){
- targetTypes.add(type);
- }
- }
- return targetTypes;
- }
- /**
- * 通过当前完成的题目数,判断是否该抽取阅读题
- * @param number
- * @return
- */
- public boolean verbalRC(Integer number){
- for(Integer n : verbalRCPosition){
- if (n == number) return true;
- }
- return false;
- }
- /**
- * 通过当前完成的题目数,判断当前阶段
- * @param number
- * @return
- */
- public Integer quantStep(Integer number) {
- Integer step = 0;
- Integer all = 0;
- for(Integer n : quantBaseLevel){
- all += n;
- if (all >= number) return step;
- step += 1;
- }
- return step;
- }
- /**
- * 初始化第一阶段题目
- * 一篇4题的阅读压轴
- * { "ids": [], "level": 0 }
- * @param structId
- * @return
- */
- public JSONObject initVerbal(Integer structId){
- JSONObject info = new JSONObject();
- Integer[] rcQ = questionNoService.randomExaminationRc(structId, 4, null);
- List<QuestionNoRelation> rcRelationList = questionNoService.listWithRelationByIds(rcQ);
- Integer rcLevel = computeNoLevel(rcRelationList);
- Integer targetLevel = 0;
- Collection types = QuestionType.FromSubject(QuestionSubject.VERBAL);
- List<QuestionDifficultRelation> difficultList = questionNoService.allExaminationByType(structId, types);
- List<QuestionDifficultRelation> selectedList = null;
- do{
- selectedList = randomList(difficultList, verbalPre - 4);
- targetLevel = rcLevel + computeDifficultLevel(selectedList);
- }while(targetLevel >= verbalInitLevel);
- List<Integer> targetIds = new ArrayList<>(verbalPre);
- for(QuestionDifficultRelation relation : selectedList){
- targetIds.add(relation.getId());
- }
- targetIds.addAll(Arrays.asList(rcQ));
- info.put("level", targetLevel);
- info.put("ids", targetIds);
- return info;
- }
- /**
- * 生成下一阶段题目
- * 一篇3题的阅读压轴
- * { "ids": [], "level": 0 }
- * @param structId
- * @param level
- * @param typeNumbers
- * @param ids
- * @return
- */
- public JSONObject generateVerbal(Integer structId, Integer level, Map<String, Integer> typeNumbers, Collection ids){
- JSONObject info = new JSONObject();
- Integer[] rcQ = questionNoService.randomExaminationRc(structId, 3, ids);
- List<QuestionNoRelation> rcRelationList = questionNoService.listWithRelationByIds(rcQ);
- Integer rcLevel = computeNoLevel(rcRelationList);
- Collection types = QuestionType.FromSubject(QuestionSubject.VERBAL);
- List<QuestionDifficultRelation> difficultList = questionNoService.allExaminationByType(structId, types);
- List<QuestionDifficultRelation> selectedList = new ArrayList<>(verbalPre - 3);
- Integer[] levels = generateLevel(level - rcLevel,verbalPre - 3);
- do{
- QuestionDifficultRelation r = random(difficultList, ids, levels[selectedList.size()]);
- int typeNumber = typeNumbers.get(r.getQuestionType()) + 1;
- switch(r.getQuestionType()){
- case "sc":
- if (typeNumber > verbalSC) {
- continue;
- }
- break;
- case "cr":
- if (typeNumber > verbalCR) {
- continue;
- }
- break;
- }
- typeNumbers.put(r.getQuestionType(), typeNumber);
- selectedList.add(r);
- ids.add(r.getId());
- }while(selectedList.size() == verbalPre -3);
- List<Integer> targetIds = new ArrayList<>(verbalPre);
- for(QuestionDifficultRelation relation : selectedList){
- targetIds.add(relation.getId());
- }
- targetIds.addAll(Arrays.asList(rcQ));
- info.put("ids", targetIds);
- info.put("level", level);
- return info;
- }
- /**
- * 初始化第一阶段题目
- * 一篇4题的阅读压轴
- * { "ids": [], "level": 0 }
- * @param structId
- * @return
- */
- public JSONObject initQuant(Integer structId){
- JSONObject info = new JSONObject();
- Integer targetLevel = 0;
- Collection types = QuestionType.FromSubject(QuestionSubject.QUANT);
- Integer number = quantBaseLevel[0];
- List<QuestionDifficultRelation> difficultList = questionNoService.allExaminationByType(structId, types);
- List<QuestionDifficultRelation> selectedList = null;
- do{
- selectedList = randomList(difficultList, number);
- targetLevel = computeDifficultLevel(selectedList);
- }while(targetLevel >= quantInitLevel);
- List<Integer> targetIds = new ArrayList<>(number);
- for(QuestionDifficultRelation relation : selectedList){
- targetIds.add(relation.getId());
- }
- info.put("level", targetLevel);
- info.put("ids", targetIds);
- return info;
- }
- /**
- * 生成下一阶段题目
- * 一篇3题的阅读压轴
- * { "ids": [], "level": 0 }
- * @param structId
- * @param level
- * @param typeNumbers
- * @param ids
- * @return
- */
- public JSONObject generateQuant(Integer structId, Integer level, Map<String, Integer> typeNumbers, Collection ids, Integer step){
- JSONObject info = new JSONObject();
- Collection types = QuestionType.FromSubject(QuestionSubject.QUANT);
- Integer number = quantBaseLevel[step];
- List<QuestionDifficultRelation> difficultList = questionNoService.allExaminationByType(structId, types);
- List<QuestionDifficultRelation> selectedList = null;
- Integer[] levels = generateLevel(level,number);
- do{
- QuestionDifficultRelation r = random(difficultList, ids, levels[selectedList.size()]);
- int typeNumber = typeNumbers.get(r.getQuestionType()) + 1;
- switch(r.getQuestionType()){
- case "ps":
- if (typeNumber > quantPS) {
- continue;
- }
- break;
- case "ds":
- if (typeNumber > quantDS) {
- continue;
- }
- break;
- }
- typeNumbers.put(r.getQuestionType(), typeNumber);
- selectedList.add(r);
- ids.add(r.getId());
- }while(selectedList.size() == number);
- List<Integer> targetIds = new ArrayList<>(number);
- for(QuestionDifficultRelation relation : selectedList){
- targetIds.add(relation.getId());
- }
- info.put("ids", targetIds);
- info.put("level", level);
- return info;
- }
- /**
- * 随机生成对应的题目列表
- * @param all
- * @param size
- * @return
- */
- public List<QuestionDifficultRelation> randomList(List<QuestionDifficultRelation> all, Integer size){
- List<QuestionDifficultRelation> list = new ArrayList<>(size);
- Set<Integer> indexSet = new HashSet<>();
- do{
- int index = rand.nextInt(all.size());
- if (!indexSet.contains(index)){
- QuestionDifficultRelation target = all.get(index);
- list.add(target);
- indexSet.add(index);
- }
- }while(list.size() == size);
- return list;
- }
- /**
- * 随机生成对应的题目
- * @param all
- * @param ids
- * @param level
- * @return
- */
- public QuestionDifficultRelation random(List<QuestionDifficultRelation> all, Collection ids, Integer level){
- String difficult = levelToDifficult(level);
- do{
- int index = rand.nextInt(all.size());
- QuestionDifficultRelation target = all.get(index);
- if (ids == null || !ids.contains(target.getId())){
- if (difficult == null || target.getDifficult().equals(difficult)) return target;
- }
- }while(true);
- }
- /**
- * 计算考题对应的难度分
- * @param relationList
- * @return
- */
- public Integer computeNoLevel(List<QuestionNoRelation> relationList){
- int level = 0;
- for(QuestionNoRelation relation : relationList){
- level += difficultToLevel(relation.getQuestion().getDifficult());
- }
- return level;
- }
- public Integer computeDifficultLevel(List<QuestionDifficultRelation> relationList){
- int level = 0;
- for(QuestionDifficultRelation relation : relationList){
- level += difficultToLevel(relation.getDifficult());
- }
- return level;
- }
- public Integer difficultToLevel(String difficult){
- switch(difficult){
- case "easy":
- return 1;
- case "medium":
- return 2;
- case "hard":
- return 3;
- }
- return 0;
- }
- public String levelToDifficult(Integer level){
- switch(level){
- case 1:
- return "easy";
- case 2:
- return "medium";
- case 3:
- return "hard";
- }
- return null;
- }
- public Integer[] generateLevel(Integer level, Integer number){
- Integer[] levels = new Integer[number];
- int no = 0;
- // 至少有一个可以3分
- if (level > number + 1){
- for(int i = 0; i < number; i++){
- int n = rand.nextInt(2) + 2; // 随机2-3
- levels[i] = n;
- level -= n;
- no += 1;
- // 只能还有一个2分
- if (level == number - no + 1){
- break;
- }
- }
- number -= no;
- }
- if(level == number + 1){
- // 只有一个2分
- levels[no] = 2;
- no += 1;
- }
- // 剩余都是1分
- for (int i = 0; i < number; i++) {
- levels[i+no] = 1;
- }
- shuffle(levels);
- return levels;
- }
- public static <T> void swap(T[] a, int i, int j){
- T temp = a[i];
- a[i] = a[j];
- a[j] = temp;
- }
- public static <T> void shuffle(T[] arr) {
- int length = arr.length;
- for ( int i = length; i > 0; i-- ){
- int randInd = rand.nextInt(i);
- swap(arr, randInd, i - 1);
- }
- }
- }
|