QuestionNoService.java 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. package com.qxgmat.service.inline;
  2. import com.github.pagehelper.Page;
  3. import com.nuliji.tools.AbstractService;
  4. import com.nuliji.tools.PageResult;
  5. import com.nuliji.tools.Transform;
  6. import com.nuliji.tools.exception.ParameterException;
  7. import com.nuliji.tools.exception.SystemException;
  8. import com.nuliji.tools.mybatis.Example;
  9. import com.qxgmat.data.constants.enums.module.StructModule;
  10. import com.qxgmat.data.constants.enums.status.DirectionStatus;
  11. import com.qxgmat.data.dao.QuestionNoMapper;
  12. import com.qxgmat.data.dao.entity.Question;
  13. import com.qxgmat.data.dao.entity.QuestionNo;
  14. import com.qxgmat.data.dao.entity.UserCollectQuestion;
  15. import com.qxgmat.data.dao.entity.UserQuestion;
  16. import com.qxgmat.data.inline.PaperStat;
  17. import com.qxgmat.data.relation.QuestionNoRelationMapper;
  18. import com.qxgmat.data.relation.entity.QuestionDifficultRelation;
  19. import com.qxgmat.data.relation.entity.QuestionNoRelation;
  20. import org.slf4j.Logger;
  21. import org.slf4j.LoggerFactory;
  22. import org.springframework.stereotype.Service;
  23. import org.springframework.transaction.annotation.Transactional;
  24. import javax.annotation.Resource;
  25. import java.util.*;
  26. import java.util.stream.Collectors;
  27. @Service
  28. public class QuestionNoService extends AbstractService {
  29. private static final Logger logger = LoggerFactory.getLogger(QuestionNoService.class);
  30. protected boolean SOFT_FLAG = true;
  31. @Resource
  32. private QuestionNoMapper questionNoMapper;
  33. @Resource
  34. private QuestionNoRelationMapper questionNoRelationMapper;
  35. @Resource
  36. private QuestionService questionService;
  37. /**
  38. * 根据题干搜索相似题目: 相似度80%
  39. * @param page
  40. * @param size
  41. * @param stem
  42. * @return
  43. */
  44. public PageResult<QuestionNoRelation> searchStem(int page, int size, String stem){
  45. // String[] stems = stem.replaceAll("\\.?,?!?:?;?\\??", "").split(" ");
  46. Page<QuestionNo> p = page(()->{
  47. questionNoRelationMapper.searchStem(stem);
  48. }, page, size);
  49. Collection ids = Transform.getIds(p, QuestionNo.class, "id");
  50. // 获取详细数据
  51. List<QuestionNo> list = select(ids);
  52. return new PageResult<>(relation(list), p.getTotal());
  53. }
  54. /**
  55. * 根据题目编号搜索相似题目
  56. * @param page
  57. * @param size
  58. * @param keyword
  59. * @param module
  60. * @return
  61. */
  62. public PageResult<QuestionNoRelation> searchNo(int page, int size, String keyword, String module){
  63. logger.info("SearchNo: {}, {}", page, size);
  64. Example example = new Example(QuestionNo.class);
  65. if(keyword != null)
  66. example.and(
  67. example.createCriteria()
  68. .andLike("title", "%"+keyword+"%")
  69. );
  70. if (module != null)
  71. example.and(
  72. example.createCriteria()
  73. .andEqualTo("module", module)
  74. );
  75. example.orderBy("id").asc();
  76. Page<QuestionNo> p = page(()->select(questionNoMapper, example), page, size);
  77. logger.info("SearchNo result: {}", p.toString());
  78. return new PageResult<>(relation(p), p.getTotal());
  79. }
  80. /**
  81. * 根据题目编号搜索相似题目
  82. * @param page
  83. * @param size
  84. * @param keyword
  85. * @return
  86. */
  87. public Page<QuestionNoRelation> searchStemFulltext(int page, int size, String keyword, String[] questionTypes, String module, Integer[] structIds, String place, String difficult, Integer qxCatId, String order, DirectionStatus direction){
  88. if (direction == null){
  89. direction = DirectionStatus.DESC;
  90. }
  91. String finalOrder = order;
  92. DirectionStatus finalDirection = direction;
  93. Page<QuestionNoRelation> p = page(()->{
  94. questionNoRelationMapper.searchStemFulltext(keyword, questionTypes, module, structIds, place, difficult, qxCatId, finalOrder, finalDirection.key);
  95. }, page, size);
  96. Collection ids = Transform.getIds(p, QuestionNo.class, "id");
  97. // 获取详细数据
  98. List<QuestionNo> list = select(ids);
  99. List<QuestionNoRelation> relationList = relation(list);
  100. Transform.replace(p, relationList, QuestionNoRelation.class, "id");
  101. return p;
  102. }
  103. /**
  104. * 根据题目编号搜索相似题目
  105. * @param page
  106. * @param size
  107. * @param keyword
  108. * @return
  109. */
  110. public Page<QuestionNo> searchNoFulltext(int page, int size, String keyword, Integer qxCatId){
  111. Page<QuestionNo> p = page(()->{
  112. questionNoRelationMapper.searchNoFulltext(keyword, qxCatId);
  113. }, page, size);
  114. Collection ids = Transform.getIds(p, QuestionNo.class, "id");
  115. // 获取详细数据
  116. List<QuestionNo> list = select(ids);
  117. Transform.replace(p, list, QuestionNo.class, "id");
  118. return p;
  119. }
  120. /**
  121. * 获取结构模块下的题目列表: 按序号排列
  122. * @param module
  123. * @param structId
  124. * @return
  125. */
  126. public List<QuestionNo> listByStruct(StructModule module, Integer structId){
  127. Example example = new Example(QuestionNo.class);
  128. example.and(
  129. example.createCriteria()
  130. .andEqualTo("module", module.key)
  131. .andCondition(String.format(formatSet, structId, "module_struct"))
  132. );
  133. example.orderBy("no").asc();
  134. return select(questionNoMapper, example);
  135. }
  136. /**
  137. * 获取结构模块下的题目列表: 按序号排列
  138. * @param module
  139. * @param structIds
  140. * @return
  141. */
  142. public List<QuestionNo> listByStruct(StructModule module, Integer[] structIds){
  143. Example example = new Example(QuestionNo.class);
  144. example.and(
  145. example.createCriteria()
  146. .andEqualTo("module", module.key)
  147. );
  148. Example.Criteria criteria = example.createCriteria();
  149. for(Integer structId : structIds){
  150. criteria.orCondition(String.format(formatSet, structId, "module_struct"));
  151. }
  152. example.and(criteria);
  153. example.orderBy("no").asc();
  154. return select(questionNoMapper, example);
  155. }
  156. /**
  157. * 获取结构模块下的题目列表: 按序号排列
  158. * @param module
  159. * @param structId
  160. * @return
  161. */
  162. public List<QuestionNoRelation> listWithRelationByStruct(StructModule module, Integer structId){
  163. return relation(listByStruct(module, structId));
  164. }
  165. /**
  166. * 根据题目标号列表获取题目
  167. * @param nos
  168. * @param module
  169. * @return
  170. */
  171. public List<QuestionNoRelation> listWithRelationByNos(String[] nos, String module){
  172. if (nos.length == 0) return new ArrayList<>();
  173. Example example = new Example(QuestionNo.class);
  174. example.and(
  175. example.createCriteria()
  176. .andIn("no", Arrays.stream(nos).collect(Collectors.toList()))
  177. );
  178. if (module != null)
  179. example.and(
  180. example.createCriteria()
  181. .andEqualTo("module", module)
  182. );
  183. List<QuestionNo> p = select(questionNoMapper, example);
  184. return relation(p);
  185. }
  186. /**
  187. * 根据题目获取关联的题目编号
  188. * @param questionId
  189. * @return
  190. */
  191. public List<QuestionNo> listByQuestion(Number questionId){
  192. Example example = new Example(QuestionNo.class);
  193. example.and(
  194. example.createCriteria()
  195. .andEqualTo("questionId", questionId)
  196. );
  197. return select(questionNoMapper, example);
  198. }
  199. /**
  200. * 根据题目编号id列表获取关联题目
  201. * @param ids
  202. * @return
  203. */
  204. public List<QuestionNoRelation> listWithRelationByIds(Number[] ids){
  205. List<QuestionNo> p = select(questionNoMapper, ids);
  206. return relation(p);
  207. }
  208. /**
  209. * 根据题目编号id列表获取关联题目
  210. * @param ids
  211. * @return
  212. */
  213. public Map<Number, QuestionNoRelation> mapWithRelationByIds(Number[] ids){
  214. List<QuestionNo> p = select(questionNoMapper, ids);
  215. List<QuestionNoRelation> list = relation(p);
  216. Map<Number, QuestionNoRelation> map = new HashMap<>();
  217. for(QuestionNoRelation relation : list){
  218. map.put(relation.getId(), relation);
  219. }
  220. return map;
  221. }
  222. /**
  223. * 根据题目编号id获取关联题目
  224. * @param id
  225. * @return
  226. */
  227. public QuestionNoRelation getWithRelation(Number id){
  228. QuestionNo questionNo = get(id);
  229. return relation(questionNo);
  230. }
  231. /**
  232. * 随机获取对应模块下的试题:排除已做试题
  233. * @param structId
  234. * @param filterIds
  235. * @return
  236. */
  237. public Integer randomExamination(Integer structId, Collection targetTypes, Collection filterIds){
  238. List<QuestionNo> questionNoList = questionNoRelationMapper.randomExamination(structId, targetTypes, filterIds, 1);
  239. if (questionNoList.size() > 0){
  240. return questionNoList.get(0).getId();
  241. }else{
  242. return null;
  243. }
  244. }
  245. /**
  246. * 随机批量获取对应模块下的试题:排除已做试题
  247. * @param structId
  248. * @param targetTypes
  249. * @param filterIds
  250. * @param size
  251. * @return
  252. */
  253. public Integer[] randomExaminationList(Integer structId, Collection targetTypes, Collection filterIds, Integer size){
  254. List<QuestionNo> questionNoList = questionNoRelationMapper.randomExamination(structId, targetTypes, filterIds, size);
  255. if (questionNoList.size() > 0){
  256. Integer[] ids = new Integer[questionNoList.size()];
  257. for(int i = 0; i< questionNoList.size(); i++){
  258. ids[i] = questionNoList.get(i).getId();
  259. }
  260. return ids;
  261. }else{
  262. return new Integer[0];
  263. }
  264. }
  265. /**
  266. * 获取该struct下指定类型的所有题目信息
  267. * @param structId
  268. * @param targetTypes
  269. * @return
  270. */
  271. public List<QuestionDifficultRelation> allExaminationByType(Integer structId, Collection targetTypes){
  272. return questionNoRelationMapper.allExaminationByType(structId, targetTypes);
  273. }
  274. /**
  275. * 随机查找模考阅读题
  276. * @param structId
  277. * @param number
  278. * @param filterIds
  279. * @return
  280. */
  281. public Integer[] randomExaminationRc(Integer structId, Integer number, Collection filterIds){
  282. Example example = new Example(QuestionNo.class);
  283. example.and(
  284. example.createCriteria()
  285. .andCondition(String.format(formatSet, structId, "module_struct"))
  286. .andEqualTo("relationNumber", number)
  287. .andNotIn("id", filterIds)
  288. );
  289. example.setOrderByClause("RAND()");
  290. QuestionNo questionNo = one(questionNoMapper, example);
  291. if (questionNo == null){
  292. throw new ParameterException("阅读题查找失败");
  293. }
  294. return Arrays.stream(questionNo.getRelationQuestion()).boxed().toArray(Integer[]::new);
  295. }
  296. /**
  297. * 绑定no和question
  298. * @param ids
  299. * @param questionId
  300. * @return
  301. */
  302. public Boolean bindQuestion(Integer[] ids, Integer questionId){
  303. if (ids.length == 0) return false;
  304. Example example = new Example(QuestionNo.class);
  305. example.and(
  306. example.createCriteria()
  307. .andIn("id", Arrays.stream(ids).collect(Collectors.toList()))
  308. );
  309. int result = update(questionNoMapper, example, QuestionNo.builder()
  310. .questionId(questionId)
  311. .deleteTime(null)
  312. .build());
  313. return result > 0;
  314. }
  315. /**
  316. * 设定编号关联关系, 并设定题目数量
  317. * @param ids
  318. * @return
  319. */
  320. public Boolean relationQuestion(int[] ids){
  321. if (ids.length == 0) return false;
  322. Example example = new Example(QuestionNo.class);
  323. example.and(
  324. example.createCriteria()
  325. .andIn("id", Arrays.stream(ids).boxed().collect(Collectors.toList()))
  326. );
  327. int result = update(questionNoMapper, example, QuestionNo.builder()
  328. .relationQuestion(ids)
  329. .relationNumber(ids.length)
  330. .deleteTime(null)
  331. .build());
  332. return result > 0;
  333. }
  334. /**
  335. * 根据题目获取总试卷统计信息
  336. * @param questionNoList
  337. * @return
  338. */
  339. public PaperStat statPaper(List<QuestionNo> questionNoList){
  340. PaperStat stat = new PaperStat();
  341. Integer totalTime = 0;
  342. Integer totalNumber = 0;
  343. Integer totalCorrect = 0;
  344. for(QuestionNo questionNo : questionNoList){
  345. totalTime += questionNo.getTotalTime();
  346. totalNumber += questionNo.getTotalNumber();
  347. totalCorrect += questionNo.getTotalCorrect();
  348. }
  349. stat.setTotalCorrect(totalCorrect);
  350. stat.setTotalNumber(totalNumber);
  351. stat.setTotalTime(totalTime);
  352. return stat;
  353. }
  354. /**
  355. * 累加做题记录到questionNo
  356. * @param question
  357. */
  358. public void accumulation(UserQuestion question){
  359. questionNoRelationMapper.accumulation(question.getQuestionNoId(), 1, question.getUserTime(), question.getIsCorrect());
  360. }
  361. /**
  362. * 累加收藏记录到questionNo
  363. * @param question
  364. */
  365. public void accumulationCollect(UserCollectQuestion question, int collect){
  366. questionNoRelationMapper.accumulationCollect(question.getQuestionNoId(), collect);
  367. }
  368. /**
  369. * 根据试卷分组获取统计信息
  370. * @param questionNoIdsMap
  371. * @return
  372. */
  373. public Map<Integer, PaperStat> statPaperMap(Map<Integer, Integer[]> questionNoIdsMap){
  374. Map<Integer, PaperStat> relationMap = new HashMap<>();
  375. List<Integer> ids = new ArrayList<>();
  376. for(Integer[] questionNoIds : questionNoIdsMap.values()){
  377. ids.addAll(Arrays.stream(questionNoIds).collect(Collectors.toList()));
  378. }
  379. List<QuestionNo> questionNoList = select(ids);
  380. Map questionNoMap = Transform.getMap(questionNoList, QuestionNo.class, "id");
  381. List<QuestionNo> l = new ArrayList<>();
  382. for(Integer k: questionNoIdsMap.keySet()){
  383. l.clear();
  384. for (Integer questionNoId : questionNoIdsMap.get(k)){
  385. l.add((QuestionNo)questionNoMap.get(questionNoId));
  386. }
  387. relationMap.put(k, statPaper(l));
  388. }
  389. return relationMap;
  390. }
  391. public List<QuestionNoRelation> relation(List<QuestionNo> p){
  392. List<QuestionNoRelation> relationList = Transform.convert(p, QuestionNoRelation.class);
  393. Collection questionIds = Transform.getIds(p, QuestionNo.class, "questionId");
  394. List<Question> questions = questionService.select(questionIds);
  395. Transform.combine(relationList, questions, QuestionNoRelation.class, "questionId", "question", Question.class, "id");
  396. return relationList;
  397. }
  398. public QuestionNoRelation relation(QuestionNo p){
  399. QuestionNoRelation relation = Transform.convert(p, QuestionNoRelation.class);
  400. Question question = questionService.get(p.getQuestionId());
  401. relation.setQuestion(question);
  402. return relation;
  403. }
  404. /**
  405. * 通过题目编号获取
  406. * @param title
  407. * @return
  408. */
  409. public QuestionNo getByNo(String title, String module){
  410. return one(questionNoMapper, QuestionNo.builder().title(title).module(module).build());
  411. }
  412. @Transactional
  413. public QuestionNo add(QuestionNo question){
  414. QuestionNo in = getByNo(question.getTitle(), question.getModule());
  415. if (in != null){
  416. return in;
  417. }
  418. int result = insert(questionNoMapper, question);
  419. question = one(questionNoMapper, question.getId());
  420. if(question == null){
  421. throw new SystemException("题目添加失败");
  422. }
  423. return question;
  424. }
  425. @Deprecated
  426. public QuestionNo edit(QuestionNo question){
  427. QuestionNo in = one(questionNoMapper, question.getId());
  428. if(in == null){
  429. throw new ParameterException("题目不存在");
  430. }
  431. int result = update(questionNoMapper, question);
  432. return question;
  433. }
  434. public boolean delete(Number id){
  435. QuestionNo in = one(questionNoMapper, id);
  436. if(in == null){
  437. throw new ParameterException("题目不存在");
  438. }
  439. int result = delete(questionNoMapper, id, SOFT_FLAG);
  440. return result > 0;
  441. }
  442. public QuestionNo get(Number id){
  443. QuestionNo in = one(questionNoMapper, id);
  444. if(in == null){
  445. throw new ParameterException("题目不存在");
  446. }
  447. return in;
  448. }
  449. public Page<QuestionNo> select(int page, int pageSize){
  450. return select(questionNoMapper, page, pageSize);
  451. }
  452. public Page<QuestionNo> select(Integer[] ids){
  453. return page(()->select(questionNoMapper, ids), 1, ids.length);
  454. }
  455. public List<QuestionNo> select(Collection ids){
  456. return select(questionNoMapper, ids);
  457. }
  458. }