QuestionFlowService.java 83 KB

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