package com.qxgmat.service.extend; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.nuliji.tools.Transform; import com.nuliji.tools.exception.ParameterException; import com.qxgmat.data.constants.enums.*; import com.qxgmat.data.constants.enums.module.*; import com.qxgmat.data.dao.entity.*; import com.qxgmat.data.relation.entity.*; import com.qxgmat.service.*; import com.qxgmat.service.annotation.*; import com.qxgmat.service.inline.*; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.util.*; import java.util.stream.Collectors; @Service public class QuestionFlowService { @Resource private ExercisePaperService exercisePaperService; @Resource private ExerciseStructService exerciseStructService; @Resource private PreviewService previewService; @Resource private ExaminationPaperService examinationPaperService; @Resource private ExaminationStructService examinationStructService; @Resource private QuestionNoService questionNoService; @Resource private QuestionService questionService; @Resource private CourseService courseService; @Resource private SentenceQuestionService sentenceQuestionService; @Resource private SentencePaperService sentencePaperService; @Resource private TextbookQuestionService textbookQuestionService; @Resource private TextbookLibraryService textbookLibraryService; @Resource private TextbookPaperService textbookPaperService; @Resource private PreviewPaperService previewPaperService; @Resource private PreviewAssignService previewAssignService; @Resource private UsersService usersService; @Resource private UserReportService userReportService; @Resource private UserPaperService userPaperService; @Resource private UserPaperQuestionService userPaperQuestionService; @Resource private UserQuestionService userQuestionService; @Resource private UserServiceService userServiceService; @Resource private UserCourseAppointmentService userCourseAppointmentService; @Resource private ExaminationService examinationService; @Resource private CourseExtendService courseExtendService; @Resource private ToolsService toolsService; @Resource private MessageExtendService messageExtendService; // 自由组卷初始化试卷callback private Map makePaperCallback = new HashMap<>(); // 初始化试卷的callback,根据试卷模块进行后续处理 private Map initPaperCallback = new HashMap<>(); // 初始化试卷的callback,根据试卷来源进行后续处理 private Map initOriginPaperCallback = new HashMap<>(); // 重置试卷的callback,根据试卷模块进行后续处理 private Map resetPaperCallback = new HashMap<>(); // 初始化报告的callback,根据试卷模块进行后续处理 private Map initReportCallback = new HashMap<>(); // 初始化题目,根据试卷模块进行选题处理 private Map nextCallback = new HashMap<>(); // 提交答题的callback,根据试题模块正确判断 private Map submitCallback = new HashMap<>(); // 提交答题的callback,根据试题模块后续统计,会过滤满足剔除条件 private Map submitAfterCallback = new HashMap<>(); // 完成试卷的callback,根据试卷模块进行后续处理 private Map finishCallback = new HashMap<>(); private Map finishAfterCallback = new HashMap<>(); public QuestionFlowService(){ makePaperCallback.put(QuestionModule.BASE, (userPaper, id)->{ // 获取考题时间 List relationList = questionNoService.listWithRelationByIds(userPaper.getQuestionNoIds()); Integer time = toolsService.computerTime(relationList.toArray(new QuestionNoRelation[0])); userPaper.setTime(time); return userPaper; }); makePaperCallback.put(QuestionModule.SENTENCE, (userPaper, id)->{ // 获取考题时间 List relationList = sentenceQuestionService.relation(sentenceQuestionService.listByQuestionNo(Arrays.stream(userPaper.getQuestionNoIds()).collect(Collectors.toList()))); Integer time = toolsService.computerTime(relationList.toArray(new SentenceQuestionRelation[0])); userPaper.setTime(time); return userPaper; }); makePaperCallback.put(QuestionModule.TEXTBOOK, (userPaper, id)->{ // 获取考题时间 List relationList = textbookQuestionService.relation(textbookQuestionService.listByQuestionNo(Arrays.stream(userPaper.getQuestionNoIds()).collect(Collectors.toList()))); Integer time = toolsService.computerTime(relationList.toArray(new TextbookQuestionRelation[0])); userPaper.setTime(time); return userPaper; }); initOriginPaperCallback.put(PaperOrigin.PREVIEW, (userPaper, id)->{ // id为分配表,找寻对应的paper PreviewAssign assign = previewAssignService.get(id); PreviewPaper paper = previewPaperService.get(assign.getPaperId()); // 根据不同课程处理标题信息 CourseModule courseModule = CourseModule.ValueOf(assign.getCourseModule()); switch(courseModule){ case VIDEO: case ONLINE: userPaper.setTitle(paper.getTitle()); case VS: userPaper.setTitle(assign.getTitle()); } // 新paper绑定当前记录关系 if (userPaper.getRecordId() == 0){ // 获取用户当前课程记录 Integer recordId = previewService.getRecord(userPaper.getUserId(), id); userPaper.setRecordId(recordId); } userPaper.setQuestionNoIds(paper.getQuestionNoIds()); // 根据papermodule得到考试时长 QuestionModule module = QuestionModule.WithPaper(PaperModule.ValueOf(paper.getPaperModule())); InitPaper callback = makePaperCallback.get(module); return callback.callback(userPaper, id); }); initPaperCallback.put(PaperModule.EXERCISE, (userPaper, id)->{ ExercisePaper paper = exercisePaperService.get(id); userPaper.setTitle(paper.getTitle()); userPaper.setQuestionNoIds(paper.getQuestionNoIds()); userPaper.setQuestionNumber(paper.getQuestionNumber()); // 获取考题时间 List relationList = questionNoService.listWithRelationByIds(userPaper.getQuestionNoIds()); Integer time = toolsService.computerTime(relationList.toArray(new QuestionNoRelation[0])); userPaper.setTime(time); return userPaper; }); initPaperCallback.put(PaperModule.SENTENCE, (userPaper, id)->{ SentencePaper paper = sentencePaperService.get(id); userPaper.setTitle(paper.getTitle()); userPaper.setQuestionNoIds(paper.getQuestionNoIds()); userPaper.setQuestionNumber(paper.getQuestionNumber()); // 获取考题时间 List relationList = sentenceQuestionService.relation(sentenceQuestionService.listByQuestionNo(Arrays.stream(userPaper.getQuestionNoIds()).collect(Collectors.toList()))); Integer time = toolsService.computerTime(relationList.toArray(new SentenceQuestionRelation[0])); userPaper.setTime(time); return userPaper; }); initPaperCallback.put(PaperModule.TEXTBOOK, (userPaper, id)->{ TextbookPaper paper = textbookPaperService.get(id); userPaper.setTitle(paper.getTitle()); userPaper.setQuestionNoIds(paper.getQuestionNoIds()); userPaper.setQuestionNumber(paper.getQuestionNumber()); // 获取考题时间 List relationList = textbookQuestionService.relation(textbookQuestionService.listByQuestionNo(Arrays.stream(userPaper.getQuestionNoIds()).collect(Collectors.toList()))); Integer time = toolsService.computerTime(relationList.toArray(new TextbookQuestionRelation[0])); userPaper.setTime(time); return userPaper; }); initPaperCallback.put(PaperModule.EXAMINATION, (userPaper, id)->{ ExaminationPaper paper = examinationPaperService.get(id); userPaper.setTitle(paper.getTitle()); userPaper.setIsAdapt(paper.getIsAdapt()); ExaminationPaper examinationPaper = examinationPaperService.get(userPaper.getOriginId()); ExaminationStruct examinationStruct = examinationStructService.get(examinationPaper.getStructThree()); ServiceKey serviceKey = ServiceKey.ValueOf(examinationStruct.getExtend()); if (serviceKey == ServiceKey.QX_CAT) { User user = usersService.get(userPaper.getUserId()); userPaper.setPaperNo(user.getQxCat()); UserService userService = userServiceService.getService(user.getId(), serviceKey); userPaper.setQxCat(userService.getIsReset() + 1); } return userPaper; }); initReportCallback.put(PaperModule.EXERCISE, (report, paper)->{ JSONObject setting = report.getSetting(); if (setting.getBoolean("disorder")){ // 随机试题: 选项随机,前端处理 // report.setQuestionNoIds(this.randomQuestionNoIds(paper.getQuestionNoIds())); } }); initReportCallback.put(PaperModule.SENTENCE, (report, paper)->{ // 无特殊设置 }); initReportCallback.put(PaperModule.TEXTBOOK, (report, paper)->{ // 无特殊设置 }); initReportCallback.put(PaperModule.EXAMINATION, (report, paper)->{ JSONObject setting = report.getSetting(); if (setting.getBoolean("disorder")){ // 随机试题: 选项随机,前端处理 // report.setQuestionNoIds(this.randomQuestionNoIds(paper.getQuestionNoIds())); } JSONArray order = setting.getJSONArray("order"); // 初始化第一阶段 setting.put("stage", order.getString(0)); // 初始化每阶段时间, 以及做题数 JSONObject time = new JSONObject(); JSONObject number = new JSONObject(); for(String stage : order.toJavaList(String.class)){ time.put(stage, 0); number.put(stage, 0); } setting.put("time", time); setting.put("number", number); toolsService.examinationReportInit(report, order); }); resetPaperCallback.put(PaperOrigin.PREVIEW, (userPaper, id)->{ // 重新初始化 InitPaper callback = initOriginPaperCallback.get(PaperOrigin.PREVIEW); return callback.callback(userPaper, id); }); resetPaperCallback.put(PaperOrigin.EXAMINATION, (userPaper, id)->{ // 如果是cat模考 ExaminationPaper examinationPaper = examinationPaperService.get(userPaper.getOriginId()); ExaminationStruct examinationStruct = examinationStructService.get(examinationPaper.getStructThree()); ServiceKey serviceKey = ServiceKey.ValueOf(examinationStruct.getExtend()); if (serviceKey == ServiceKey.QX_CAT){ User user = usersService.get(userPaper.getUserId()); // 创建新的paper UserPaper newPaper = userPaperService.newByPaper(userPaper.getUserId(), PaperOrigin.ValueOf(userPaper.getPaperOrigin()), PaperModule.ValueOf(userPaper.getPaperModule()), userPaper.getOriginId()); newPaper.setIsAdapt(userPaper.getIsAdapt()); newPaper.setTitle(userPaper.getTitle()); newPaper.setPaperNo(user.getQxCat()); UserService userService = userServiceService.getService(user.getId(), serviceKey); newPaper.setQxCat(userService.getIsReset() + 1); } return userPaper; }); nextCallback.put(PaperModule.EXERCISE, (question, report, lastQuestion)->{ Integer questionNoId = this.nextId(report.getQuestionNoIds(), lastQuestion!=null ? lastQuestion.getQuestionNoId():null); if (questionNoId == 0) return false; this.bindQuestionNo(question, questionNoId); // 设定最后一次练习记录 if (PaperOrigin.ValueOf(report.getPaperOrigin()) == PaperOrigin.EXERCISE){ usersService.edit(User.builder().id(question.getUserId()).latestExercise(report.getId()).build()); } return true; }); nextCallback.put(PaperModule.SENTENCE, (question, report, lastQuestion)->{ Integer questionNoId = this.nextId(report.getQuestionNoIds(), lastQuestion!=null ? lastQuestion.getQuestionNoId():null); if (questionNoId == 0) return false; SentenceQuestionRelation relation = sentenceQuestionService.relation(sentenceQuestionService.getByQuestionNo(questionNoId)); question.setQuestionNoId(relation.getQuestionNoId()); question.setQuestionId(relation.getQuestionId()); question.setQuestionType(relation.getQuestion().getQuestionType()); Integer time = toolsService.computerTime(relation); question.setTime(time); return true; }); nextCallback.put(PaperModule.TEXTBOOK, (question, report, lastQuestion)->{ Integer questionNoId = this.nextId(report.getQuestionNoIds(), lastQuestion!=null ? lastQuestion.getQuestionNoId():null); if (questionNoId == 0) return false; TextbookQuestionRelation relation = textbookQuestionService.relation(textbookQuestionService.getByQuestionNo(questionNoId)); question.setQuestionNoId(relation.getQuestionNoId()); question.setQuestionId(relation.getQuestionId()); question.setQuestionType(relation.getQuestion().getQuestionType()); Integer time = toolsService.computerTime(relation); question.setTime(time); return true; }); nextCallback.put(PaperModule.EXAMINATION, (question, report, lastQuestion)->{ ExaminationPaper paper = examinationPaperService.get(report.getOriginId()); if (!examinationCompute(paper, report, lastQuestion, question)){ return false; } // 保存report: 更新setting userReportService.edit(UserReport.builder().id(report.getId()).setting(report.getSetting()).build()); return true; }); submitCallback.put(QuestionModule.BASE, (userQuestion, userReport)->{ // 判断答题情况 JSONObject userAnswer = userQuestion.getUserAnswer(); Question question = questionService.get(userQuestion.getQuestionId()); // 作文统计字数 if (question.getQuestionType().equals(QuestionType.AWA.key)){ JSONObject detail = new JSONObject(); String awa = userAnswer.getString("awa"); String base = awa.replaceAll("/<[^>]+>/g", "") .replaceAll("/[,.+-:;']+/g", ""); detail.put("words", base.split(" ").length); userQuestion.setDetail(detail); return false; } JSONObject answer = question.getAnswer(); return (boolean) this.baseAnswer(userAnswer, answer, question); }); submitCallback.put(QuestionModule.SENTENCE, (userQuestion, userReport)->{ // 判断答题情况 JSONObject userAnswer = userQuestion.getUserAnswer(); Question question = questionService.get(userQuestion.getQuestionId()); JSONObject answer = question.getAnswer(); boolean correct = true; JSONObject detail = new JSONObject(); boolean subjectCorrect = this.sentenceAnswer(userAnswer.getJSONArray("subject"), answer.getJSONArray("subject")); detail.put("subject", subjectCorrect); correct = correct & subjectCorrect; boolean predicateCorrect = this.sentenceAnswer(userAnswer.getJSONArray("predicate"), answer.getJSONArray("predicate")); detail.put("predicate", predicateCorrect); correct = correct & predicateCorrect; boolean objectCorrect = this.sentenceAnswer(userAnswer.getJSONArray("object"), answer.getJSONArray("object")); detail.put("object", objectCorrect); correct = correct & objectCorrect; boolean optionsCorrect = this.sentenceAnswerOption(userAnswer.getJSONArray("options"), answer.getJSONArray("options")); detail.put("options", optionsCorrect); // correct = correct & optionsCorrect; userQuestion.setDetail(detail); // 主谓宾判断正确,答题正确 return correct; }); submitCallback.put(QuestionModule.TEXTBOOK, (userQuestion, userReport)->{ // 判断答题情况 JSONObject userAnswer = userQuestion.getUserAnswer(); Question question = questionService.get(userQuestion.getQuestionId()); JSONObject answer = question.getAnswer(); return this.baseAnswer(userAnswer, answer, question); }); submitAfterCallback.put(QuestionModule.BASE, (userQuestion, question)->{ // 作文不统计 if (question.getQuestionType().equals(QuestionType.AWA.key)){ return; } // 更新题目及题目编号统计 questionNoService.accumulation(userQuestion); questionService.accumulation(userQuestion); // 统计答案分布 this.answerDistributed(userQuestion, question); }); submitAfterCallback.put(QuestionModule.SENTENCE, (userQuestion, question)->{ // 更新题目及长难句统计 questionNoService.accumulation(userQuestion); questionService.accumulation(userQuestion); }); submitAfterCallback.put(QuestionModule.TEXTBOOK, (userQuestion, question)->{ // 更新题目及机经统计 questionNoService.accumulation(userQuestion); questionService.accumulation(userQuestion); this.answerDistributed(userQuestion, question); }); finishCallback.put(PaperModule.EXERCISE, (report, questionList)->{ report.setDetail(this.statExerciseReport(report, questionList)); }); finishCallback.put(PaperModule.SENTENCE, (report, questionList)->{ report.setDetail(this.statSentenceReport(report, questionList)); }); finishCallback.put(PaperModule.TEXTBOOK, (report, questionList)->{ report.setDetail(this.statTextbookReport(report, questionList)); }); finishCallback.put(PaperModule.EXAMINATION, (report, questionList)->{ this.statExaminationReport(report, questionList); }); finishAfterCallback.put(PaperOrigin.EXERCISE, (report)->{ // 重置最后一次练习记录 usersService.edit(User.builder().id(report.getUserId()).latestExercise(0).build()); }); finishAfterCallback.put(PaperOrigin.ERROR, (report)->{ // 设定最后一次错题记录 usersService.edit(User.builder().id(report.getUserId()).latestError(report.getId()).build()); }); } /** * 自由组卷:根据题目编号id * @param userId * @param origin * @param questionNoIds * @param filterTimes * @return */ @Transactional public UserPaper makePaper(Integer userId, QuestionModule module, PaperOrigin origin, List questionNoIds, Integer filterTimes){ // PaperOrigin只允许Error和Collect if (questionNoIds.size() == 0){ throw new ParameterException("题目数为空"); } QuestionOrigin questionOrigin = QuestionOrigin.WithPaper(origin); if (filterTimes != null && filterTimes > 0){ // 过滤重复多次的题目 questionNoIds = userPaperQuestionService.filterTimesQuestion(userId, questionOrigin, module, questionNoIds, filterTimes); if (questionNoIds.size() == 0){ throw new ParameterException("题目数为空"); } } int count = userPaperService.countByUser(userId, origin); UserPaper paper = userPaperService.newByPaper(userId, origin, PaperModule.WithQuestion(module), 0); switch(origin){ case ERROR: paper.setTitle(String.format("错题组卷%02d", count+1)); break; case COLLECT: paper.setTitle(String.format("收藏组卷%02d", count+1)); } paper.setQuestionNumber(questionNoIds.size()); paper.setQuestionNoIds(questionNoIds.toArray(new Integer[0])); InitPaper callback = makePaperCallback.get(module); paper = callback.callback(paper, 0); paper = userPaperService.add(paper); // 绑定关系,用于下次处理过滤 userPaperQuestionService.addOrigin(userId, paper.getId(), questionOrigin, module, questionNoIds); return paper; } public QuestionModule validGroup(Integer[] questionNoIds){ // if (questionNoIds == null || questionNoIds.length < 10) { // throw new ParameterException("不可小于10题,请重新选择"); // } if (questionNoIds.length > 50){ throw new ParameterException("不可多余50题,请重新选择"); } QuestionModule questionModule=null; List questionNoList = questionNoService.relation(questionNoService.select(questionNoIds)); QuestionSubject subject = null; for(QuestionNoRelation relation : questionNoList){ QuestionNoModule questionNoModule = QuestionNoModule.ValueOf(relation.getModule()); QuestionModule currentModule = QuestionModule.WithQuestionNo(questionNoModule); if(questionModule==null){ questionModule = currentModule; }else if(questionModule !=currentModule){ throw new ParameterException("不可同时选中语文题和数学题,请重新选择。"); } QuestionSubject currentSubject = QuestionSubject.FromType(QuestionType.ValueOf(relation.getQuestion().getQuestionType())); if (subject == null){ subject = currentSubject; }else if(subject!=currentSubject){ throw new ParameterException("不可同时选中语文题和数学题,请重新选择。"); } } return questionModule; } /** * 获取做题paper * @param userId * @param origin * @param paperId * @return */ @Transactional public UserPaper paper(Integer userId, PaperOrigin origin, Integer paperId){ PaperModule module = PaperModule.WithOrigin(origin); UserPaper paper = userPaperService.getByPaper(userId, origin, paperId); if (paper == null){ paper = userPaperService.newByPaper(userId, origin, module, paperId); // 先判断来源初始化,如果没有,则根据模块初始化 InitPaper callback = initOriginPaperCallback.get(origin); if (callback == null) { callback = initPaperCallback.get(module); } paper = callback.callback(paper, paperId); paper = userPaperService.add(paper); } return paper; } /** * 开始新一轮做题 * @param userId * @param origin * @param paperId * @param setting * @return */ @Transactional public UserReportRelation start(Integer userId, PaperOrigin origin, Integer paperId, JSONObject setting){ UserPaper paper = paper(userId, origin, paperId); // 查找对应的report是否有,如果没有或reset为1,则添加 UserReport userReport = null; if (paper.getIsReset() > 0) { paper.setIsReset(0); // 是否对重置有特殊处理 InitPaper callback = resetPaperCallback.get(origin); if (callback != null){ paper = callback.callback(paper, paperId); } if (paper.getId() != null){ userPaperService.edit(paper); }else{ paper = userPaperService.add(paper); } }else if(setting == null){ // 对于长难句这种没有设置开始页的,读取最后一次 userReport = userReportService.getLastByPaper(userId, paper.getId()); } if (userReport == null){ userReport = userReportService.newByPaper(paper, setting); InitReport callback = initReportCallback.get(PaperModule.ValueOf(paper.getPaperModule())); callback.callback(userReport, paper); userReportService.add(userReport); } return relationReport(userReport); } /** * 继续做题:判断是否可以继续 * @param userId * @param userReportId * @return */ public UserReportRelation continueReport(Integer userId, Integer userReportId){ UserReport userReport = userReportService.get(userReportId); if (!userReport.getUserId().equals(userId)){ throw new ParameterException("试卷不存在"); } if (userReport.getDetail() != null && userReport.getFinishTime() != null){ throw new ParameterException("做题结束"); } if (userReport.getUserNumber()>=userReport.getQuestionNumber()){ throw new ParameterException("答题结束,请提交完成"); } return relationReport(userReport); } /** * 获取单个report信息:基础 * @param userId * @param userReportId * @return */ public UserReportRelation baseReport(Integer userId, Integer userReportId){ UserReport userReport = userReportService.get(userReportId); if (!userReport.getUserId().equals(userId)){ throw new ParameterException("试卷不存在"); } return relationReport(userReport); } /** * 获取report的下一道题 * @param userId * @param userReportId * @return */ @Transactional public UserQuestion next(Integer userId, Integer userReportId){ UserQuestion userQuestion = userQuestionService.getLastByReport(userId, userReportId); // 查找未完成的questionId if (userQuestion==null || userQuestion.getUserTime() >0){ // 创建新的question UserReport userReport = userReportService.get(userReportId); if (!userReport.getUserId().equals(userId)){ throw new ParameterException("试卷不存在"); } UserQuestion lastQuestion = userQuestion; userQuestion = userQuestionService.newByReport(userReport, lastQuestion); InitQuestion callback = nextCallback.get(PaperModule.ValueOf(userReport.getPaperModule())); if (callback.callback(userQuestion, userReport, lastQuestion)){ userQuestion = userQuestionService.add(userQuestion); }else{ return null; } } return userQuestion; } /** * 提交试题 * @param userId * @param userQuestion * @return */ @Transactional public Boolean submit(Integer userId, UserQuestion userQuestion){ if (!userQuestion.getUserId().equals(userId)){ throw new ParameterException("题目不存在"); } QuestionModule module = QuestionModule.ValueOf(userQuestion.getQuestionModule()); UserReport userReport = userReportService.get(userQuestion.getReportId()); SubmitQuestion callback = submitCallback.get(module); Boolean result = callback.callback(userQuestion, userReport); userQuestion.setIsCorrect(result ? 1 : 0); // 如果做错,从移除错题中移除 if(!result){ userPaperQuestionService.removeRemoveError(userId, module, userQuestion.getQuestionNoId()); } userQuestionService.edit(userQuestion); // 根据剔除逻辑判断是否统计 if (toolsService.filterTime(userQuestion)){ Question question = questionService.get(userQuestion.getQuestionId()); SubmitAfterQuestion afterCallback = submitAfterCallback.get(module); afterCallback.callback(userQuestion, question); } // 更新对应report记录 userReportService.accumulation(userQuestion); // 自动finish if (userReport.getQuestionNumber().equals(userReport.getUserNumber())){ this.finish(userId, userReport.getId()); } return true; } /** * 模考进入下一阶段:调整出题逻辑,上一阶段都当成未完成 * @param userId * @param userReportId * @return */ @Transactional public Boolean stage(Integer userId, Integer userReportId){ UserReport userReport = userReportService.get(userReportId); if (!userReport.getUserId().equals(userId)){ throw new ParameterException("试卷不存在"); } if (userReport.getDetail() != null && userReport.getFinishTime() != null){ throw new ParameterException("做题结束"); } PaperOrigin origin = PaperOrigin.ValueOf(userReport.getPaperOrigin()); if (origin != PaperOrigin.EXAMINATION){ throw new ParameterException("不是模考试卷"); } ExaminationPaper paper = examinationPaperService.get(userReport.getOriginId()); JSONObject setting = userReport.getSetting(); // 当前stage,补全所有时间,切换成下一个stage JSONArray order = setting.getJSONArray("order"); String stage = setting.getString("stage"); JSONObject time = setting.getJSONObject("time"); JSONObject number = setting.getJSONObject("number"); Integer useTime = time.getInteger(stage); Integer totalTime = toolsService.examinationSubjectTime(stage); time.put(stage, totalTime); // 自动提交所有该stage的题目 Integer totalNumber = toolsService.examinationSubjectNumber(stage); // 自动提交最后一题 UserQuestion lastQuestion = userQuestionService.getLastByReport(userId, userReportId); UserQuestion question; if(lastQuestion != null && lastQuestion.getUserTime() == 0){ lastQuestion.setUserTime(totalTime - useTime); this.submit(userId, lastQuestion); } // 判断未完成题目数,自动生成 question = userQuestionService.newByReport(userReport, lastQuestion); while(number.getIntValue(stage) < totalNumber){ examinationCompute(paper, userReport, lastQuestion, question); question = userQuestionService.add(question); lastQuestion = question; question = userQuestionService.newByReport(userReport, lastQuestion); } // 更新setting userReportService.edit(UserReport.builder() .id(userReportId) .setting(setting).build()); // 如果是最后阶段。直接完成 int index = order.indexOf(stage); if (index == order.size() - 1){ // 完成所有阶段,结束考试 this.finish(userId, userReport.getId()); } return true; } /** * 完成试卷,进行试卷分析 * @param userId * @param userReportId * @return */ @Transactional public Boolean finish(Integer userId, Integer userReportId){ UserReport userReport = userReportService.get(userReportId); if (!userReport.getUserId().equals(userId)){ throw new ParameterException("试卷不存在"); } if (userReport.getIsFinish() > 0){ return true; } userReport.setFinishTime(new Date()); userReport.setIsFinish(1); List userQuestionList = userQuestionService.listByReport(userId, userReportId); // 分析做题结果 StatReport statReportCallback = finishCallback.get(PaperModule.ValueOf(userReport.getPaperModule())); statReportCallback.callback(userReport, userQuestionList); userReport.setIsStat(1); userReportService.edit(userReport); FinishAfterReport finishAfterReportCallback = finishAfterCallback.get(PaperOrigin.ValueOf(userReport.getPaperOrigin())); if(finishAfterReportCallback != null){ finishAfterReportCallback.callback(userReport); } // 统计: 更新对应paper记录 userPaperService.accumulation(userReport); return true; } /** * 重新开始一份试卷:设定试卷reset=1,列表不绑定最后一次考试记录 * @param userPaperId * @param userId * @return */ @Transactional public Boolean restart(Integer userPaperId, Integer userId){ // 获取最后一次report,并生成结果 UserReport userReport = userReportService.getLastByPaper(userId, userPaperId); List userQuestionList = userQuestionService.listByReport(userId, userReport.getId()); // 分析做题结果 StatReport callback = finishCallback.get(PaperModule.ValueOf(userReport.getPaperModule())); callback.callback(userReport, userQuestionList); userReport.setIsStat(1); userReportService.edit(userReport); return userPaperService.reset(userPaperId, userId); } /** * 获取提问权限记录 * @param questionType * @return */ public Integer questionRelationCourse(Integer userId, Integer assignId, QuestionType questionType){ if (assignId != null){ Integer assignRecordId = previewService.questionCourse(userId, assignId); if (assignRecordId != null) return assignRecordId; } return courseExtendService.questionRelationCourse(userId, questionType); } public Integer questionStatus(QuestionNo questionNo){ QuestionNoModule questionNoModule = QuestionNoModule.ValueOf(questionNo.getModule()); Integer id = null; // 获取基本当前权限 switch(questionNoModule){ case EXAMINATION: id = questionNo.getModuleStruct()[questionNo.getModuleStruct().length - 1]; ExaminationStruct examinationStruct = examinationStructService.get(id); return examinationStruct.getQuestionStatus(); case EXERCISE: id = questionNo.getModuleStruct()[questionNo.getModuleStruct().length - 1]; ExerciseStruct exerciseStruct = exerciseStructService.get(id); return exerciseStruct.getQuestionStatus(); case TEXTBOOK: TextbookQuestion textbookQuestion = textbookQuestionService.getByQuestionNo(questionNo.getId()); TextbookLibrary textbookLibrary = textbookLibraryService.get(textbookQuestion.getLibraryId()); return textbookLibrary.getQuestionStatus(); default: // 自由组卷,不提供提问显示 return -1; } } /** * 累计考试学习时间 * @param userId * @return */ public Integer studyTime(Integer userId, Date startTime, Date endTime){ UserRecordStatRelation record = userQuestionService.stat(userId, startTime, endTime); return record != null ? record.getUserTime() : 0; } /** * 平均考试时间 * @return */ public Integer studyAvgTime(Date startTime, Date endTime){ UserRecordStatRelation record = userQuestionService.statAvg(startTime, endTime); return record != null ? record.getUserTime() : 0; } /** * 模考完整出题逻辑 * @param paper * @param report * @param lastQuestion * @param question * @return */ public boolean examinationCompute(ExaminationPaper paper, UserReport report, UserQuestion lastQuestion, UserQuestion question){ JSONObject setting = report.getSetting(); JSONArray order = setting.getJSONArray("order"); String stage = setting.getString("stage"); JSONObject time = setting.getJSONObject("time"); JSONObject number = setting.getJSONObject("number"); time.put(stage, time.getIntValue(stage)+ lastQuestion.getUserTime()); Integer totalNumber = toolsService.examinationSubjectNumber(stage); // 判断数量是否已经完成 if (number.getIntValue(stage) >= totalNumber){ // 进入下一阶段 int index = order.indexOf(stage); if (index == order.size() - 1){ // 完成所有阶段,结束考试 return false; } stage = order.getString(index + 1); setting.put("stage", stage); // 重置stage数 question.setStageNo(1); question.setStage(stage); } // 获取本阶段完成数,剩余题目数 Integer subnumber = number.getIntValue(stage); Integer surplus = totalNumber - subnumber; QuestionSubject subject = QuestionSubject.ValueOf(stage); List questionTypes = QuestionType.SpecialFromSubject(subject); List userQuestionList = userQuestionService.listByReportAndType(report.getUserId(), report.getId(), questionTypes); Collection ids = Transform.getIds(userQuestionList, UserQuestion.class, "questionNoId"); // 根据设置出题 Integer questionNoId = 0; if (paper.getIsAdapt() > 0 && QuestionSubject.SupportAdapt(subject)){ switch(subject){ case VERBAL: questionNoId = verbalCompute(paper, setting, subnumber, ids, userQuestionList); break; case QUANT: questionNoId = quantCompute(paper, setting, subnumber, ids, userQuestionList); break; default: throw new ParameterException("模考出题流程错误:"+subject.key+"不支持适应性判断"); } }else{ questionNoId = randomCompute(subject, paper, questionTypes, setting, subnumber, ids, userQuestionList); } if (questionNoId == 0) { throw new ParameterException("模考出题流程错误:题目生成错误"); } QuestionNoRelation relation = questionNoService.getWithRelation(questionNoId); question.setQuestionNoId(relation.getId()); question.setQuestionId(relation.getQuestionId()); question.setQuestionType(relation.getQuestion().getQuestionType()); question.setTime(toolsService.computerTime(relation)); // 更新题目数 number.put(stage, subnumber + 1); return true; } /** * 语文出题计算 * @param setting * @param subnumber * @param ids * @param subQuestionList * @return */ public Integer verbalCompute(ExaminationPaper paper, JSONObject setting, Integer subnumber, Collection ids, List subQuestionList){ // 一共分为4个阶段:每个阶段9题,包含一题阅读 // 其中句改SC有14题,阅读RC有13题(共4篇阅读,每篇题数为3、3、3、4),逻辑CR为9题 // verbal: { "steps": [{"ids": [], "level": 0}, {}] } List questionNoIds = new ArrayList<>(); JSONObject verbal = setting.getJSONObject("verbal"); if (verbal == null) { verbal = new JSONObject(); verbal.put("steps", new JSONArray()); setting.put("verbal", verbal); } JSONArray steps = verbal.getJSONArray("steps"); // 判断当前是第几阶段 Integer step = subnumber / examinationService.verbalPre + 1; Integer questionIndex = 0; JSONObject info; if (subnumber == 0){ // 初始化 info = examinationService.initVerbal(paper.getStructThree()); steps.add(info); }else if(subnumber % examinationService.verbalPre == 0){ info = steps.getJSONObject(step); List currentIds = info.getJSONArray("ids").toJavaObject(questionNoIds.getClass()); // 计算上阶段的做题情况 long correct = subQuestionList.stream().filter((x)->currentIds.contains(x.getQuestionNoId()) && x.getIsCorrect() > 0).count(); // 下一阶段 Integer level = examinationService.verbalNextLevel(info.getInteger("level"), examinationService.verbalPre, correct); Map typeNumber = examinationService.statTypeNumber(subQuestionList); info = examinationService.generateVerbal(paper.getStructThree(), level, typeNumber, ids); steps.add(info); }else{ info = steps.getJSONObject(step); questionIndex = subnumber % examinationService.verbalPre; } //获取下一题 questionNoIds = info.getJSONArray("ids").toJavaObject(questionNoIds.getClass()); return (Integer) questionNoIds.get(questionIndex); } /** * 数学出题计算 * @param setting * @param subnumber * @param ids * @param subQuestionList * @return */ public Integer quantCompute(ExaminationPaper paper, JSONObject setting, Integer subnumber, Collection ids, List subQuestionList){ // 一共分为4个阶段:每个阶段题分别为8、8、8、7题,合计31题 // 其中数学PS有17题,数学DS有14题 // quant: { "steps": [{"ids": [], "level": 0}, {}] } List questionNoIds = new ArrayList<>(); JSONObject quant = setting.getJSONObject("quant"); if (quant == null) { quant = new JSONObject(); quant.put("steps", new JSONArray()); setting.put("quant", quant); } JSONArray steps = quant.getJSONArray("steps"); // 判断当前是第几阶段 Integer step = examinationService.quantStep(subnumber); Integer nextStep = examinationService.quantStep(subnumber+1); Integer questionIndex = 0; JSONObject info; if (subnumber == 0){ // 初始化 info = examinationService.initQuant(paper.getStructThree()); steps.add(info); }else if(step < nextStep){ info = steps.getJSONObject(step); List currentIds = info.getJSONArray("ids").toJavaObject(questionNoIds.getClass()); // 计算上阶段的做题情况 long correct = subQuestionList.stream().filter((x)->currentIds.contains(x.getQuestionNoId()) && x.getIsCorrect() > 0).count(); // 下一阶段 Integer level = examinationService.quantNextLevel(info.getInteger("level"), examinationService.quantBaseLevel[step], correct, step); Map typeNumber = examinationService.statTypeNumber(subQuestionList); info = examinationService.generateQuant(paper.getStructThree(), level, typeNumber, ids, nextStep); steps.add(info); }else{ info = steps.getJSONObject(step); questionIndex = subnumber - examinationService.quantNumber[step]; } //获取下一题 questionNoIds = info.getJSONArray("ids").toJavaObject(questionNoIds.getClass()); return (Integer) questionNoIds.get(questionIndex); } /** * 随机出题计算 * @param subject * @param paper * @param questionTypes * @param setting * @param subnumber * @param ids * @param subQuestionList * @return */ public Integer randomCompute(QuestionSubject subject, ExaminationPaper paper, List questionTypes, JSONObject setting, Integer subnumber, Collection ids, List subQuestionList){ // 随机挑题 switch (subject){ case VERBAL: // 固定顺序抽取阅读题 if(examinationService.verbalRC(subnumber)){ // 第一次抽取4题,后面抽取3题,和适应性一致 JSONObject rc = setting.getJSONObject("rc"); Integer number = 0; if (rc == null) { rc = new JSONObject(); setting.put("rc", rc); number = 4; }else{ number = 3; } Integer[] questions = questionNoService.randomExaminationRc(paper.getStructThree(), number, rc.values()); // 写入后续题目关系 Integer position = subnumber; for(int q: questions){ rc.put(position.toString(), q); position += 1; } } // 判断是否后续阅读题 JSONObject rc = setting.getJSONObject("rc"); if(rc.getInteger(subnumber.toString()) != null){ return rc.getIntValue(subnumber.toString()); } break; } Map typeNumber = examinationService.statTypeNumber(subQuestionList); List targetTypes = examinationService.needQuestionTypes(typeNumber, questionTypes); // 不主动查询阅读题:targetTypes没有rc return questionNoService.randomExamination(paper.getStructThree(), targetTypes, ids); } /** * 获取报告题目列表 * @param userReportId * @param userId * @return */ public List listByReport(Integer userId,Integer userReportId){ List userQuestionList = userQuestionService.listByReport(userId, userReportId); return userQuestionList; } /** * 乱序生成题目列表 * @param questionNoIds * @return */ private Integer[] randomQuestionNoIds(Integer[] questionNoIds){ Integer[] ran = new Integer[questionNoIds.length]; List base = Arrays.stream(questionNoIds).collect(Collectors.toList()); int length = base.size(); for(int i = 0; i < ran.length; i++){ ran[i] = base.remove((int)(Math.random()*length)); length -= 1; } return ran; } /** * 顺序获取下一题 * @param ids * @param id * @return */ private Integer nextId(Integer[] ids, Integer id){ if (id == null) return ids[0]; boolean flag = false; for(Integer a : ids){ if (a.equals(id)){ flag = true; continue; } if (flag){ return a; } } return 0; } /** * 关联绑定questionNo类型试题 * @param question * @param questionNoId */ private void bindQuestionNo(UserQuestion question, Integer questionNoId){ QuestionNoRelation relation = questionNoService.getWithRelation(questionNoId); question.setQuestionNoId(relation.getId()); question.setQuestionId(relation.getQuestionId()); question.setQuestionType(relation.getQuestion().getQuestionType()); Integer time = toolsService.computerTime(relation); question.setTime(time); } /** * 获取报表关联试卷 * @param p * @return */ private UserReportRelation relationReport(UserReport p){ UserReportRelation relation = Transform.convert(p, UserReportRelation.class); UserPaper paper = userPaperService.get(p.getPaperId()); relation.setPaper(paper); return relation; } /** * 基本题型的答案判断 * @param userAnswer * @param answer * @param question * @return */ private Boolean baseAnswer(JSONObject userAnswer, JSONObject answer, Question question){ String type = question.getContent().getString("type"); QuestionContentType contentType = QuestionContentType.ValueOf(type); JSONArray userQuestions = userAnswer.getJSONArray("questions"); JSONArray questions = answer.getJSONArray("questions"); for(int i = 0; i< questions.size(); i++){ JSONObject userOne = userQuestions.getJSONObject(i); JSONObject one = questions.getJSONObject(i); switch(contentType){ case DOUBLE: JSONArray userDoubleList = userOne.getJSONArray("double"); JSONArray doubleList = one.getJSONArray("double"); // if(JSONObject.toJSON(userDoubleList) != JSONObject.toJSON(doubleList)){ // return false; // } for(int j = 0; j < doubleList.size(); j++){ JSONArray singleList = doubleList.getJSONArray(j); JSONArray userSingleList = userDoubleList.getJSONArray(i); for (int k = 0; k < singleList.size(); k++){ if (userSingleList.getBoolean(k) != singleList.getBoolean(k)){ return false; } } } break; case SINGLE: case INLINE: default: JSONArray userSingleList = userOne.getJSONArray("single"); JSONArray singleList = one.getJSONArray("single"); // if(JSONObject.toJSON(userSingleList) != JSONObject.toJSON(singleList)){ // return false; // } for(int j = 0; j < singleList.size(); j++){ if (userSingleList.getBoolean(j) != singleList.getBoolean(j)){ return false; } } } } return true; } /** * 长难句单个选项答案判断 * @param userAnswer * @param answer * @return */ private Boolean sentenceAnswer(JSONArray userAnswer, JSONArray answer){ // 数量一致,并且都包含 for(Object a : answer){ JSONArray singleArray = (JSONArray) a; if (singleArray == null){ return userAnswer == null; } if (userAnswer != null && singleArray.size() == userAnswer.size()){ for (int i = 0; i < singleArray.size(); i++){ JSONObject single = singleArray.getJSONObject(i); JSONObject user = userAnswer.getJSONObject(i); // 判断uuid是否一致 if (!single.getString("uuid").equals(user.getString("uuid"))){ return false; } } return true; } } return false; } /** * 长难句多选答案判断 * @param userAnswer * @param answer * @return */ private Boolean sentenceAnswerOption(JSONArray userAnswer, JSONArray answer){ // 数量一致,并且都包含 if (userAnswer.size() == answer.size()){ for(Object s : userAnswer){ if (!answer.contains(s)){ return false; } } }else{ return false; } return true; } /** * 统计答案分布 * @param userQuestion * @param question */ private void answerDistributed(UserQuestion userQuestion, Question question){ JSONObject answerDistributed = question.getAnswerDistributed(); if (answerDistributed == null){ answerDistributed = new JSONObject(); } JSONObject answer = question.getAnswer(); JSONObject userAnswer = userQuestion.getUserAnswer(); String type = question.getContent().getString("type"); QuestionContentType contentType = QuestionContentType.ValueOf(type); JSONArray userQuestions = userAnswer.getJSONArray("questions"); JSONArray questions = answer.getJSONArray("questions"); JSONArray distributed = answerDistributed.getJSONArray("questions"); if (distributed == null || distributed.isEmpty()){ distributed = new JSONArray(); answerDistributed.put("questions", distributed); } for(int i = 0; i< questions.size(); i++){ JSONObject userOne = userQuestions.getJSONObject(i); JSONObject one = questions.getJSONObject(i); JSONObject target = null; if (distributed.size() > i){ target = distributed.getJSONObject(i); } if (target == null || target.isEmpty()){ target = new JSONObject(); distributed.add(i, target); } switch(contentType){ case DOUBLE: JSONArray userDoubleList = userOne.getJSONArray("double"); JSONArray doubleList = one.getJSONArray("double"); JSONArray doubleResult = target.getJSONArray("double"); if (doubleResult == null || doubleResult.isEmpty()){ doubleResult = new JSONArray(); target.put("double", doubleResult); } for(int j = 0; j < doubleList.size(); j++){ JSONArray singleList = doubleList.getJSONArray(j); JSONArray userSingleList = userDoubleList.getJSONArray(i); JSONArray singleResult = doubleResult.getJSONArray(j); if (singleResult == null){ singleResult = new JSONArray(0); doubleResult.set(j, singleResult); } for (int k = 0; k < singleList.size(); k++){ if (singleResult.get(k) == null){ singleResult.set(k, 0); } if (userSingleList.getBoolean(k)){ singleResult.set(k, singleResult.getIntValue(k)+1); } } } break; case SINGLE: case INLINE: default: JSONArray userSingleList = userOne.getJSONArray("single"); JSONArray singleList = one.getJSONArray("single"); JSONArray singleResult = target.getJSONArray("single"); if (singleResult == null || singleResult.isEmpty()){ singleResult = new JSONArray(); target.put("single", singleResult); } for(int j = 0; j < singleList.size(); j++){ if (singleResult.get(j) == null){ singleResult.set(j, 0); } if (userSingleList.getBoolean(j)){ singleResult.set(j, singleResult.getIntValue(j)+1); } } } } questionService.edit(Question.builder().id(question.getId()) .answerDistributed(answerDistributed) .build()); } /** * 根据练习报告格式,统计信息 * @param report * @param questionList * @return */ private JSONObject statExerciseReport(UserReport report, List questionList){ UserPaper paper = userPaperService.get(report.getPaperId()); Integer[] questionNoIds = new Integer[questionList.size()]; int index = 0; for(UserQuestion userQuestion : questionList){ questionNoIds[index] = userQuestion.getQuestionNoId(); index += 1; } Map relationMap = questionNoService.mapWithRelationByIds(questionNoIds); // report JSONObject detail = new JSONObject(); JSONArray pace = new JSONArray(); JSONObject difficultMap = new JSONObject(); JSONObject placeMap = new JSONObject(); for (UserQuestion userQuestion:questionList){ QuestionNoRelation relation = relationMap.get(userQuestion.getQuestionNoId()); // 每题用时 JSONObject one = new JSONObject(); one.put("time", userQuestion.getTime()); one.put("userTime", userQuestion.getUserTime()); one.put("no", userQuestion.getNo()); pace.add(one); // 考点用时,以及正确度 String placeKey = relation.getQuestion().getPlace(); JSONObject place = placeMap.getJSONObject(placeKey); if (place == null){ place = new JSONObject(); place.put("key", placeKey); place.put("userNumber", 1); place.put("userCorrect", userQuestion.getIsCorrect()); place.put("userTime", userQuestion.getUserTime()); placeMap.put(placeKey, place); }else{ place.put("userNumber", place.getInteger("userNumber") + 1); place.put("userCorrect", place.getInteger("userCorrect") + userQuestion.getIsCorrect()); place.put("userTime", place.getInteger("userTime") + userQuestion.getUserTime()); } // 难度正确度 String difficultKey = relation.getQuestion().getDifficult(); JSONObject difficult = difficultMap.getJSONObject(difficultKey); if (difficult == null){ difficult = new JSONObject(); difficult.put("key", difficultKey); difficult.put("userNumber", 1); difficult.put("userCorrect", userQuestion.getIsCorrect()); difficult.put("totalNumber", relation.getTotalNumber() + 1); difficult.put("totalCorrect", relation.getTotalCorrect() + userQuestion.getIsCorrect()); difficultMap.put(difficultKey, difficult); }else{ difficult.put("userNumber", difficult.getInteger("userNumber") + 1); difficult.put("userCorrect", difficult.getInteger("userCorrect") + userQuestion.getIsCorrect()); difficult.put("totalNumber", difficult.getInteger("totalNumber") + relation.getTotalNumber() + 1); difficult.put("totalCorrect", difficult.getInteger("totalCorrect") + relation.getTotalCorrect() + userQuestion.getIsCorrect()); } } detail.put("pace", pace); JSONArray difficult = new JSONArray(); difficult.addAll(difficultMap.values()); detail.put("difficult", difficult); JSONArray place = new JSONArray(); place.addAll(placeMap.values()); detail.put("place", place); JSONObject limit = new JSONObject(); // 限时统计考试正确度 UserReportLimitRelation relation = userReportService.statLimit(report.getPaperOrigin(), report.getOriginId()); limit.put("userNumber", relation.getUserNumber()); limit.put("userCorrect", relation.getUserCorrect()); detail.put("limit", limit); JSONObject info = new JSONObject(); // 基本信息 info.put("times", paper.getTimes() + 1); // paper还未计数 info.put("finishTime", report.getFinishTime()); info.put("userTime", report.getUserTime()); info.put("time", report.getTime()); info.put("questionNumber", report.getQuestionNumber()); info.put("userNumber", report.getUserNumber()); info.put("userCorrect", report.getUserCorrect()); Integer totalNumber = 0; Integer totalCorrect = 0; Integer totalTime = 0; for (QuestionNoRelation questionNoRelation : relationMap.values()){ totalNumber += questionNoRelation.getTotalNumber(); totalCorrect += questionNoRelation.getTotalCorrect(); totalTime += questionNoRelation.getTotalTime(); } Integer correctTime = 0; Integer incorrectTime = 0; for (UserQuestion userQuestion : questionList){ if (userQuestion.getIsCorrect() > 0){ correctTime += userQuestion.getUserTime(); }else{ incorrectTime += userQuestion.getUserTime(); } } info.put("totalNumber", totalNumber); info.put("totalCorrect", totalCorrect); info.put("totalTime", totalTime); info.put("correctTime", correctTime); info.put("incorrectTime", incorrectTime); detail.put("info", info); return detail; } /** * 根据机经报告格式,统计信息:移除练习中的难度分析 * @param report * @param questionList * @return */ private JSONObject statTextbookReport(UserReport report, List questionList){ UserPaper paper = userPaperService.get(report.getPaperId()); Collection questionNoIds = Transform.getIds(questionList, UserQuestion.class, "questionNoId"); List relationList = textbookQuestionService.relation(textbookQuestionService.listByQuestionNo(questionNoIds)); Map relationMap = new HashMap<>(); for(TextbookQuestionRelation relation : relationList){ relationMap.put(relation.getQuestionNoId(), relation); } // report JSONObject detail = new JSONObject(); JSONArray pace = new JSONArray(); JSONObject placeMap = new JSONObject(); for (UserQuestion userQuestion:questionList){ TextbookQuestionRelation relation = relationMap.get(userQuestion.getQuestionNoId()); // 每题用时 JSONObject one = new JSONObject(); one.put("time", userQuestion.getTime()); one.put("userTime", userQuestion.getUserTime()); one.put("no", userQuestion.getNo()); pace.add(one); // 考点用时,以及正确度 String placeKey = relation.getQuestion().getPlace(); JSONObject place = placeMap.getJSONObject(placeKey); if (place == null){ place = new JSONObject(); place.put("key", placeKey); place.put("userNumber", 1); place.put("userCorrect", userQuestion.getIsCorrect()); place.put("userTime", userQuestion.getUserTime()); placeMap.put(placeKey, place); }else{ place.put("userNumber", place.getInteger("userNumber") + 1); place.put("userCorrect", place.getInteger("userCorrect") + userQuestion.getIsCorrect()); place.put("userTime", place.getInteger("userTime") + userQuestion.getUserTime()); } } detail.put("pace", pace); JSONArray place = new JSONArray(); place.addAll(placeMap.values()); detail.put("place", place); JSONObject limit = new JSONObject(); // 限时统计考试正确度 UserReportLimitRelation relation = userReportService.statLimit(report.getPaperOrigin(), report.getOriginId()); limit.put("userNumber", relation.getUserNumber()); limit.put("userCorrect", relation.getUserCorrect()); detail.put("limit", limit); JSONObject info = new JSONObject(); // 基本信息 info.put("times", paper.getTimes() + 1); // paper还未计数 info.put("finishTime", report.getFinishTime()); info.put("userTime", report.getUserTime()); info.put("time", report.getTime()); info.put("questionNumber", report.getQuestionNumber()); info.put("userNumber", report.getUserNumber()); info.put("userCorrect", report.getUserCorrect()); Integer totalNumber = 0; Integer totalCorrect = 0; Integer totalTime = 0; for (TextbookQuestionRelation questionNoRelation : relationMap.values()){ totalNumber += questionNoRelation.getTotalNumber(); totalCorrect += questionNoRelation.getTotalCorrect(); totalTime += questionNoRelation.getTotalTime(); } Integer correctTime = 0; Integer incorrectTime = 0; for (UserQuestion userQuestion : questionList){ if (userQuestion.getIsCorrect() > 0){ correctTime += userQuestion.getUserTime(); }else{ incorrectTime += userQuestion.getUserTime(); } } info.put("totalNumber", totalNumber); info.put("totalCorrect", totalCorrect); info.put("totalTime", totalTime); info.put("correctTime", correctTime); info.put("incorrectTime", incorrectTime); detail.put("info", info); return detail; } /** * 根据长难句报告格式,统计信息 * @param report * @param questionList * @return */ private JSONObject statSentenceReport(UserReport report, List questionList){ UserPaper paper = userPaperService.get(report.getPaperId()); Collection questionNoIds = Transform.getIds(questionList, UserQuestion.class, "questionNoId"); List relationList = sentenceQuestionService.relation(sentenceQuestionService.listByQuestionNo(questionNoIds)); Map relationMap = new HashMap<>(); for(SentenceQuestionRelation relation : relationList){ relationMap.put(relation.getQuestionNoId(), relation); } // report JSONObject detail = new JSONObject(); JSONObject ability = new JSONObject(); Integer struct = 0; Integer logic = 0; Integer speed = 0; for (UserQuestion userQuestion:questionList){ if (userQuestion.getUserTime() < userQuestion.getTime()){ speed += 1; } JSONObject questionDetail = userQuestion.getDetail(); if (questionDetail.getBoolean("subject") && questionDetail.getBoolean("predicate") && questionDetail.getBoolean("object")){ struct += 1; } if (questionDetail.getBoolean("options")){ logic += 1; } } ability.put("struct", struct * 100 / report.getQuestionNumber()); ability.put("logic", logic * 100 / report.getQuestionNumber()); ability.put("speed", speed * 100 / report.getQuestionNumber()); ability.put("score", (struct * 40 + logic * 30 + speed * 30) / report.getQuestionNumber()); detail.put("ability", ability); JSONObject info = new JSONObject(); // 基本信息 info.put("times", paper.getTimes() + 1); // paper还未计数 info.put("finishTime", report.getFinishTime()); info.put("userTime", report.getUserTime()); info.put("time", report.getTime()); info.put("questionNumber", report.getQuestionNumber()); info.put("userNumber", report.getUserNumber()); info.put("userCorrect", report.getUserCorrect()); Integer totalNumber = 0; Integer totalCorrect = 0; Integer totalTime = 0; for (SentenceQuestionRelation questionNoRelation : relationMap.values()){ totalNumber += questionNoRelation.getTotalNumber(); totalCorrect += questionNoRelation.getTotalCorrect(); totalTime += questionNoRelation.getTotalTime(); } Integer correctTime = 0; Integer incorrectTime = 0; for (UserQuestion userQuestion : questionList){ if (userQuestion.getIsCorrect() > 0){ correctTime += userQuestion.getUserTime(); }else{ incorrectTime += userQuestion.getUserTime(); } } info.put("totalNumber", totalNumber); info.put("totalCorrect", totalCorrect); info.put("totalTime", totalTime); info.put("correctTime", correctTime); info.put("incorrectTime", incorrectTime); detail.put("info", info); return detail; } /** * 根据模考报告格式,统计信息 * @param report * @param questionList * @return */ private void statExaminationReport(UserReport report, List questionList){ UserPaper paper = userPaperService.get(report.getPaperId()); Collection questionNoIds = Transform.getIds(questionList, UserQuestion.class, "questionNoId"); Map relationMap = questionNoService.mapWithRelationByIds((Integer[])questionNoIds.toArray()); // report JSONObject detail = new JSONObject(); JSONObject score = new JSONObject(); // 成绩单 JSONObject subjectMap = new JSONObject(); JSONObject typeMap = new JSONObject(); JSONObject tempMap = new JSONObject(); JSONObject difficult = null; JSONObject place = null; for (UserQuestion userQuestion : questionList){ QuestionNoRelation relation = relationMap.get(userQuestion.getQuestionNoId()); QuestionType questionType = QuestionType.ValueOf(relation.getQuestion().getQuestionType()); QuestionSubject questionSubject = QuestionSubject.FromType(questionType); JSONObject type = typeMap.getJSONObject(questionType.key); JSONObject tempType = tempMap.getJSONObject(questionType.key); JSONObject subject = subjectMap.getJSONObject(questionSubject.key); JSONObject tempSubject = tempMap.getJSONObject(questionSubject.key); // 归类 if (type == null || type.isEmpty()){ type = new JSONObject(); type.put("key", questionType.key); subject.put("pace", new JSONArray()); JSONObject initTypeInfo = new JSONObject(); // 初始化题型基础信息 initTypeInfo.put("userNumber", 0); initTypeInfo.put("userTime", 0); initTypeInfo.put("userCorrect", 0); initTypeInfo.put("correctTime", 0); initTypeInfo.put("incorrectTime", 0); initTypeInfo.put("diffCorrect", 0f); initTypeInfo.put("diffIncorrect", 0f); type.put("info", initTypeInfo); typeMap.put(questionType.key, type); tempType = new JSONObject(); tempType.put("place", new JSONObject()); tempType.put("difficult", new JSONObject()); tempMap.put(questionType.key, tempType); } if (subject == null || subject.isEmpty()){ subject = new JSONObject(); subject.put("key", questionSubject.key); subject.put("pace", new JSONArray()); JSONObject initSubjectInfo = new JSONObject(); JSONObject subjectBase = toolsService.examinationSubjectInit(questionSubject); // 初始化学科基础信息 initSubjectInfo.put("questionNumber", subjectBase.getIntValue("number")); initSubjectInfo.put("time", subjectBase.getIntValue("time")); initSubjectInfo.put("userNumber", 0); initSubjectInfo.put("userTime", 0); initSubjectInfo.put("userCorrect", 0); initSubjectInfo.put("correctTime", 0); initSubjectInfo.put("incorrectTime", 0); initSubjectInfo.put("diffCorrect", 0f); initSubjectInfo.put("diffIncorrect", 0f); initSubjectInfo.put("difficultScore", 0); subject.put("info", initSubjectInfo); subjectMap.put(questionSubject.key, subject); tempSubject = new JSONObject(); tempSubject.put("place", new JSONObject()); tempSubject.put("difficult", new JSONObject()); tempMap.put(questionSubject.key, tempType); } JSONArray paceType = type.getJSONArray("pace"); JSONObject placeTypeMap = tempType.getJSONObject("place"); JSONObject difficultTypeMap = tempType.getJSONObject("difficult"); JSONObject typeInfo = type.getJSONObject("info"); JSONArray paceSubject = subject.getJSONArray("pace"); JSONObject placeSubjectMap = tempType.getJSONObject("place"); JSONObject difficultSubjectMap = tempType.getJSONObject("difficult"); JSONObject subjectInfo = subject.getJSONObject("info"); // 每题用时 JSONObject one = new JSONObject(); one.put("time", userQuestion.getTime()); one.put("userTime", userQuestion.getUserTime()); one.put("no", userQuestion.getNo()); paceSubject.add(one); paceType.add(one); // 考点用时,以及正确度 String placeKey = relation.getQuestion().getPlace(); place = placeTypeMap.getJSONObject(placeKey); if (place == null){ place = new JSONObject(); place.put("key", placeKey); place.put("userNumber", 1); place.put("userCorrect", userQuestion.getIsCorrect()); place.put("userTime", userQuestion.getUserTime()); placeTypeMap.put(placeKey, place); }else{ place.put("userNumber", place.getInteger("userNumber") + 1); place.put("userCorrect", place.getInteger("userCorrect") + userQuestion.getIsCorrect()); place.put("userTime", place.getInteger("userTime") + userQuestion.getUserTime()); } place = placeSubjectMap.getJSONObject(placeKey); if (place == null){ place = new JSONObject(); place.put("key", placeKey); place.put("userNumber", 1); place.put("userCorrect", userQuestion.getIsCorrect()); place.put("userTime", userQuestion.getUserTime()); placeSubjectMap.put(placeKey, place); }else{ place.put("userNumber", place.getInteger("userNumber") + 1); place.put("userCorrect", place.getInteger("userCorrect") + userQuestion.getIsCorrect()); place.put("userTime", place.getInteger("userTime") + userQuestion.getUserTime()); } // 难度正确度 String difficultKey = relation.getQuestion().getDifficult(); difficult = difficultTypeMap.getJSONObject(difficultKey); if (difficult == null){ difficult = new JSONObject(); difficult.put("key", difficultKey); difficult.put("userNumber", 1); difficult.put("userCorrect", userQuestion.getIsCorrect()); difficult.put("totalNumber", relation.getTotalNumber() + 1); difficult.put("totalCorrect", relation.getTotalCorrect() + userQuestion.getIsCorrect()); difficultTypeMap.put(difficultKey, difficult); }else{ difficult.put("userNumber", difficult.getInteger("userNumber") + 1); difficult.put("userCorrect", difficult.getInteger("userCorrect") + userQuestion.getIsCorrect()); difficult.put("totalNumber", difficult.getInteger("totalNumber") + relation.getTotalNumber() + 1); difficult.put("totalCorrect", difficult.getInteger("totalCorrect") + relation.getTotalCorrect() + userQuestion.getIsCorrect()); } difficult = difficultSubjectMap.getJSONObject(difficultKey); if (difficult == null){ difficult = new JSONObject(); difficult.put("key", difficultKey); difficult.put("userNumber", 1); difficult.put("userCorrect", userQuestion.getIsCorrect()); difficult.put("totalNumber", relation.getTotalNumber() + 1); difficult.put("totalCorrect", relation.getTotalCorrect() + userQuestion.getIsCorrect()); difficultSubjectMap.put(difficultKey, difficult); }else{ difficult.put("userNumber", difficult.getInteger("userNumber") + 1); difficult.put("userCorrect", difficult.getInteger("userCorrect") + userQuestion.getIsCorrect()); difficult.put("totalNumber", difficult.getInteger("totalNumber") + relation.getTotalNumber() + 1); difficult.put("totalCorrect", difficult.getInteger("totalCorrect") + relation.getTotalCorrect() + userQuestion.getIsCorrect()); } // 基础数据 typeInfo.put("userNumber", typeInfo.getIntValue("userNumber")+1); typeInfo.put("userTime", typeInfo.getIntValue("userTime")+userQuestion.getUserTime()); typeInfo.put("userCorrect", typeInfo.getIntValue("userCorrect")+userQuestion.getIsCorrect()); if (userQuestion.getIsCorrect() > 0){ typeInfo.put("correctTime", typeInfo.getIntValue("correctTime")+userQuestion.getUserTime()); }else{ typeInfo.put("incorrectTime", typeInfo.getIntValue("incorrectTime")+userQuestion.getUserTime()); } subjectInfo.put("userNumber", subjectInfo.getIntValue("userNumber")+1); subjectInfo.put("userTime", subjectInfo.getIntValue("userTime")+userQuestion.getUserTime()); subjectInfo.put("userCorrect", subjectInfo.getIntValue("userCorrect")+userQuestion.getIsCorrect()); if (userQuestion.getIsCorrect() > 0){ subjectInfo.put("correctTime", subjectInfo.getIntValue("correctTime")+userQuestion.getUserTime()); }else{ subjectInfo.put("incorrectTime", subjectInfo.getIntValue("incorrectTime")+userQuestion.getUserTime()); } // 题型难度分计算 QuestionDifficult questionDifficult = QuestionDifficult.ValueOf(difficultKey); if (userQuestion.getIsCorrect() > 0){ typeInfo.put("diffCorrect", typeInfo.getFloatValue("diffCorrect") + toolsService.diffScore(relation.getTotalNumber(), relation.getTotalCorrect(), questionDifficult)); subjectInfo.put("diffCorrect", subjectInfo.getFloatValue("diffCorrect") + toolsService.diffScore(relation.getTotalNumber(), relation.getTotalCorrect(), questionDifficult)); }else{ typeInfo.put("diffIncorrect", typeInfo.getFloatValue("diffIncorrect") + toolsService.diffScore(relation.getTotalNumber(), relation.getTotalCorrect(), questionDifficult)); subjectInfo.put("diffIncorrect", subjectInfo.getFloatValue("diffIncorrect") + toolsService.diffScore(relation.getTotalNumber(), relation.getTotalCorrect(), questionDifficult)); } // 获取2级难度得分 float difficultScore = relation.getQuestion().getDifficultScore(); subjectInfo.put("difficultScore", subjectInfo.getFloatValue("difficultScore")+difficultScore); } // 计算难度平均值 for (String key : typeMap.keySet()) { JSONObject type = typeMap.getJSONObject(key); JSONObject typeInfo = type.getJSONObject("info"); typeInfo.put("avgDiffCorrect", toolsService.avgDiffScore(typeInfo.getFloat("diffCorrect"), typeInfo.getIntValue("userCorrect"))); typeInfo.put("avgDiffIncorrect", toolsService.avgDiffScore(typeInfo.getFloat("diffIncorrect"), typeInfo.getIntValue("userNumber") - typeInfo.getIntValue("userCorrect"))); } for (String key : subjectMap.keySet()) { JSONObject subject = subjectMap.getJSONObject(key); JSONObject subjectInfo = subject.getJSONObject("info"); subjectInfo.put("avgDiffCorrect", toolsService.avgDiffScore(subjectInfo.getFloat("diffCorrect"), subjectInfo.getIntValue("userCorrect"))); subjectInfo.put("avgDiffIncorrect", toolsService.avgDiffScore(subjectInfo.getFloat("diffIncorrect"), subjectInfo.getIntValue("userNumber") - subjectInfo.getIntValue("userCorrect"))); } // 学科得分计算 JSONObject quantSubject = subjectMap.getJSONObject(QuestionSubject.QUANT.key); JSONObject quantInfo = quantSubject.getJSONObject("info"); Integer quantScore = toolsService.quantScore(quantInfo.getIntValue("number"), quantInfo.getIntValue("userNumber"), quantInfo.getFloatValue("difficultScore"), quantInfo.getInteger("userCorrect")); JSONObject verbalSubject = subjectMap.getJSONObject(QuestionSubject.VERBAL.key); JSONObject verbalInfo = verbalSubject.getJSONObject("info"); Integer verbalScore = toolsService.verbalScore(verbalInfo.getIntValue("number"), verbalInfo.getIntValue("userNumber"), verbalInfo.getFloatValue("difficultScore"), verbalInfo.getInteger("userCorrect")); JSONObject irSubject = subjectMap.getJSONObject(QuestionSubject.IR.key); JSONObject irInfo = irSubject.getJSONObject("info"); Integer irScore = toolsService.irScore(irInfo.getIntValue("number"), irInfo.getIntValue("userNumber"), irInfo.getInteger("difficultScore"), irInfo.getInteger("userCorrect")); Rank rank = toolsService.totalScore(quantScore, verbalScore); score.put("totalScore", rank.getTotalScore()); score.put("totalRank", rank.getTotalRank()); score.put("quantScore", quantScore); score.put("quantRank", rank.getQuantRank()); score.put("verbalScore", verbalScore); score.put("irScore", irScore); score.put("irRank", rank.getIrRank()); detail.put("subject", subjectMap); detail.put("type", typeMap); JSONObject info = new JSONObject(); // 基本信息 info.put("times", paper.getTimes() + 1); // paper还未计数 info.put("finishTime", report.getFinishTime()); info.put("userTime", report.getUserTime()); info.put("time", report.getTime()); info.put("questionNumber", report.getQuestionNumber()); info.put("userNumber", report.getUserNumber()); info.put("userCorrect", report.getUserCorrect()); detail.put("info", info); report.setDetail(detail); report.setScore(score); // 统计 UserService userService = null; // 判断是否是cat模考:记录到第二次 ExaminationPaper examinationPaper = examinationPaperService.get(report.getOriginId()); if(examinationService.isCat(examinationPaper)){ userService = userServiceService.getService(report.getUserId(), ServiceKey.QX_CAT); } examinationPaperService.accumulation(report, userService != null && userService.getIsReset() > 0); } }