QuestionFlowService.java 77 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745
  1. package com.qxgmat.service.extend;
  2. import com.alibaba.fastjson.JSONArray;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.nuliji.tools.Transform;
  5. import com.nuliji.tools.exception.ParameterException;
  6. import com.qxgmat.data.constants.enums.*;
  7. import com.qxgmat.data.constants.enums.module.*;
  8. import com.qxgmat.data.dao.entity.*;
  9. import com.qxgmat.data.relation.entity.*;
  10. import com.qxgmat.service.*;
  11. import com.qxgmat.service.annotation.*;
  12. import com.qxgmat.service.inline.*;
  13. import org.springframework.stereotype.Service;
  14. import org.springframework.transaction.annotation.Transactional;
  15. import javax.annotation.Resource;
  16. import java.util.*;
  17. import java.util.stream.Collectors;
  18. @Service
  19. public class QuestionFlowService {
  20. @Resource
  21. private ExercisePaperService exercisePaperService;
  22. @Resource
  23. private PreviewService previewService;
  24. @Resource
  25. private ExaminationPaperService examinationPaperService;
  26. @Resource
  27. private ExaminationStructService examinationStructService;
  28. @Resource
  29. private QuestionNoService questionNoService;
  30. @Resource
  31. private QuestionService questionService;
  32. @Resource
  33. private CourseService courseService;
  34. @Resource
  35. private SentenceQuestionService sentenceQuestionService;
  36. @Resource
  37. private SentencePaperService sentencePaperService;
  38. @Resource
  39. private TextbookQuestionService textbookQuestionService;
  40. @Resource
  41. private TextbookPaperService textbookPaperService;
  42. @Resource
  43. private PreviewPaperService previewPaperService;
  44. @Resource
  45. private PreviewAssignService previewAssignService;
  46. @Resource
  47. private UsersService usersService;
  48. @Resource
  49. private UserReportService userReportService;
  50. @Resource
  51. private UserPaperService userPaperService;
  52. @Resource
  53. private UserPaperQuestionService userPaperQuestionService;
  54. @Resource
  55. private UserQuestionService userQuestionService;
  56. @Resource
  57. private UserServiceService userServiceService;
  58. @Resource
  59. private UserCourseAppointmentService userCourseAppointmentService;
  60. @Resource
  61. private ExaminationService examinationService;
  62. @Resource
  63. private CourseExtendService courseExtendService;
  64. @Resource
  65. private ToolsService toolsService;
  66. @Resource
  67. private MessageExtendService messageExtendService;
  68. // 自由组卷初始化试卷callback
  69. private Map<QuestionModule, InitPaper> makePaperCallback = new HashMap<>();
  70. // 初始化试卷的callback,根据试卷模块进行后续处理
  71. private Map<PaperModule, InitPaper> initPaperCallback = new HashMap<>();
  72. // 初始化试卷的callback,根据试卷来源进行后续处理
  73. private Map<PaperOrigin, InitPaper> initOriginPaperCallback = new HashMap<>();
  74. // 重置试卷的callback,根据试卷模块进行后续处理
  75. private Map<PaperOrigin, InitPaper> resetPaperCallback = new HashMap<>();
  76. // 初始化报告的callback,根据试卷模块进行后续处理
  77. private Map<PaperModule, InitReport> initReportCallback = new HashMap<>();
  78. // 初始化题目,根据试卷模块进行选题处理
  79. private Map<PaperModule, InitQuestion> nextCallback = new HashMap<>();
  80. // 提交答题的callback,根据试题模块正确判断
  81. private Map<QuestionModule, SubmitQuestion> submitCallback = new HashMap<>();
  82. // 提交答题的callback,根据试题模块后续统计,会过滤满足剔除条件
  83. private Map<QuestionModule, SubmitAfterQuestion> submitAfterCallback = new HashMap<>();
  84. // 完成试卷的callback,根据试卷模块进行后续处理
  85. private Map<PaperModule, StatReport> finishCallback = new HashMap<>();
  86. public QuestionFlowService(){
  87. makePaperCallback.put(QuestionModule.BASE, (userPaper, id)->{
  88. // 获取考题时间
  89. List<QuestionNoRelation> relationList = questionNoService.listWithRelationByIds(userPaper.getQuestionNoIds());
  90. Integer time = toolsService.computerTime(relationList.toArray(new QuestionNoRelation[0]));
  91. userPaper.setTime(time);
  92. return userPaper;
  93. });
  94. makePaperCallback.put(QuestionModule.SENTENCE, (userPaper, id)->{
  95. // 获取考题时间
  96. List<SentenceQuestionRelation> relationList = sentenceQuestionService.listWithRelationByIds(userPaper.getQuestionNoIds());
  97. Integer time = toolsService.computerTime(relationList.toArray(new SentenceQuestionRelation[0]));
  98. userPaper.setTime(time);
  99. return userPaper;
  100. });
  101. makePaperCallback.put(QuestionModule.TEXTBOOK, (userPaper, id)->{
  102. // 获取考题时间
  103. List<TextbookQuestionRelation> relationList = textbookQuestionService.listWithRelationByIds(userPaper.getQuestionNoIds());
  104. Integer time = toolsService.computerTime(relationList.toArray(new TextbookQuestionRelation[0]));
  105. userPaper.setTime(time);
  106. return userPaper;
  107. });
  108. initOriginPaperCallback.put(PaperOrigin.PREVIEW, (userPaper, id)->{
  109. // id为分配表,找寻对应的paper
  110. PreviewAssign assign = previewAssignService.get(id);
  111. PreviewPaper paper = previewPaperService.get(assign.getPaperId());
  112. // 根据不同课程处理标题信息
  113. CourseModule courseModule = CourseModule.ValueOf(assign.getCourseModule());
  114. switch(courseModule){
  115. case VIDEO:
  116. case ONLINE:
  117. userPaper.setTitle(paper.getTitle());
  118. case VS:
  119. userPaper.setTitle(assign.getTitle());
  120. }
  121. // 新paper绑定当前记录关系
  122. if (userPaper.getRecordId() == 0){
  123. // 获取用户当前课程记录
  124. Integer recordId = previewService.getRecord(userPaper.getUserId(), id);
  125. userPaper.setRecordId(recordId);
  126. }
  127. userPaper.setQuestionNoIds(paper.getQuestionNoIds());
  128. // 根据papermodule得到考试时长
  129. QuestionModule module = QuestionModule.WithPaper(PaperModule.ValueOf(paper.getPaperModule()));
  130. InitPaper callback = makePaperCallback.get(module);
  131. return callback.callback(userPaper, id);
  132. });
  133. initPaperCallback.put(PaperModule.EXERCISE, (userPaper, id)->{
  134. ExercisePaper paper = exercisePaperService.get(id);
  135. userPaper.setTitle(paper.getTitle());
  136. userPaper.setQuestionNoIds(paper.getQuestionNoIds());
  137. // 获取考题时间
  138. List<QuestionNoRelation> relationList = questionNoService.listWithRelationByIds(userPaper.getQuestionNoIds());
  139. Integer time = toolsService.computerTime(relationList.toArray(new QuestionNoRelation[0]));
  140. userPaper.setTime(time);
  141. return userPaper;
  142. });
  143. initPaperCallback.put(PaperModule.SENTENCE, (userPaper, id)->{
  144. SentencePaper paper = sentencePaperService.get(id);
  145. userPaper.setTitle(paper.getTitle());
  146. userPaper.setQuestionNoIds(paper.getQuestionNoIds());
  147. userPaper.setQuestionNumber(paper.getQuestionNumber());
  148. // 获取考题时间
  149. List<SentenceQuestionRelation> relationList = sentenceQuestionService.listWithRelationByIds(userPaper.getQuestionNoIds());
  150. Integer time = toolsService.computerTime(relationList.toArray(new SentenceQuestionRelation[0]));
  151. userPaper.setTime(time);
  152. return userPaper;
  153. });
  154. initPaperCallback.put(PaperModule.TEXTBOOK, (userPaper, id)->{
  155. TextbookPaper paper = textbookPaperService.get(id);
  156. userPaper.setTitle(paper.getTitle());
  157. userPaper.setQuestionNoIds(paper.getQuestionNoIds());
  158. userPaper.setQuestionNumber(paper.getQuestionNumber());
  159. // 获取考题时间
  160. List<TextbookQuestionRelation> relationList = textbookQuestionService.listWithRelationByIds(userPaper.getQuestionNoIds());
  161. Integer time = toolsService.computerTime(relationList.toArray(new TextbookQuestionRelation[0]));
  162. userPaper.setTime(time);
  163. return userPaper;
  164. });
  165. initPaperCallback.put(PaperModule.EXAMINATION, (userPaper, id)->{
  166. ExaminationPaper paper = examinationPaperService.get(id);
  167. userPaper.setTitle(paper.getTitle());
  168. userPaper.setIsAdapt(paper.getIsAdapt());
  169. ExaminationPaper examinationPaper = examinationPaperService.get(userPaper.getOriginId());
  170. ExaminationStruct examinationStruct = examinationStructService.get(examinationPaper.getStructThree());
  171. ServiceKey serviceKey = ServiceKey.ValueOf(examinationStruct.getExtend());
  172. if (serviceKey == ServiceKey.QX_CAT) {
  173. User user = usersService.get(userPaper.getUserId());
  174. userPaper.setPaperNo(user.getQxCat());
  175. }
  176. return userPaper;
  177. });
  178. initReportCallback.put(PaperModule.EXERCISE, (report, paper)->{
  179. JSONObject setting = report.getSetting();
  180. if (setting.getBoolean("disorder")){
  181. // 随机试题: 选项随机,前端处理
  182. // report.setQuestionNoIds(this.randomQuestionNoIds(paper.getQuestionNoIds()));
  183. }
  184. });
  185. initReportCallback.put(PaperModule.SENTENCE, (report, paper)->{
  186. // 无特殊设置
  187. });
  188. initReportCallback.put(PaperModule.TEXTBOOK, (report, paper)->{
  189. // 无特殊设置
  190. });
  191. initReportCallback.put(PaperModule.EXAMINATION, (report, paper)->{
  192. JSONObject setting = report.getSetting();
  193. if (setting.getBoolean("disorder")){
  194. // 随机试题: 选项随机,前端处理
  195. // report.setQuestionNoIds(this.randomQuestionNoIds(paper.getQuestionNoIds()));
  196. }
  197. JSONArray order = setting.getJSONArray("order");
  198. // 初始化第一阶段
  199. setting.put("stage", order.getString(0));
  200. // 初始化每阶段时间, 以及做题数
  201. JSONObject time = new JSONObject();
  202. JSONObject number = new JSONObject();
  203. for(String stage : order.toJavaList(String.class)){
  204. time.put(stage, 0);
  205. number.put(stage, 0);
  206. }
  207. setting.put("time", time);
  208. setting.put("number", number);
  209. toolsService.examinationReportInit(report, order);
  210. });
  211. resetPaperCallback.put(PaperOrigin.PREVIEW, (userPaper, id)->{
  212. // 重新初始化
  213. InitPaper callback = initOriginPaperCallback.get(PaperOrigin.PREVIEW);
  214. return callback.callback(userPaper, id);
  215. });
  216. resetPaperCallback.put(PaperOrigin.EXAMINATION, (userPaper, id)->{
  217. // 如果是cat模考
  218. ExaminationPaper examinationPaper = examinationPaperService.get(userPaper.getOriginId());
  219. ExaminationStruct examinationStruct = examinationStructService.get(examinationPaper.getStructThree());
  220. ServiceKey serviceKey = ServiceKey.ValueOf(examinationStruct.getExtend());
  221. if (serviceKey == ServiceKey.QX_CAT){
  222. User user = usersService.get(userPaper.getUserId());
  223. // 创建新的paper
  224. userPaper = userPaperService.newByPaper(userPaper.getUserId(), PaperOrigin.ValueOf(userPaper.getPaperOrigin()), PaperModule.ValueOf(userPaper.getPaperModule()), userPaper.getOriginId());
  225. userPaper.setIsAdapt(userPaper.getIsAdapt());
  226. userPaper.setTitle(userPaper.getTitle());
  227. userPaper.setPaperNo(user.getQxCat());
  228. }
  229. return userPaper;
  230. });
  231. nextCallback.put(PaperModule.EXERCISE, (question, report, lastQuestion)->{
  232. Integer questionNoId = this.nextId(report.getQuestionNoIds(), lastQuestion!=null ? lastQuestion.getQuestionNoId():null);
  233. if (questionNoId == 0) return false;
  234. this.bindQuestionNo(question, questionNoId);
  235. // 设定最后一次练习记录
  236. usersService.edit(User.builder().id(question.getUserId()).latestExercise(report.getPaperId()).build());
  237. // 设定最后一次错题记录
  238. usersService.edit(User.builder().id(question.getUserId()).latestError(report.getPaperId()).build());
  239. return true;
  240. });
  241. nextCallback.put(PaperModule.SENTENCE, (question, report, lastQuestion)->{
  242. Integer questionNoId = this.nextId(report.getQuestionNoIds(), lastQuestion!=null ? lastQuestion.getQuestionNoId():null);
  243. if (questionNoId == 0) return false;
  244. SentenceQuestionRelation relation = sentenceQuestionService.relation(sentenceQuestionService.get(questionNoId));
  245. question.setQuestionNoId(relation.getId());
  246. question.setQuestionId(relation.getQuestionId());
  247. question.setQuestionType(relation.getQuestion().getQuestionType());
  248. Integer time = toolsService.computerTime(relation);
  249. question.setTime(time);
  250. return true;
  251. });
  252. nextCallback.put(PaperModule.TEXTBOOK, (question, report, lastQuestion)->{
  253. Integer questionNoId = this.nextId(report.getQuestionNoIds(), lastQuestion!=null ? lastQuestion.getQuestionNoId():null);
  254. if (questionNoId == 0) return false;
  255. TextbookQuestionRelation relation = textbookQuestionService.relation(textbookQuestionService.get(questionNoId));
  256. question.setQuestionNoId(relation.getId());
  257. question.setQuestionId(relation.getQuestionId());
  258. question.setQuestionType(relation.getQuestion().getQuestionType());
  259. Integer time = toolsService.computerTime(relation);
  260. question.setTime(time);
  261. return true;
  262. });
  263. nextCallback.put(PaperModule.EXAMINATION, (question, report, lastQuestion)->{
  264. ExaminationPaper paper = examinationPaperService.get(report.getOriginId());
  265. if (!examinationCompute(paper, report, lastQuestion, question)){
  266. return false;
  267. }
  268. // 保存report: 更新setting
  269. userReportService.edit(UserReport.builder().id(report.getId()).setting(report.getSetting()).build());
  270. return true;
  271. });
  272. submitCallback.put(QuestionModule.BASE, (userQuestion, userReport)->{
  273. // 判断答题情况
  274. JSONObject userAnswer = userQuestion.getUserAnswer();
  275. Question question = questionService.get(userQuestion.getQuestionId());
  276. // 作文统计字数
  277. if (question.getQuestionType().equals(QuestionType.AWA.key)){
  278. JSONObject detail = new JSONObject();
  279. String awa = userAnswer.getString("awa");
  280. String base = awa.replaceAll("/<[^>]+>/g", "")
  281. .replaceAll("/[,.+-:;']+/g", "");
  282. detail.put("words", base.split(" ").length);
  283. userQuestion.setDetail(detail);
  284. return false;
  285. }
  286. JSONObject answer = question.getAnswer();
  287. return (boolean) this.baseAnswer(userAnswer, answer, question);
  288. });
  289. submitCallback.put(QuestionModule.SENTENCE, (userQuestion, userReport)->{
  290. // 判断答题情况
  291. JSONObject userAnswer = userQuestion.getUserAnswer();
  292. Question question = questionService.get(userQuestion.getQuestionId());
  293. JSONObject answer = question.getAnswer();
  294. boolean correct = true;
  295. JSONObject detail = new JSONObject();
  296. boolean subjectCorrect = this.sentenceAnswer(userAnswer.getJSONArray("subject"), answer.getJSONArray("subject"));
  297. detail.put("subject", subjectCorrect);
  298. correct = correct & subjectCorrect;
  299. boolean predicateCorrect = this.sentenceAnswer(userAnswer.getJSONArray("predicate"), answer.getJSONArray("predicate"));
  300. detail.put("predicate", predicateCorrect);
  301. correct = correct & predicateCorrect;
  302. boolean objectCorrect = this.sentenceAnswer(userAnswer.getJSONArray("object"), answer.getJSONArray("object"));
  303. detail.put("object", objectCorrect);
  304. correct = correct & objectCorrect;
  305. boolean optionsCorrect = this.sentenceAnswerOption(userAnswer.getJSONArray("options"), answer.getJSONArray("options"));
  306. detail.put("options", optionsCorrect);
  307. // correct = correct & optionsCorrect;
  308. userQuestion.setDetail(detail);
  309. // 主谓宾判断正确,答题正确
  310. return correct;
  311. });
  312. submitCallback.put(QuestionModule.TEXTBOOK, (userQuestion, userReport)->{
  313. // 判断答题情况
  314. JSONObject userAnswer = userQuestion.getUserAnswer();
  315. Question question = questionService.get(userQuestion.getQuestionId());
  316. JSONObject answer = question.getAnswer();
  317. return this.baseAnswer(userAnswer, answer, question);
  318. });
  319. submitAfterCallback.put(QuestionModule.BASE, (userQuestion, question)->{
  320. // 作文不统计
  321. if (question.getQuestionType().equals(QuestionType.AWA.key)){
  322. return;
  323. }
  324. // 更新题目及题目编号统计
  325. questionNoService.accumulation(userQuestion);
  326. questionService.accumulation(userQuestion);
  327. // 统计答案分布
  328. this.answerDistributed(userQuestion, question);
  329. });
  330. submitAfterCallback.put(QuestionModule.SENTENCE, (userQuestion, question)->{
  331. // 更新题目及长难句统计
  332. sentenceQuestionService.accumulation(userQuestion);
  333. questionService.accumulation(userQuestion);
  334. });
  335. submitAfterCallback.put(QuestionModule.TEXTBOOK, (userQuestion, question)->{
  336. // 更新题目及机经统计
  337. textbookQuestionService.accumulation(userQuestion);
  338. questionService.accumulation(userQuestion);
  339. this.answerDistributed(userQuestion, question);
  340. });
  341. finishCallback.put(PaperModule.EXERCISE, (report, questionList)->{
  342. report.setDetail(this.statExerciseReport(report, questionList));
  343. });
  344. finishCallback.put(PaperModule.SENTENCE, (report, questionList)->{
  345. report.setDetail(this.statSentenceReport(report, questionList));
  346. });
  347. finishCallback.put(PaperModule.TEXTBOOK, (report, questionList)->{
  348. report.setDetail(this.statTextbookReport(report, questionList));
  349. });
  350. finishCallback.put(PaperModule.EXAMINATION, (report, questionList)->{
  351. this.statExaminationReport(report, questionList);
  352. });
  353. }
  354. /**
  355. * 自由组卷:根据题目编号id
  356. * @param userId
  357. * @param origin
  358. * @param questionNoIds
  359. * @param filterTimes
  360. * @return
  361. */
  362. @Transactional
  363. public UserPaper makePaper(Integer userId, QuestionModule module, PaperOrigin origin, List<Integer> questionNoIds, Integer filterTimes){
  364. // PaperOrigin只允许Error和Collect
  365. if (questionNoIds.size() == 0){
  366. throw new ParameterException("题目数为空");
  367. }
  368. // todo 题目数不能超过50
  369. // todo 不同类型不能一起组卷
  370. QuestionOrigin questionOrigin = QuestionOrigin.WithPaper(origin);
  371. if (filterTimes > 0){
  372. // 过滤重复多次的题目
  373. questionNoIds = userPaperQuestionService.filterTimesQuestion(userId, questionOrigin, module, questionNoIds, filterTimes);
  374. if (questionNoIds.size() == 0){
  375. throw new ParameterException("题目数为空");
  376. }
  377. }
  378. UserPaper paper = userPaperService.newByPaper(userId, origin, PaperModule.WithQuestion(module), 0);
  379. paper.setQuestionNumber(questionNoIds.size());
  380. paper.setQuestionNoIds(questionNoIds.toArray(new Integer[0]));
  381. InitPaper callback = makePaperCallback.get(module);
  382. paper = callback.callback(paper, 0);
  383. paper = userPaperService.add(paper);
  384. // 绑定关系,用于下次处理过滤
  385. userPaperQuestionService.addOrigin(userId, paper.getId(), questionOrigin, module, questionNoIds);
  386. return paper;
  387. }
  388. /**
  389. * 获取做题paper
  390. * @param userId
  391. * @param origin
  392. * @param paperId
  393. * @return
  394. */
  395. @Transactional
  396. public UserPaper paper(Integer userId, PaperOrigin origin, Integer paperId){
  397. PaperModule module = PaperModule.WithOrigin(origin);
  398. UserPaper paper = userPaperService.getByPaper(userId, origin, paperId);
  399. if (paper == null){
  400. paper = userPaperService.newByPaper(userId, origin, module, paperId);
  401. // 先判断来源初始化,如果没有,则根据模块初始化
  402. InitPaper callback = initOriginPaperCallback.get(origin);
  403. if (callback == null) {
  404. callback = initPaperCallback.get(module);
  405. }
  406. paper = callback.callback(paper, paperId);
  407. paper = userPaperService.add(paper);
  408. }
  409. return paper;
  410. }
  411. /**
  412. * 开始新一轮做题
  413. * @param userId
  414. * @param origin
  415. * @param paperId
  416. * @param setting
  417. * @return
  418. */
  419. @Transactional
  420. public UserReportRelation start(Integer userId, PaperOrigin origin, Integer paperId, JSONObject setting){
  421. UserPaper paper = paper(userId, origin, paperId);
  422. // 查找对应的report是否有,如果没有或reset为1,则添加
  423. UserReport userReport = null;
  424. if (paper.getIsReset() > 0) {
  425. paper.setIsReset(0);
  426. // 是否对重置有特殊处理
  427. InitPaper callback = resetPaperCallback.get(origin);
  428. if (callback != null){
  429. paper = callback.callback(paper, paperId);
  430. }
  431. if (paper.getId() != null){
  432. userPaperService.edit(paper);
  433. }else{
  434. paper = userPaperService.add(paper);
  435. }
  436. }else if(setting == null){
  437. // 对于长难句这种没有设置开始页的,读取最后一次
  438. userReport = userReportService.getLastByPaper(userId, paper.getId());
  439. }
  440. if (userReport == null){
  441. userReport = userReportService.newByPaper(paper, setting);
  442. InitReport callback = initReportCallback.get(PaperModule.ValueOf(paper.getPaperModule()));
  443. callback.callback(userReport, paper);
  444. userReportService.add(userReport);
  445. }
  446. return relationReport(userReport);
  447. }
  448. /**
  449. * 继续做题:判断是否可以继续
  450. * @param userId
  451. * @param userReportId
  452. * @return
  453. */
  454. public UserReportRelation continueReport(Integer userId, Integer userReportId){
  455. UserReport userReport = userReportService.get(userReportId);
  456. if (!userReport.getUserId().equals(userId)){
  457. throw new ParameterException("试卷不存在");
  458. }
  459. if (userReport.getDetail() != null && userReport.getFinishTime() != null){
  460. throw new ParameterException("做题结束");
  461. }
  462. if (userReport.getUserNumber()>=userReport.getQuestionNumber()){
  463. throw new ParameterException("答题结束,请提交完成");
  464. }
  465. return relationReport(userReport);
  466. }
  467. /**
  468. * 获取单个report信息:基础
  469. * @param userId
  470. * @param userReportId
  471. * @return
  472. */
  473. public UserReportRelation baseReport(Integer userId, Integer userReportId){
  474. UserReport userReport = userReportService.get(userReportId);
  475. if (!userReport.getUserId().equals(userId)){
  476. throw new ParameterException("试卷不存在");
  477. }
  478. return relationReport(userReport);
  479. }
  480. /**
  481. * 获取report的下一道题
  482. * @param userId
  483. * @param userReportId
  484. * @return
  485. */
  486. @Transactional
  487. public UserQuestion next(Integer userId, Integer userReportId){
  488. UserQuestion userQuestion = userQuestionService.getLastByReport(userId, userReportId);
  489. // 查找未完成的questionId
  490. if (userQuestion==null || userQuestion.getUserTime() >0){
  491. // 创建新的question
  492. UserReport userReport = userReportService.get(userReportId);
  493. if (!userReport.getUserId().equals(userId)){
  494. throw new ParameterException("试卷不存在");
  495. }
  496. UserQuestion lastQuestion = userQuestion;
  497. userQuestion = userQuestionService.newByReport(userReport, lastQuestion);
  498. InitQuestion callback = nextCallback.get(PaperModule.ValueOf(userReport.getPaperModule()));
  499. callback.callback(userQuestion, userReport, lastQuestion);
  500. userQuestion = userQuestionService.add(userQuestion);
  501. }
  502. return userQuestion;
  503. }
  504. /**
  505. * 提交试题
  506. * @param userId
  507. * @param userQuestion
  508. * @return
  509. */
  510. @Transactional
  511. public Boolean submit(Integer userId, UserQuestion userQuestion){
  512. if (!userQuestion.getUserId().equals(userId)){
  513. throw new ParameterException("题目不存在");
  514. }
  515. QuestionModule module = QuestionModule.ValueOf(userQuestion.getQuestionModule());
  516. UserReport userReport = userReportService.get(userQuestion.getReportId());
  517. SubmitQuestion callback = submitCallback.get(module);
  518. Boolean result = callback.callback(userQuestion, userReport);
  519. userQuestion.setIsCorrect(result ? 1 : 0);
  520. // 如果做错,从移除错题中移除
  521. if(!result){
  522. userPaperQuestionService.removeRemoveError(userId, module, userQuestion.getQuestionNoId());
  523. }
  524. userQuestionService.edit(userQuestion);
  525. // 根据剔除逻辑判断是否统计
  526. if (toolsService.filterTime(userQuestion)){
  527. Question question = questionService.get(userQuestion.getQuestionId());
  528. SubmitAfterQuestion afterCallback = submitAfterCallback.get(module);
  529. afterCallback.callback(userQuestion, question);
  530. }
  531. // 更新对应report记录
  532. userReportService.accumulation(userQuestion);
  533. // 自动finish
  534. if (userReport.getQuestionNumber().equals(userReport.getUserNumber())){
  535. this.finish(userId, userReport.getId());
  536. }
  537. return true;
  538. }
  539. /**
  540. * 模考进入下一阶段:调整出题逻辑,上一阶段都当成未完成
  541. * @param userId
  542. * @param userReportId
  543. * @return
  544. */
  545. @Transactional
  546. public Boolean stage(Integer userId, Integer userReportId){
  547. UserReport userReport = userReportService.get(userReportId);
  548. if (!userReport.getUserId().equals(userId)){
  549. throw new ParameterException("试卷不存在");
  550. }
  551. if (userReport.getDetail() != null && userReport.getFinishTime() != null){
  552. throw new ParameterException("做题结束");
  553. }
  554. PaperOrigin origin = PaperOrigin.ValueOf(userReport.getPaperOrigin());
  555. if (origin != PaperOrigin.EXAMINATION){
  556. throw new ParameterException("不是模考试卷");
  557. }
  558. ExaminationPaper paper = examinationPaperService.get(userReport.getOriginId());
  559. JSONObject setting = userReport.getSetting();
  560. // 当前stage,补全所有时间,切换成下一个stage
  561. JSONArray order = setting.getJSONArray("order");
  562. String stage = setting.getString("stage");
  563. JSONObject time = setting.getJSONObject("time");
  564. JSONObject number = setting.getJSONObject("number");
  565. Integer useTime = time.getInteger(stage);
  566. Integer totalTime = toolsService.examinationSubjectTime(stage);
  567. time.put(stage, totalTime);
  568. // 自动提交所有该stage的题目
  569. Integer totalNumber = toolsService.examinationSubjectNumber(stage);
  570. // 自动提交最后一题
  571. UserQuestion lastQuestion = userQuestionService.getLastByReport(userId, userReportId);
  572. UserQuestion question;
  573. if(lastQuestion != null && lastQuestion.getUserTime() == 0){
  574. lastQuestion.setUserTime(totalTime - useTime);
  575. this.submit(userId, lastQuestion);
  576. }
  577. // 判断未完成题目数,自动生成
  578. question = userQuestionService.newByReport(userReport, lastQuestion);
  579. while(number.getIntValue(stage) < totalNumber){
  580. examinationCompute(paper, userReport, lastQuestion, question);
  581. question = userQuestionService.add(question);
  582. lastQuestion = question;
  583. question = userQuestionService.newByReport(userReport, lastQuestion);
  584. }
  585. // 更新setting
  586. userReportService.edit(UserReport.builder()
  587. .id(userReportId)
  588. .setting(setting).build());
  589. // 如果是最后阶段。直接完成
  590. int index = order.indexOf(stage);
  591. if (index == order.size() - 1){
  592. // 完成所有阶段,结束考试
  593. this.finish(userId, userReport.getId());
  594. }
  595. return true;
  596. }
  597. /**
  598. * 完成试卷,进行试卷分析
  599. * @param userId
  600. * @param userReportId
  601. * @return
  602. */
  603. @Transactional
  604. public Boolean finish(Integer userId, Integer userReportId){
  605. UserReport userReport = userReportService.get(userReportId);
  606. if (!userReport.getUserId().equals(userId)){
  607. throw new ParameterException("试卷不存在");
  608. }
  609. if (userReport.getIsFinish() > 0){
  610. return true;
  611. }
  612. userReport.setFinishTime(new Date());
  613. userReport.setIsFinish(1);
  614. List<UserQuestion> userQuestionList = userQuestionService.listByReport(userId, userReportId);
  615. // 分析做题结果
  616. StatReport callback = finishCallback.get(PaperModule.ValueOf(userReport.getPaperModule()));
  617. callback.callback(userReport, userQuestionList);
  618. userReport.setIsStat(1);
  619. userReportService.edit(userReport);
  620. // 统计: 更新对应paper记录
  621. userPaperService.accumulation(userReport);
  622. return true;
  623. }
  624. /**
  625. * 重新开始一份试卷:设定试卷reset=1,列表不绑定最后一次考试记录
  626. * @param userPaperId
  627. * @param userId
  628. * @return
  629. */
  630. @Transactional
  631. public Boolean restart(Integer userPaperId, Integer userId){
  632. // 获取最后一次report,并生成结果
  633. UserReport userReport = userReportService.getLastByPaper(userId, userPaperId);
  634. List<UserQuestion> userQuestionList = userQuestionService.listByReport(userId, userReport.getId());
  635. // 分析做题结果
  636. StatReport callback = finishCallback.get(PaperModule.ValueOf(userReport.getPaperModule()));
  637. callback.callback(userReport, userQuestionList);
  638. userReport.setIsStat(1);
  639. userReportService.edit(userReport);
  640. return userPaperService.reset(userPaperId, userId);
  641. }
  642. /**
  643. * 获取提问权限记录
  644. * @param questionType
  645. * @return
  646. */
  647. public Integer questionRelationCourse(Integer userId, Integer assignId, QuestionType questionType){
  648. if (assignId != null){
  649. Integer assignRecordId = previewService.questionCourse(userId, assignId);
  650. if (assignRecordId != null) return assignRecordId;
  651. }
  652. return courseExtendService.questionRelationCourse(userId, questionType);
  653. }
  654. /**
  655. * 累计考试学习时间
  656. * @param userId
  657. * @return
  658. */
  659. public Integer studyTime(Integer userId, Date startTime, Date endTime){
  660. UserRecordStatRelation record = userQuestionService.stat(userId, startTime != null? startTime.toString():null, endTime != null ? endTime.toString(): null);
  661. return record != null ? record.getUserTime() : 0;
  662. }
  663. /**
  664. * 平均考试时间
  665. * @return
  666. */
  667. public Integer studyAvgTime(Date startTime, Date endTime){
  668. UserRecordStatRelation record = userQuestionService.statAvg(startTime != null? startTime.toString():null, endTime != null ? endTime.toString(): null);
  669. return record != null ? record.getUserTime() : 0;
  670. }
  671. /**
  672. * 模考完整出题逻辑
  673. * @param paper
  674. * @param report
  675. * @param lastQuestion
  676. * @param question
  677. * @return
  678. */
  679. public boolean examinationCompute(ExaminationPaper paper, UserReport report, UserQuestion lastQuestion, UserQuestion question){
  680. JSONObject setting = report.getSetting();
  681. JSONArray order = setting.getJSONArray("order");
  682. String stage = setting.getString("stage");
  683. JSONObject time = setting.getJSONObject("time");
  684. JSONObject number = setting.getJSONObject("number");
  685. time.put(stage, time.getIntValue(stage)+ lastQuestion.getUserTime());
  686. Integer totalNumber = toolsService.examinationSubjectNumber(stage);
  687. // 判断数量是否已经完成
  688. if (number.getIntValue(stage) >= totalNumber){
  689. // 进入下一阶段
  690. int index = order.indexOf(stage);
  691. if (index == order.size() - 1){
  692. // 完成所有阶段,结束考试
  693. return false;
  694. }
  695. stage = order.getString(index + 1);
  696. setting.put("stage", stage);
  697. // 重置stage数
  698. question.setStageNo(1);
  699. question.setStage(stage);
  700. }
  701. // 获取本阶段完成数,剩余题目数
  702. Integer subnumber = number.getIntValue(stage);
  703. Integer surplus = totalNumber - subnumber;
  704. QuestionSubject subject = QuestionSubject.ValueOf(stage);
  705. List<String> questionTypes = QuestionType.FromSubject(subject);
  706. List<UserQuestion> userQuestionList = userQuestionService.listByReportAndType(report.getUserId(), report.getId(), questionTypes);
  707. Collection ids = Transform.getIds(userQuestionList, UserQuestion.class, "questionNoId");
  708. // 根据设置出题
  709. Integer questionNoId = 0;
  710. if (paper.getIsAdapt() > 0 && QuestionSubject.SupportAdapt(subject)){
  711. switch(subject){
  712. case VERBAL:
  713. questionNoId = verbalCompute(paper, setting, subnumber, ids, userQuestionList);
  714. break;
  715. case QUANT:
  716. questionNoId = quantCompute(paper, setting, subnumber, ids, userQuestionList);
  717. break;
  718. default:
  719. throw new ParameterException("模考出题流程错误:"+subject.key+"不支持适应性判断");
  720. }
  721. }else{
  722. questionNoId = randomCompute(subject, paper, questionTypes, setting, subnumber, ids, userQuestionList);
  723. }
  724. if (questionNoId == 0) {
  725. throw new ParameterException("模考出题流程错误:题目生成错误");
  726. }
  727. QuestionNoRelation relation = questionNoService.getWithRelation(questionNoId);
  728. question.setQuestionNoId(relation.getId());
  729. question.setQuestionId(relation.getQuestionId());
  730. question.setQuestionType(relation.getQuestion().getQuestionType());
  731. question.setTime(toolsService.computerTime(relation));
  732. // 更新题目数
  733. number.put(stage, subnumber + 1);
  734. return true;
  735. }
  736. /**
  737. * 语文出题计算
  738. * @param setting
  739. * @param subnumber
  740. * @param ids
  741. * @param subQuestionList
  742. * @return
  743. */
  744. public Integer verbalCompute(ExaminationPaper paper, JSONObject setting, Integer subnumber, Collection ids, List<UserQuestion> subQuestionList){
  745. // 一共分为4个阶段:每个阶段9题,包含一题阅读
  746. // 其中句改SC有14题,阅读RC有13题(共4篇阅读,每篇题数为3、3、3、4),逻辑CR为9题
  747. // verbal: { "steps": [{"ids": [], "level": 0}, {}] }
  748. List questionNoIds = new ArrayList<>();
  749. JSONObject verbal = setting.getJSONObject("verbal");
  750. if (verbal == null) {
  751. verbal = new JSONObject();
  752. verbal.put("steps", new JSONArray());
  753. setting.put("verbal", verbal);
  754. }
  755. JSONArray steps = verbal.getJSONArray("steps");
  756. // 判断当前是第几阶段
  757. Integer step = subnumber / examinationService.verbalPre + 1;
  758. Integer questionIndex = 0;
  759. JSONObject info;
  760. if (subnumber == 0){
  761. // 初始化
  762. info = examinationService.initVerbal(paper.getStructThree());
  763. steps.add(info);
  764. }else if(subnumber % examinationService.verbalPre == 0){
  765. info = steps.getJSONObject(step);
  766. List currentIds = info.getJSONArray("ids").toJavaObject(questionNoIds.getClass());
  767. // 计算上阶段的做题情况
  768. long correct = subQuestionList.stream().filter((x)->currentIds.contains(x.getQuestionNoId()) && x.getIsCorrect() > 0).count();
  769. // 下一阶段
  770. Integer level = examinationService.verbalNextLevel(info.getInteger("level"), examinationService.verbalPre, correct);
  771. Map<String, Integer> typeNumber = examinationService.statTypeNumber(subQuestionList);
  772. info = examinationService.generateVerbal(paper.getStructThree(), level, typeNumber, ids);
  773. steps.add(info);
  774. }else{
  775. info = steps.getJSONObject(step);
  776. questionIndex = subnumber % examinationService.verbalPre;
  777. }
  778. //获取下一题
  779. questionNoIds = info.getJSONArray("ids").toJavaObject(questionNoIds.getClass());
  780. return (Integer) questionNoIds.get(questionIndex);
  781. }
  782. /**
  783. * 数学出题计算
  784. * @param setting
  785. * @param subnumber
  786. * @param ids
  787. * @param subQuestionList
  788. * @return
  789. */
  790. public Integer quantCompute(ExaminationPaper paper, JSONObject setting, Integer subnumber, Collection ids, List<UserQuestion> subQuestionList){
  791. // 一共分为4个阶段:每个阶段题分别为8、8、8、7题,合计31题
  792. // 其中数学PS有17题,数学DS有14题
  793. // quant: { "steps": [{"ids": [], "level": 0}, {}] }
  794. List questionNoIds = new ArrayList<>();
  795. JSONObject quant = setting.getJSONObject("quant");
  796. if (quant == null) {
  797. quant = new JSONObject();
  798. quant.put("steps", new JSONArray());
  799. setting.put("quant", quant);
  800. }
  801. JSONArray steps = quant.getJSONArray("steps");
  802. // 判断当前是第几阶段
  803. Integer step = examinationService.quantStep(subnumber);
  804. Integer nextStep = examinationService.quantStep(subnumber+1);
  805. Integer questionIndex = 0;
  806. JSONObject info;
  807. if (subnumber == 0){
  808. // 初始化
  809. info = examinationService.initQuant(paper.getStructThree());
  810. steps.add(info);
  811. }else if(step < nextStep){
  812. info = steps.getJSONObject(step);
  813. List currentIds = info.getJSONArray("ids").toJavaObject(questionNoIds.getClass());
  814. // 计算上阶段的做题情况
  815. long correct = subQuestionList.stream().filter((x)->currentIds.contains(x.getQuestionNoId()) && x.getIsCorrect() > 0).count();
  816. // 下一阶段
  817. Integer level = examinationService.quantNextLevel(info.getInteger("level"), examinationService.quantBaseLevel[step], correct, step);
  818. Map<String, Integer> typeNumber = examinationService.statTypeNumber(subQuestionList);
  819. info = examinationService.generateQuant(paper.getStructThree(), level, typeNumber, ids, nextStep);
  820. steps.add(info);
  821. }else{
  822. info = steps.getJSONObject(step);
  823. questionIndex = subnumber - examinationService.quantNumber[step];
  824. }
  825. //获取下一题
  826. questionNoIds = info.getJSONArray("ids").toJavaObject(questionNoIds.getClass());
  827. return (Integer) questionNoIds.get(questionIndex);
  828. }
  829. /**
  830. * 随机出题计算
  831. * @param subject
  832. * @param paper
  833. * @param questionTypes
  834. * @param setting
  835. * @param subnumber
  836. * @param ids
  837. * @param subQuestionList
  838. * @return
  839. */
  840. public Integer randomCompute(QuestionSubject subject, ExaminationPaper paper, List<String> questionTypes, JSONObject setting, Integer subnumber, Collection ids, List<UserQuestion> subQuestionList){
  841. // 随机挑题
  842. switch (subject){
  843. case VERBAL:
  844. // 固定顺序抽取阅读题
  845. if(examinationService.verbalRC(subnumber)){
  846. // 第一次抽取4题,后面抽取3题,和适应性一致
  847. JSONObject rc = setting.getJSONObject("rc");
  848. Integer number = 0;
  849. if (rc == null) {
  850. rc = new JSONObject();
  851. setting.put("rc", rc);
  852. number = 4;
  853. }else{
  854. number = 3;
  855. }
  856. Integer[] questions = questionNoService.randomExaminationRc(paper.getStructThree(), number, rc.values());
  857. // 写入后续题目关系
  858. Integer position = subnumber;
  859. for(int q: questions){
  860. rc.put(position.toString(), q);
  861. position += 1;
  862. }
  863. }
  864. // 判断是否后续阅读题
  865. JSONObject rc = setting.getJSONObject("rc");
  866. if(rc.getInteger(subnumber.toString()) != null){
  867. return rc.getIntValue(subnumber.toString());
  868. }
  869. break;
  870. }
  871. Map<String, Integer> typeNumber = examinationService.statTypeNumber(subQuestionList);
  872. List<String> targetTypes = examinationService.needQuestionTypes(typeNumber, questionTypes);
  873. // 不主动查询阅读题:targetTypes没有rc
  874. return questionNoService.randomExamination(paper.getStructThree(), targetTypes, ids);
  875. }
  876. /**
  877. * 获取报告题目列表
  878. * @param userReportId
  879. * @param userId
  880. * @return
  881. */
  882. public List<UserQuestion> listByReport(Integer userReportId, Integer userId){
  883. List<UserQuestion> userQuestionList = userQuestionService.listByReport(userId, userReportId);
  884. return userQuestionList;
  885. }
  886. /**
  887. * 乱序生成题目列表
  888. * @param questionNoIds
  889. * @return
  890. */
  891. private Integer[] randomQuestionNoIds(Integer[] questionNoIds){
  892. Integer[] ran = new Integer[questionNoIds.length];
  893. List<Integer> base = Arrays.stream(questionNoIds).collect(Collectors.toList());
  894. int length = base.size();
  895. for(int i = 0; i < ran.length; i++){
  896. ran[i] = base.remove((int)(Math.random()*length));
  897. length -= 1;
  898. }
  899. return ran;
  900. }
  901. /**
  902. * 顺序获取下一题
  903. * @param ids
  904. * @param id
  905. * @return
  906. */
  907. private Integer nextId(Integer[] ids, Integer id){
  908. if (id == null) return ids[0];
  909. boolean flag = false;
  910. for(Integer a : ids){
  911. if (a.equals(id)){
  912. flag = true;
  913. continue;
  914. }
  915. if (flag){
  916. return a;
  917. }
  918. }
  919. return 0;
  920. }
  921. /**
  922. * 关联绑定questionNo类型试题
  923. * @param question
  924. * @param questionNoId
  925. */
  926. private void bindQuestionNo(UserQuestion question, Integer questionNoId){
  927. QuestionNoRelation relation = questionNoService.getWithRelation(questionNoId);
  928. question.setQuestionNoId(relation.getId());
  929. question.setQuestionId(relation.getQuestionId());
  930. question.setQuestionType(relation.getQuestion().getQuestionType());
  931. Integer time = toolsService.computerTime(relation);
  932. question.setTime(time);
  933. }
  934. /**
  935. * 获取报表关联试卷
  936. * @param p
  937. * @return
  938. */
  939. private UserReportRelation relationReport(UserReport p){
  940. UserReportRelation relation = Transform.convert(p, UserReportRelation.class);
  941. UserPaper paper = userPaperService.get(p.getPaperId());
  942. relation.setPaper(paper);
  943. return relation;
  944. }
  945. /**
  946. * 基本题型的答案判断
  947. * @param userAnswer
  948. * @param answer
  949. * @param question
  950. * @return
  951. */
  952. private Boolean baseAnswer(JSONObject userAnswer, JSONObject answer, Question question){
  953. String type = question.getContent().getString("type");
  954. QuestionContentType contentType = QuestionContentType.ValueOf(type);
  955. JSONArray userQuestions = userAnswer.getJSONArray("questions");
  956. JSONArray questions = answer.getJSONArray("questions");
  957. for(int i = 0; i< questions.size(); i++){
  958. JSONObject userOne = userQuestions.getJSONObject(i);
  959. JSONObject one = questions.getJSONObject(i);
  960. switch(contentType){
  961. case DOUBLE:
  962. JSONArray userDoubleList = userOne.getJSONArray("double");
  963. JSONArray doubleList = one.getJSONArray("double");
  964. // if(JSONObject.toJSON(userDoubleList) != JSONObject.toJSON(doubleList)){
  965. // return false;
  966. // }
  967. for(int j = 0; j < doubleList.size(); j++){
  968. JSONArray singleList = doubleList.getJSONArray(j);
  969. JSONArray userSingleList = userDoubleList.getJSONArray(i);
  970. for (int k = 0; k < singleList.size(); k++){
  971. if (userSingleList.getBoolean(k) != singleList.getBoolean(k)){
  972. return false;
  973. }
  974. }
  975. }
  976. break;
  977. case SINGLE:
  978. case INLINE:
  979. default:
  980. JSONArray userSingleList = userOne.getJSONArray("single");
  981. JSONArray singleList = one.getJSONArray("single");
  982. // if(JSONObject.toJSON(userSingleList) != JSONObject.toJSON(singleList)){
  983. // return false;
  984. // }
  985. for(int j = 0; j < singleList.size(); j++){
  986. if (userSingleList.getBoolean(j) != singleList.getBoolean(j)){
  987. return false;
  988. }
  989. }
  990. }
  991. }
  992. return true;
  993. }
  994. /**
  995. * 长难句单个选项答案判断
  996. * @param userAnswer
  997. * @param answer
  998. * @return
  999. */
  1000. private Boolean sentenceAnswer(JSONArray userAnswer, JSONArray answer){
  1001. // 数量一致,并且都包含
  1002. for(Object a : answer){
  1003. JSONArray singleArray = (JSONArray) a;
  1004. if (singleArray == null){
  1005. return userAnswer == null;
  1006. }
  1007. if (userAnswer != null && singleArray.size() == userAnswer.size()){
  1008. for (int i = 0; i < singleArray.size(); i++){
  1009. JSONObject single = singleArray.getJSONObject(i);
  1010. JSONObject user = userAnswer.getJSONObject(i);
  1011. // 判断uuid是否一致
  1012. if (!single.getString("uuid").equals(user.getString("uuid"))){
  1013. return false;
  1014. }
  1015. }
  1016. return true;
  1017. }
  1018. }
  1019. return false;
  1020. }
  1021. /**
  1022. * 长难句多选答案判断
  1023. * @param userAnswer
  1024. * @param answer
  1025. * @return
  1026. */
  1027. private Boolean sentenceAnswerOption(JSONArray userAnswer, JSONArray answer){
  1028. // 数量一致,并且都包含
  1029. if (userAnswer.size() == answer.size()){
  1030. for(Object s : userAnswer){
  1031. if (!answer.contains(s)){
  1032. return false;
  1033. }
  1034. }
  1035. }else{
  1036. return false;
  1037. }
  1038. return true;
  1039. }
  1040. /**
  1041. * 统计答案分布
  1042. * @param userQuestion
  1043. * @param question
  1044. */
  1045. private void answerDistributed(UserQuestion userQuestion, Question question){
  1046. JSONObject answerDistributed = question.getAnswerDistributed();
  1047. JSONObject answer = question.getAnswer();
  1048. JSONObject userAnswer = userQuestion.getUserAnswer();
  1049. String type = question.getContent().getString("type");
  1050. QuestionContentType contentType = QuestionContentType.ValueOf(type);
  1051. JSONArray userQuestions = userAnswer.getJSONArray("questions");
  1052. JSONArray questions = answer.getJSONArray("questions");
  1053. JSONArray distributed = answerDistributed.getJSONArray("questions");
  1054. if (distributed == null || distributed.isEmpty()){
  1055. distributed = new JSONArray();
  1056. answerDistributed.put("questions", distributed);
  1057. }
  1058. for(int i = 0; i< questions.size(); i++){
  1059. JSONObject userOne = userQuestions.getJSONObject(i);
  1060. JSONObject one = questions.getJSONObject(i);
  1061. JSONObject target = distributed.getJSONObject(i);
  1062. if (target == null || target.isEmpty()){
  1063. target = new JSONObject();
  1064. distributed.add(i, target);
  1065. }
  1066. switch(contentType){
  1067. case DOUBLE:
  1068. JSONArray userDoubleList = userOne.getJSONArray("double");
  1069. JSONArray doubleList = one.getJSONArray("double");
  1070. JSONArray doubleResult = target.getJSONArray("double");
  1071. if (doubleResult == null || doubleResult.isEmpty()){
  1072. doubleResult = new JSONArray();
  1073. target.put("double", doubleResult);
  1074. }
  1075. for(int j = 0; j < doubleList.size(); j++){
  1076. JSONArray singleList = doubleList.getJSONArray(j);
  1077. JSONArray userSingleList = userDoubleList.getJSONArray(i);
  1078. JSONArray singleResult = doubleResult.getJSONArray(j);
  1079. if (singleResult == null){
  1080. singleResult = new JSONArray(0);
  1081. doubleResult.set(j, singleResult);
  1082. }
  1083. for (int k = 0; k < singleList.size(); k++){
  1084. if (singleResult.get(k) == null){
  1085. singleResult.set(k, 0);
  1086. }
  1087. if (userSingleList.getBoolean(k)){
  1088. singleResult.set(k, singleResult.getIntValue(k)+1);
  1089. }
  1090. }
  1091. }
  1092. break;
  1093. case SINGLE:
  1094. case INLINE:
  1095. default:
  1096. JSONArray userSingleList = userOne.getJSONArray("single");
  1097. JSONArray singleList = one.getJSONArray("single");
  1098. JSONArray singleResult = target.getJSONArray("single");
  1099. if (singleResult == null || singleResult.isEmpty()){
  1100. singleResult = new JSONArray();
  1101. target.put("single", singleResult);
  1102. }
  1103. for(int j = 0; j < singleList.size(); j++){
  1104. if (singleResult.get(j) == null){
  1105. singleResult.set(j, 0);
  1106. }
  1107. if (userSingleList.getBoolean(j)){
  1108. singleResult.set(j, singleResult.getIntValue(j)+1);
  1109. }
  1110. }
  1111. }
  1112. }
  1113. questionService.edit(Question.builder().id(question.getId())
  1114. .answerDistributed(answerDistributed)
  1115. .build());
  1116. }
  1117. /**
  1118. * 根据练习报告格式,统计信息
  1119. * @param report
  1120. * @param questionList
  1121. * @return
  1122. */
  1123. private JSONObject statExerciseReport(UserReport report, List<UserQuestion> questionList){
  1124. UserPaper paper = userPaperService.get(report.getPaperId());
  1125. Collection questionNoIds = Transform.getIds(questionList, UserQuestion.class, "questionNoId");
  1126. Map<Number, QuestionNoRelation> relationMap = questionNoService.mapWithRelationByIds((Integer[])questionNoIds.toArray());
  1127. // report
  1128. JSONObject detail = new JSONObject();
  1129. JSONArray pace = new JSONArray();
  1130. JSONObject difficultMap = new JSONObject();
  1131. JSONObject placeMap = new JSONObject();
  1132. for (UserQuestion userQuestion:questionList){
  1133. QuestionNoRelation relation = relationMap.get(userQuestion.getQuestionNoId());
  1134. // 每题用时
  1135. JSONObject one = new JSONObject();
  1136. one.put("time", userQuestion.getTime());
  1137. one.put("userTime", userQuestion.getUserTime());
  1138. one.put("no", userQuestion.getNo());
  1139. pace.add(one);
  1140. // 考点用时,以及正确度
  1141. String placeKey = relation.getQuestion().getPlace();
  1142. JSONObject place = placeMap.getJSONObject(placeKey);
  1143. if (place == null){
  1144. place = new JSONObject();
  1145. place.put("key", placeKey);
  1146. place.put("userNumber", 1);
  1147. place.put("userCorrect", userQuestion.getIsCorrect());
  1148. place.put("userTime", userQuestion.getUserTime());
  1149. placeMap.put(placeKey, place);
  1150. }else{
  1151. place.put("userNumber", place.getInteger("userNumber") + 1);
  1152. place.put("userCorrect", place.getInteger("userCorrect") + userQuestion.getIsCorrect());
  1153. place.put("userTime", place.getInteger("userTime") + userQuestion.getUserTime());
  1154. }
  1155. // 难度正确度
  1156. String difficultKey = relation.getQuestion().getDifficult();
  1157. JSONObject difficult = difficultMap.getJSONObject(difficultKey);
  1158. if (difficult == null){
  1159. difficult = new JSONObject();
  1160. difficult.put("key", difficultKey);
  1161. difficult.put("userNumber", 1);
  1162. difficult.put("userCorrect", userQuestion.getIsCorrect());
  1163. difficult.put("totalNumber", relation.getTotalNumber());
  1164. difficult.put("totalCorrect", relation.getTotalCorrect());
  1165. difficultMap.put(difficultKey, difficult);
  1166. }else{
  1167. difficult.put("userNumber", difficult.getInteger("userNumber") + 1);
  1168. difficult.put("userCorrect", difficult.getInteger("userCorrect") + userQuestion.getIsCorrect());
  1169. difficult.put("totalNumber", difficult.getInteger("totalNumber") + relation.getTotalNumber());
  1170. difficult.put("totalCorrect", difficult.getInteger("totalCorrect") + relation.getTotalCorrect());
  1171. }
  1172. }
  1173. detail.put("pace", pace);
  1174. JSONArray difficult = new JSONArray();
  1175. difficult.addAll(difficultMap.values());
  1176. detail.put("difficult", difficult);
  1177. JSONArray place = new JSONArray();
  1178. place.addAll(placeMap.values());
  1179. detail.put("place", place);
  1180. JSONObject limit = new JSONObject();
  1181. // 限时统计考试正确度
  1182. UserReportLimitRelation relation = userReportService.statLimit(report.getPaperOrigin(), report.getOriginId());
  1183. limit.put("userNumber", relation.getUserNumber());
  1184. limit.put("userCorrect", relation.getUserCorrect());
  1185. detail.put("limit", limit);
  1186. JSONObject info = new JSONObject();
  1187. // 基本信息
  1188. info.put("times", paper.getTimes() + 1); // paper还未计数
  1189. info.put("finishTime", report.getFinishTime());
  1190. info.put("userTime", report.getUserTime());
  1191. info.put("time", report.getTime());
  1192. info.put("questionNumber", report.getQuestionNumber());
  1193. info.put("userNumber", report.getUserNumber());
  1194. info.put("userCorrect", report.getUserCorrect());
  1195. Integer totalNumber = 0;
  1196. Integer totalCorrect = 0;
  1197. Integer totalTime = 0;
  1198. for (QuestionNoRelation questionNoRelation : relationMap.values()){
  1199. totalNumber += questionNoRelation.getTotalNumber();
  1200. totalCorrect += questionNoRelation.getTotalCorrect();
  1201. totalTime += questionNoRelation.getTotalTime();
  1202. }
  1203. Integer correctTime = 0;
  1204. Integer incorrectTime = 0;
  1205. for (UserQuestion userQuestion : questionList){
  1206. if (userQuestion.getIsCorrect() > 0){
  1207. correctTime += userQuestion.getUserTime();
  1208. }else{
  1209. incorrectTime += userQuestion.getUserTime();
  1210. }
  1211. }
  1212. info.put("totalNumber", totalNumber);
  1213. info.put("totalCorrect", totalCorrect);
  1214. info.put("totalTime", totalTime);
  1215. info.put("correctTime", correctTime);
  1216. info.put("incorrectTime", incorrectTime);
  1217. detail.put("info", info);
  1218. return detail;
  1219. }
  1220. /**
  1221. * 根据机经报告格式,统计信息:移除练习中的难度分析
  1222. * @param report
  1223. * @param questionList
  1224. * @return
  1225. */
  1226. private JSONObject statTextbookReport(UserReport report, List<UserQuestion> questionList){
  1227. UserPaper paper = userPaperService.get(report.getPaperId());
  1228. Collection questionNoIds = Transform.getIds(questionList, UserQuestion.class, "questionNoId");
  1229. Map<Number, TextbookQuestionRelation> relationMap = textbookQuestionService.mapWithRelationByIds((Integer[])questionNoIds.toArray());
  1230. // report
  1231. JSONObject detail = new JSONObject();
  1232. JSONArray pace = new JSONArray();
  1233. JSONObject placeMap = new JSONObject();
  1234. for (UserQuestion userQuestion:questionList){
  1235. TextbookQuestionRelation relation = relationMap.get(userQuestion.getQuestionNoId());
  1236. // 每题用时
  1237. JSONObject one = new JSONObject();
  1238. one.put("time", userQuestion.getTime());
  1239. one.put("userTime", userQuestion.getUserTime());
  1240. one.put("no", userQuestion.getNo());
  1241. pace.add(one);
  1242. // 考点用时,以及正确度
  1243. String placeKey = relation.getQuestion().getPlace();
  1244. JSONObject place = placeMap.getJSONObject(placeKey);
  1245. if (place == null){
  1246. place = new JSONObject();
  1247. place.put("key", placeKey);
  1248. place.put("userNumber", 1);
  1249. place.put("userCorrect", userQuestion.getIsCorrect());
  1250. place.put("userTime", userQuestion.getUserTime());
  1251. placeMap.put(placeKey, place);
  1252. }else{
  1253. place.put("userNumber", place.getInteger("userNumber") + 1);
  1254. place.put("userCorrect", place.getInteger("userCorrect") + userQuestion.getIsCorrect());
  1255. place.put("userTime", place.getInteger("userTime") + userQuestion.getUserTime());
  1256. }
  1257. }
  1258. detail.put("pace", pace);
  1259. JSONArray place = new JSONArray();
  1260. place.addAll(placeMap.values());
  1261. detail.put("place", place);
  1262. JSONObject limit = new JSONObject();
  1263. // 限时统计考试正确度
  1264. UserReportLimitRelation relation = userReportService.statLimit(report.getPaperOrigin(), report.getOriginId());
  1265. limit.put("userNumber", relation.getUserNumber());
  1266. limit.put("userCorrect", relation.getUserCorrect());
  1267. detail.put("limit", limit);
  1268. JSONObject info = new JSONObject();
  1269. // 基本信息
  1270. info.put("times", paper.getTimes() + 1); // paper还未计数
  1271. info.put("finishTime", report.getFinishTime());
  1272. info.put("userTime", report.getUserTime());
  1273. info.put("time", report.getTime());
  1274. info.put("questionNumber", report.getQuestionNumber());
  1275. info.put("userNumber", report.getUserNumber());
  1276. info.put("userCorrect", report.getUserCorrect());
  1277. Integer totalNumber = 0;
  1278. Integer totalCorrect = 0;
  1279. Integer totalTime = 0;
  1280. for (TextbookQuestionRelation questionNoRelation : relationMap.values()){
  1281. totalNumber += questionNoRelation.getTotalNumber();
  1282. totalCorrect += questionNoRelation.getTotalCorrect();
  1283. totalTime += questionNoRelation.getTotalTime();
  1284. }
  1285. Integer correctTime = 0;
  1286. Integer incorrectTime = 0;
  1287. for (UserQuestion userQuestion : questionList){
  1288. if (userQuestion.getIsCorrect() > 0){
  1289. correctTime += userQuestion.getUserTime();
  1290. }else{
  1291. incorrectTime += userQuestion.getUserTime();
  1292. }
  1293. }
  1294. info.put("totalNumber", totalNumber);
  1295. info.put("totalCorrect", totalCorrect);
  1296. info.put("totalTime", totalTime);
  1297. info.put("correctTime", correctTime);
  1298. info.put("incorrectTime", incorrectTime);
  1299. detail.put("info", info);
  1300. return detail;
  1301. }
  1302. /**
  1303. * 根据长难句报告格式,统计信息
  1304. * @param report
  1305. * @param questionList
  1306. * @return
  1307. */
  1308. private JSONObject statSentenceReport(UserReport report, List<UserQuestion> questionList){
  1309. UserPaper paper = userPaperService.get(report.getPaperId());
  1310. Collection questionNoIds = Transform.getIds(questionList, UserQuestion.class, "questionNoId");
  1311. Map<Number, SentenceQuestionRelation> relationMap = sentenceQuestionService.mapWithRelationByIds(questionNoIds.toArray());
  1312. // report
  1313. JSONObject detail = new JSONObject();
  1314. JSONObject ability = new JSONObject();
  1315. Integer struct = 0;
  1316. Integer logic = 0;
  1317. Integer speed = 0;
  1318. for (UserQuestion userQuestion:questionList){
  1319. if (userQuestion.getUserTime() < userQuestion.getTime()){
  1320. speed += 1;
  1321. }
  1322. JSONObject questionDetail = userQuestion.getDetail();
  1323. if (questionDetail.getBoolean("subject") && questionDetail.getBoolean("predicate") && questionDetail.getBoolean("object")){
  1324. struct += 1;
  1325. }
  1326. if (questionDetail.getBoolean("options")){
  1327. logic += 1;
  1328. }
  1329. }
  1330. ability.put("struct", struct * 100 / report.getQuestionNumber());
  1331. ability.put("logic", logic * 100 / report.getQuestionNumber());
  1332. ability.put("speed", speed * 100 / report.getQuestionNumber());
  1333. ability.put("score", (struct * 40 + logic * 30 + speed * 30) / report.getQuestionNumber());
  1334. detail.put("ability", ability);
  1335. JSONObject info = new JSONObject();
  1336. // 基本信息
  1337. info.put("times", paper.getTimes() + 1); // paper还未计数
  1338. info.put("finishTime", report.getFinishTime());
  1339. info.put("userTime", report.getUserTime());
  1340. info.put("time", report.getTime());
  1341. info.put("questionNumber", report.getQuestionNumber());
  1342. info.put("userNumber", report.getUserNumber());
  1343. info.put("userCorrect", report.getUserCorrect());
  1344. Integer totalNumber = 0;
  1345. Integer totalCorrect = 0;
  1346. Integer totalTime = 0;
  1347. for (SentenceQuestionRelation questionNoRelation : relationMap.values()){
  1348. totalNumber += questionNoRelation.getTotalNumber();
  1349. totalCorrect += questionNoRelation.getTotalCorrect();
  1350. totalTime += questionNoRelation.getTotalTime();
  1351. }
  1352. Integer correctTime = 0;
  1353. Integer incorrectTime = 0;
  1354. for (UserQuestion userQuestion : questionList){
  1355. if (userQuestion.getIsCorrect() > 0){
  1356. correctTime += userQuestion.getUserTime();
  1357. }else{
  1358. incorrectTime += userQuestion.getUserTime();
  1359. }
  1360. }
  1361. info.put("totalNumber", totalNumber);
  1362. info.put("totalCorrect", totalCorrect);
  1363. info.put("totalTime", totalTime);
  1364. info.put("correctTime", correctTime);
  1365. info.put("incorrectTime", incorrectTime);
  1366. detail.put("info", info);
  1367. return detail;
  1368. }
  1369. /**
  1370. * 根据模考报告格式,统计信息
  1371. * @param report
  1372. * @param questionList
  1373. * @return
  1374. */
  1375. private void statExaminationReport(UserReport report, List<UserQuestion> questionList){
  1376. UserPaper paper = userPaperService.get(report.getPaperId());
  1377. Collection questionNoIds = Transform.getIds(questionList, UserQuestion.class, "questionNoId");
  1378. Map<Number, QuestionNoRelation> relationMap = questionNoService.mapWithRelationByIds((Integer[])questionNoIds.toArray());
  1379. // report
  1380. JSONObject detail = new JSONObject();
  1381. JSONObject score = new JSONObject();
  1382. // 成绩单
  1383. JSONObject subjectMap = new JSONObject();
  1384. JSONObject typeMap = new JSONObject();
  1385. JSONObject tempMap = new JSONObject();
  1386. JSONObject difficult = null;
  1387. JSONObject place = null;
  1388. for (UserQuestion userQuestion : questionList){
  1389. QuestionNoRelation relation = relationMap.get(userQuestion.getQuestionNoId());
  1390. QuestionType questionType = QuestionType.ValueOf(relation.getQuestion().getQuestionType());
  1391. QuestionSubject questionSubject = QuestionSubject.FromType(questionType);
  1392. JSONObject type = typeMap.getJSONObject(questionType.key);
  1393. JSONObject tempType = tempMap.getJSONObject(questionType.key);
  1394. JSONObject subject = subjectMap.getJSONObject(questionSubject.key);
  1395. JSONObject tempSubject = tempMap.getJSONObject(questionSubject.key);
  1396. // 归类
  1397. if (type == null || type.isEmpty()){
  1398. type = new JSONObject();
  1399. type.put("key", questionType.key);
  1400. subject.put("pace", new JSONArray());
  1401. JSONObject initTypeInfo = new JSONObject();
  1402. // 初始化题型基础信息
  1403. initTypeInfo.put("userNumber", 0);
  1404. initTypeInfo.put("userTime", 0);
  1405. initTypeInfo.put("userCorrect", 0);
  1406. initTypeInfo.put("correctTime", 0);
  1407. initTypeInfo.put("incorrectTime", 0);
  1408. initTypeInfo.put("diffCorrect", 0f);
  1409. initTypeInfo.put("diffIncorrect", 0f);
  1410. type.put("info", initTypeInfo);
  1411. typeMap.put(questionType.key, type);
  1412. tempType = new JSONObject();
  1413. tempType.put("place", new JSONObject());
  1414. tempType.put("difficult", new JSONObject());
  1415. tempMap.put(questionType.key, tempType);
  1416. }
  1417. if (subject == null || subject.isEmpty()){
  1418. subject = new JSONObject();
  1419. subject.put("key", questionSubject.key);
  1420. subject.put("pace", new JSONArray());
  1421. JSONObject initSubjectInfo = new JSONObject();
  1422. JSONObject subjectBase = toolsService.examinationSubjectInit(questionSubject);
  1423. // 初始化学科基础信息
  1424. initSubjectInfo.put("questionNumber", subjectBase.getIntValue("number"));
  1425. initSubjectInfo.put("time", subjectBase.getIntValue("time"));
  1426. initSubjectInfo.put("userNumber", 0);
  1427. initSubjectInfo.put("userTime", 0);
  1428. initSubjectInfo.put("userCorrect", 0);
  1429. initSubjectInfo.put("correctTime", 0);
  1430. initSubjectInfo.put("incorrectTime", 0);
  1431. initSubjectInfo.put("diffCorrect", 0f);
  1432. initSubjectInfo.put("diffIncorrect", 0f);
  1433. initSubjectInfo.put("difficultScore", 0);
  1434. subject.put("info", initSubjectInfo);
  1435. subjectMap.put(questionSubject.key, subject);
  1436. tempSubject = new JSONObject();
  1437. tempSubject.put("place", new JSONObject());
  1438. tempSubject.put("difficult", new JSONObject());
  1439. tempMap.put(questionSubject.key, tempType);
  1440. }
  1441. JSONArray paceType = type.getJSONArray("pace");
  1442. JSONObject placeTypeMap = tempType.getJSONObject("place");
  1443. JSONObject difficultTypeMap = tempType.getJSONObject("difficult");
  1444. JSONObject typeInfo = type.getJSONObject("info");
  1445. JSONArray paceSubject = subject.getJSONArray("pace");
  1446. JSONObject placeSubjectMap = tempType.getJSONObject("place");
  1447. JSONObject difficultSubjectMap = tempType.getJSONObject("difficult");
  1448. JSONObject subjectInfo = subject.getJSONObject("info");
  1449. // 每题用时
  1450. JSONObject one = new JSONObject();
  1451. one.put("time", userQuestion.getTime());
  1452. one.put("userTime", userQuestion.getUserTime());
  1453. one.put("no", userQuestion.getNo());
  1454. paceSubject.add(one);
  1455. paceType.add(one);
  1456. // 考点用时,以及正确度
  1457. String placeKey = relation.getQuestion().getPlace();
  1458. place = placeTypeMap.getJSONObject(placeKey);
  1459. if (place == null){
  1460. place = new JSONObject();
  1461. place.put("key", placeKey);
  1462. place.put("userNumber", 1);
  1463. place.put("userCorrect", userQuestion.getIsCorrect());
  1464. place.put("userTime", userQuestion.getUserTime());
  1465. placeTypeMap.put(placeKey, place);
  1466. }else{
  1467. place.put("userNumber", place.getInteger("userNumber") + 1);
  1468. place.put("userCorrect", place.getInteger("userCorrect") + userQuestion.getIsCorrect());
  1469. place.put("userTime", place.getInteger("userTime") + userQuestion.getUserTime());
  1470. }
  1471. place = placeSubjectMap.getJSONObject(placeKey);
  1472. if (place == null){
  1473. place = new JSONObject();
  1474. place.put("key", placeKey);
  1475. place.put("userNumber", 1);
  1476. place.put("userCorrect", userQuestion.getIsCorrect());
  1477. place.put("userTime", userQuestion.getUserTime());
  1478. placeSubjectMap.put(placeKey, place);
  1479. }else{
  1480. place.put("userNumber", place.getInteger("userNumber") + 1);
  1481. place.put("userCorrect", place.getInteger("userCorrect") + userQuestion.getIsCorrect());
  1482. place.put("userTime", place.getInteger("userTime") + userQuestion.getUserTime());
  1483. }
  1484. // 难度正确度
  1485. String difficultKey = relation.getQuestion().getDifficult();
  1486. difficult = difficultTypeMap.getJSONObject(difficultKey);
  1487. if (difficult == null){
  1488. difficult = new JSONObject();
  1489. difficult.put("key", difficultKey);
  1490. difficult.put("userNumber", 1);
  1491. difficult.put("userCorrect", userQuestion.getIsCorrect());
  1492. difficult.put("totalNumber", relation.getTotalNumber());
  1493. difficult.put("totalCorrect", relation.getTotalCorrect());
  1494. difficultTypeMap.put(difficultKey, difficult);
  1495. }else{
  1496. difficult.put("userNumber", difficult.getInteger("userNumber") + 1);
  1497. difficult.put("userCorrect", difficult.getInteger("userCorrect") + userQuestion.getIsCorrect());
  1498. difficult.put("totalNumber", difficult.getInteger("totalNumber") + relation.getTotalNumber());
  1499. difficult.put("totalCorrect", difficult.getInteger("totalCorrect") + relation.getTotalCorrect());
  1500. }
  1501. difficult = difficultSubjectMap.getJSONObject(difficultKey);
  1502. if (difficult == null){
  1503. difficult = new JSONObject();
  1504. difficult.put("key", difficultKey);
  1505. difficult.put("userNumber", 1);
  1506. difficult.put("userCorrect", userQuestion.getIsCorrect());
  1507. difficult.put("totalNumber", relation.getTotalNumber());
  1508. difficult.put("totalCorrect", relation.getTotalCorrect());
  1509. difficultSubjectMap.put(difficultKey, difficult);
  1510. }else{
  1511. difficult.put("userNumber", difficult.getInteger("userNumber") + 1);
  1512. difficult.put("userCorrect", difficult.getInteger("userCorrect") + userQuestion.getIsCorrect());
  1513. difficult.put("totalNumber", difficult.getInteger("totalNumber") + relation.getTotalNumber());
  1514. difficult.put("totalCorrect", difficult.getInteger("totalCorrect") + relation.getTotalCorrect());
  1515. }
  1516. // 基础数据
  1517. typeInfo.put("userNumber", typeInfo.getIntValue("userNumber")+1);
  1518. typeInfo.put("userTime", typeInfo.getIntValue("userTime")+userQuestion.getUserTime());
  1519. typeInfo.put("userCorrect", typeInfo.getIntValue("userCorrect")+userQuestion.getIsCorrect());
  1520. if (userQuestion.getIsCorrect() > 0){
  1521. typeInfo.put("correctTime", typeInfo.getIntValue("correctTime")+userQuestion.getUserTime());
  1522. }else{
  1523. typeInfo.put("incorrectTime", typeInfo.getIntValue("incorrectTime")+userQuestion.getUserTime());
  1524. }
  1525. subjectInfo.put("userNumber", subjectInfo.getIntValue("userNumber")+1);
  1526. subjectInfo.put("userTime", subjectInfo.getIntValue("userTime")+userQuestion.getUserTime());
  1527. subjectInfo.put("userCorrect", subjectInfo.getIntValue("userCorrect")+userQuestion.getIsCorrect());
  1528. if (userQuestion.getIsCorrect() > 0){
  1529. subjectInfo.put("correctTime", subjectInfo.getIntValue("correctTime")+userQuestion.getUserTime());
  1530. }else{
  1531. subjectInfo.put("incorrectTime", subjectInfo.getIntValue("incorrectTime")+userQuestion.getUserTime());
  1532. }
  1533. // 题型难度分计算
  1534. QuestionDifficult questionDifficult = QuestionDifficult.ValueOf(difficultKey);
  1535. if (userQuestion.getIsCorrect() > 0){
  1536. typeInfo.put("diffCorrect", typeInfo.getFloatValue("diffCorrect") + toolsService.diffScore(relation.getTotalNumber(), relation.getTotalCorrect(), questionDifficult));
  1537. subjectInfo.put("diffCorrect", subjectInfo.getFloatValue("diffCorrect") + toolsService.diffScore(relation.getTotalNumber(), relation.getTotalCorrect(), questionDifficult));
  1538. }else{
  1539. typeInfo.put("diffIncorrect", typeInfo.getFloatValue("diffIncorrect") + toolsService.diffScore(relation.getTotalNumber(), relation.getTotalCorrect(), questionDifficult));
  1540. subjectInfo.put("diffIncorrect", subjectInfo.getFloatValue("diffIncorrect") + toolsService.diffScore(relation.getTotalNumber(), relation.getTotalCorrect(), questionDifficult));
  1541. }
  1542. // 获取2级难度得分
  1543. float difficultScore = relation.getQuestion().getDifficultScore();
  1544. subjectInfo.put("difficultScore", subjectInfo.getFloatValue("difficultScore")+difficultScore);
  1545. }
  1546. // 计算难度平均值
  1547. for (String key : typeMap.keySet()) {
  1548. JSONObject type = typeMap.getJSONObject(key);
  1549. JSONObject typeInfo = type.getJSONObject("info");
  1550. typeInfo.put("avgDiffCorrect", toolsService.avgDiffScore(typeInfo.getFloat("diffCorrect"), typeInfo.getIntValue("userCorrect")));
  1551. typeInfo.put("avgDiffIncorrect", toolsService.avgDiffScore(typeInfo.getFloat("diffIncorrect"), typeInfo.getIntValue("userNumber") - typeInfo.getIntValue("userCorrect")));
  1552. }
  1553. for (String key : subjectMap.keySet()) {
  1554. JSONObject subject = subjectMap.getJSONObject(key);
  1555. JSONObject subjectInfo = subject.getJSONObject("info");
  1556. subjectInfo.put("avgDiffCorrect", toolsService.avgDiffScore(subjectInfo.getFloat("diffCorrect"), subjectInfo.getIntValue("userCorrect")));
  1557. subjectInfo.put("avgDiffIncorrect", toolsService.avgDiffScore(subjectInfo.getFloat("diffIncorrect"), subjectInfo.getIntValue("userNumber") - subjectInfo.getIntValue("userCorrect")));
  1558. }
  1559. // 学科得分计算
  1560. JSONObject quantSubject = subjectMap.getJSONObject(QuestionSubject.QUANT.key);
  1561. JSONObject quantInfo = quantSubject.getJSONObject("info");
  1562. Integer quantScore = toolsService.quantScore(quantInfo.getIntValue("number"), quantInfo.getIntValue("userNumber"), quantInfo.getFloatValue("difficultScore"), quantInfo.getInteger("userCorrect"));
  1563. JSONObject verbalSubject = subjectMap.getJSONObject(QuestionSubject.VERBAL.key);
  1564. JSONObject verbalInfo = verbalSubject.getJSONObject("info");
  1565. Integer verbalScore = toolsService.verbalScore(verbalInfo.getIntValue("number"), verbalInfo.getIntValue("userNumber"), verbalInfo.getFloatValue("difficultScore"), verbalInfo.getInteger("userCorrect"));
  1566. JSONObject irSubject = subjectMap.getJSONObject(QuestionSubject.IR.key);
  1567. JSONObject irInfo = irSubject.getJSONObject("info");
  1568. Integer irScore = toolsService.irScore(irInfo.getIntValue("number"), irInfo.getIntValue("userNumber"), irInfo.getInteger("difficultScore"), irInfo.getInteger("userCorrect"));
  1569. Rank rank = toolsService.totalScore(quantScore, verbalScore);
  1570. score.put("totalScore", rank.getTotalScore());
  1571. score.put("totalRank", rank.getTotalRank());
  1572. score.put("quantScore", quantScore);
  1573. score.put("quantRank", rank.getQuantRank());
  1574. score.put("verbalScore", verbalScore);
  1575. score.put("irScore", irScore);
  1576. score.put("irRank", rank.getIrRank());
  1577. detail.put("subject", subjectMap);
  1578. detail.put("type", typeMap);
  1579. JSONObject info = new JSONObject();
  1580. // 基本信息
  1581. info.put("times", paper.getTimes() + 1); // paper还未计数
  1582. info.put("finishTime", report.getFinishTime());
  1583. info.put("userTime", report.getUserTime());
  1584. info.put("time", report.getTime());
  1585. info.put("questionNumber", report.getQuestionNumber());
  1586. info.put("userNumber", report.getUserNumber());
  1587. info.put("userCorrect", report.getUserCorrect());
  1588. detail.put("info", info);
  1589. report.setDetail(detail);
  1590. report.setScore(score);
  1591. // 统计
  1592. UserService userService = null;
  1593. // 判断是否是cat模考:记录到第二次
  1594. ExaminationPaper examinationPaper = examinationPaperService.get(report.getOriginId());
  1595. if(examinationService.isCat(examinationPaper)){
  1596. userService = userServiceService.getService(report.getUserId(), ServiceKey.QX_CAT);
  1597. }
  1598. examinationPaperService.accumulation(report, userService != null && userService.getIsReset() > 0);
  1599. }
  1600. }