TCPaperStructController.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. package com.qmth.distributed.print.api;
  2. import com.google.gson.reflect.TypeToken;
  3. import com.qmth.boot.api.annotation.Aac;
  4. import com.qmth.boot.api.constant.ApiConstant;
  5. import com.qmth.boot.api.exception.ApiException;
  6. import com.qmth.boot.core.rateLimit.annotation.RateLimit;
  7. import com.qmth.distributed.print.business.bean.dto.CourseWeightDto;
  8. import com.qmth.distributed.print.business.bean.excel.PaperStructDto;
  9. import com.qmth.distributed.print.business.bean.params.report.PaperStructParams;
  10. import com.qmth.distributed.print.business.bean.result.EditResult;
  11. import com.qmth.distributed.print.business.bean.result.ObeCourseWeightResult;
  12. import com.qmth.distributed.print.business.bean.result.report.PaperStructDimensionResult;
  13. import com.qmth.distributed.print.business.entity.ObeCourseOutline;
  14. import com.qmth.distributed.print.business.entity.TCPaperStruct;
  15. import com.qmth.distributed.print.business.service.ObeCourseOutlineService;
  16. import com.qmth.distributed.print.business.service.PrintCommonService;
  17. import com.qmth.distributed.print.business.service.TCPaperStructService;
  18. import com.qmth.distributed.print.business.service.TRBasicInfoService;
  19. import com.qmth.teachcloud.common.annotation.OperationLogDetail;
  20. import com.qmth.teachcloud.common.contant.SystemConstant;
  21. import com.qmth.teachcloud.common.entity.MarkQuestion;
  22. import com.qmth.teachcloud.common.entity.SysUser;
  23. import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
  24. import com.qmth.teachcloud.common.enums.log.OperationTypeEnum;
  25. import com.qmth.teachcloud.common.util.*;
  26. import com.qmth.teachcloud.mark.entity.MarkPaper;
  27. import com.qmth.teachcloud.mark.service.MarkQuestionService;
  28. import io.swagger.annotations.*;
  29. import org.apache.commons.collections4.CollectionUtils;
  30. import org.slf4j.Logger;
  31. import org.slf4j.LoggerFactory;
  32. import org.springframework.beans.BeanUtils;
  33. import org.springframework.transaction.annotation.Transactional;
  34. import org.springframework.validation.BindingResult;
  35. import org.springframework.web.bind.annotation.*;
  36. import org.springframework.web.multipart.MultipartFile;
  37. import javax.annotation.Resource;
  38. import javax.validation.Valid;
  39. import java.io.IOException;
  40. import java.util.ArrayList;
  41. import java.util.List;
  42. import java.util.Map;
  43. import java.util.Objects;
  44. import java.util.stream.Collectors;
  45. /**
  46. * <p>
  47. * 试卷结构 前端控制器
  48. * </p>
  49. *
  50. * @author wangliang
  51. * @since 2024-02-18
  52. */
  53. @Api(tags = "课程目标达成度-成绩管理-试卷结构Controller")
  54. @RestController
  55. @RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + SystemConstant.PREFIX_URL_COURSE_DEGREE)
  56. public class TCPaperStructController {
  57. private final static Logger log = LoggerFactory.getLogger(TCPaperStructController.class);
  58. @Resource
  59. MarkQuestionService markQuestionService;
  60. @Resource
  61. TCPaperStructService tcPaperStructService;
  62. @Resource
  63. TRBasicInfoService trBasicInfoService;
  64. @Resource
  65. PrintCommonService printCommonService;
  66. @Resource
  67. RedisUtil redisUtil;
  68. @Resource
  69. ObeCourseOutlineService obeCourseOutlineService;
  70. @ApiOperation(value = "导入试卷结构")
  71. @RequestMapping(value = "/final_score/paper_struct/import", method = RequestMethod.POST)
  72. @OperationLogDetail(operationType = OperationTypeEnum.IMPORT)
  73. @ApiResponses({@ApiResponse(code = 200, message = "导入成功", response = EditResult.class)})
  74. public Result finalScorePaperStructImport(@ApiParam(value = "上传文件", required = true) @RequestParam MultipartFile file,
  75. @ApiParam(value = "培养方案id", required = true) @RequestParam Long cultureProgramId,
  76. @ApiParam(value = "科目编码", required = true) @RequestParam Long courseId,
  77. @ApiParam(value = "试卷编号") @RequestParam(required = false) String paperNumber) {
  78. printCommonService.getLock(cultureProgramId, courseId, paperNumber);
  79. String lockKey = SystemConstant.REDIS_PAPER_STRUCT_FLOW_PREFIX + SystemConstant.IMPORT + cultureProgramId + "_" + courseId + "_" + paperNumber;
  80. boolean lock = redisUtil.lock(lockKey, SystemConstant.REDIS_PAPER_STRUCT_TIME_OUT);
  81. if (!lock) {
  82. throw ExceptionResultEnum.ERROR.exception("正在导入数据,请稍候再试!");
  83. }
  84. Map<String, String> map = null;
  85. try {
  86. map = tcPaperStructService.paperStructExcelImport(file, cultureProgramId, courseId, paperNumber);
  87. } catch (Exception e) {
  88. log.error(SystemConstant.LOG_ERROR, e);
  89. if (e instanceof ApiException) {
  90. ResultUtil.error((ApiException) e, ((ApiException) e).getCode(), e.getMessage());
  91. } else {
  92. ResultUtil.error(e.getMessage());
  93. }
  94. } finally {
  95. redisUtil.releaseLock(lockKey);
  96. }
  97. return ResultUtil.ok(map);
  98. }
  99. @ApiOperation(value = "同步试卷蓝图结构")
  100. @RequestMapping(value = "/final_score/paper_struct_dimension/sync", method = RequestMethod.POST)
  101. @OperationLogDetail(operationType = OperationTypeEnum.SYNC)
  102. @ApiResponses({@ApiResponse(code = 200, message = "同步成功", response = EditResult.class)})
  103. @Aac(rateLimit = @RateLimit(count = 1, period = 1000L))
  104. public Result finalScorePaperStructDimensionSync(@ApiParam(value = "考试id") @RequestParam(required = false) Long examId,
  105. @ApiParam(value = "课程id", required = true) @RequestParam Long courseId,
  106. @ApiParam(value = "科目编码") @RequestParam(required = false) String courseCode,
  107. @ApiParam(value = "试卷编号") @RequestParam(required = false) String paperNumber,
  108. @ApiParam(value = "培养方案id", required = true) @RequestParam Long cultureProgramId) {
  109. Objects.requireNonNull(paperNumber, "未查询到题和知识点对应关系请手动关联");
  110. printCommonService.getLock(cultureProgramId, courseId, paperNumber);
  111. String lockKey = SystemConstant.REDIS_PAPER_STRUCT_FLOW_PREFIX + SystemConstant.SYNC + cultureProgramId + "_" + courseId + "_" + paperNumber;
  112. boolean lock = redisUtil.lock(lockKey, SystemConstant.REDIS_PAPER_STRUCT_TIME_OUT);
  113. if (!lock) {
  114. throw ExceptionResultEnum.ERROR.exception("正在同步数据,请稍候再试!");
  115. }
  116. Map<String, String> map = null;
  117. try {
  118. map = tcPaperStructService.paperStructSync(examId, courseId, paperNumber, cultureProgramId);
  119. } catch (Exception e) {
  120. log.error(SystemConstant.LOG_ERROR, e);
  121. if (e instanceof ApiException) {
  122. ResultUtil.error((ApiException) e, ((ApiException) e).getCode(), e.getMessage());
  123. } else {
  124. ResultUtil.error(e.getMessage());
  125. }
  126. } finally {
  127. redisUtil.releaseLock(lockKey);
  128. }
  129. return ResultUtil.ok(map);
  130. }
  131. @ApiOperation(value = "期末成绩试卷蓝图保存")
  132. @RequestMapping(value = "/final_score/paper_struct/save", method = RequestMethod.POST)
  133. @OperationLogDetail(operationType = OperationTypeEnum.UPDATE)
  134. @ApiResponses({@ApiResponse(code = 200, message = "试卷蓝图保存", response = Object.class)})
  135. @Transactional
  136. public Result finalScorePaperStructSave(@ApiParam(value = "试卷蓝图结构", required = true) @Valid @RequestBody PaperStructParams paperStructParams, BindingResult bindingResult) throws IOException {
  137. if (bindingResult.hasErrors()) {
  138. return ResultUtil.error(bindingResult.getAllErrors().get(0).getDefaultMessage());
  139. }
  140. printCommonService.getLock(paperStructParams.getCultureProgramId(), paperStructParams.getCourseId(), paperStructParams.getPaperNumber());
  141. ObeCourseOutline obeCourseOutline = obeCourseOutlineService.findByCultureProgramIdAndCourseId(paperStructParams.getCultureProgramId(), paperStructParams.getCourseId());
  142. ObeCourseWeightResult obeCourseWeightResult = trBasicInfoService.findCourseWeightResultRmi(obeCourseOutline.getId());
  143. for (CourseWeightDto c : obeCourseWeightResult.getSubmitForm()) {
  144. for (PaperStructDimensionResult paperStructDimensionResult : paperStructParams.getPaperStruct()) {
  145. Objects.requireNonNull(paperStructDimensionResult.getMainNumber(), "大题号为空");
  146. Objects.requireNonNull(paperStructDimensionResult.getSubNumber(), "小题号为空");
  147. if (!CollectionUtils.isEmpty(paperStructDimensionResult.getTargetList()) && paperStructDimensionResult.getTargetList().size() > 1) {
  148. throw ExceptionResultEnum.ERROR.exception("一个题只能属于一个目标");
  149. }
  150. }
  151. List<PaperStructDimensionResult> paperStructDimensionResultList = paperStructParams.getPaperStruct();
  152. Double score = paperStructDimensionResultList.stream().filter(s -> Objects.equals(s.getCourseTargetName(), c.getCourseTargetName())).mapToDouble(PaperStructDimensionResult::getScore).sum();
  153. Objects.requireNonNull(c.getTotalWeight(), "[" + c.getCourseTargetName() + "]未设置权重");
  154. // Objects.requireNonNull(c.getTotalScore(), "[" + c.getCourseTargetName() + "]未设置目标分值");
  155. // if (new BigDecimal(score).compareTo(c.getTotalWeight()) == 1) {
  156. // throw ExceptionResultEnum.ERROR.exception("[" + c.getCourseTargetName() + "]包含的小题总分与权重设置不一致,请到期末成绩--试卷蓝图设置里调整");
  157. // }
  158. paperStructDimensionResultList.stream().filter(s -> {
  159. if (Objects.equals(s.getCourseTargetName(), c.getCourseTargetName())) {
  160. s.getTargetList().stream().peek(e -> e.setFinalScoreQuestionScoreSum(score)).collect(Collectors.toList());
  161. return true;
  162. }
  163. return false;
  164. }).collect(Collectors.toList());
  165. }
  166. SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
  167. TCPaperStruct tcPaperStructDb = tcPaperStructService.queryPaperStruct(paperStructParams.getCultureProgramId(), paperStructParams.getCourseId(), paperStructParams.getPaperNumber());
  168. if (Objects.isNull(tcPaperStructDb)) {
  169. MarkPaper markPaper = printCommonService.getMarkPaper(paperStructParams.getExamId(), paperStructParams.getCourseCode(), paperStructParams.getPaperNumber(), paperStructParams.getCourseId());
  170. tcPaperStructDb = new TCPaperStruct(paperStructParams.getCultureProgramId(), paperStructParams.getCourseId(), paperStructParams.getCourseCode(), markPaper.getCourseName(), paperStructParams.getPaperNumber(), JacksonUtil.parseJson(paperStructParams.getPaperStruct()), sysUser.getId(), obeCourseWeightResult.getDimensionSign());
  171. tcPaperStructService.save(tcPaperStructDb);
  172. } else {
  173. TCPaperStruct tcPaperStructSource = new TCPaperStruct();
  174. BeanUtils.copyProperties(tcPaperStructDb, tcPaperStructSource);
  175. tcPaperStructDb.updateInfo(JacksonUtil.parseJson(paperStructParams.getPaperStruct()), sysUser.getId());
  176. if (!tcPaperStructDb.equals(tcPaperStructSource)) {
  177. trBasicInfoService.clearReportData(tcPaperStructDb.getCultureProgramId(), tcPaperStructDb.getCourseId(), tcPaperStructDb.getPaperNumber(), false);
  178. tcPaperStructDb.setDimensionSign(obeCourseWeightResult.getDimensionSign());
  179. tcPaperStructService.updateById(tcPaperStructDb);
  180. }
  181. }
  182. return ResultUtil.ok(true);
  183. }
  184. @ApiOperation(value = "期末成绩试卷蓝图查询")
  185. @RequestMapping(value = "/final_score/paper_struct/query", method = RequestMethod.POST)
  186. @ApiResponses({@ApiResponse(code = 200, message = "试卷蓝图查询", response = PaperStructDimensionResult.class)})
  187. public Result finalScorePaperStructQuery(@ApiParam(value = "考试id") @RequestParam(required = false) Long examId,
  188. @ApiParam(value = "科目id", required = true) @RequestParam Long courseId,
  189. @ApiParam(value = "科目编码") @RequestParam(required = false) String courseCode,
  190. @ApiParam(value = "试卷编号") @RequestParam(required = false) String paperNumber,
  191. @ApiParam(value = "培养方案id", required = true) @RequestParam Long cultureProgramId) {
  192. ObeCourseOutline obeCourseOutline = obeCourseOutlineService.findByCultureProgramIdAndCourseId(cultureProgramId, courseId);
  193. List<PaperStructDimensionResult> paperStructDimensionResultList = null;
  194. TCPaperStruct tcPaperStruct = tcPaperStructService.queryPaperStruct(cultureProgramId, courseId, paperNumber);
  195. if (Objects.isNull(tcPaperStruct) || (Objects.isNull(tcPaperStruct.getPaperStruct()) && Objects.isNull(tcPaperStruct.getPaperStructDimension()))) {
  196. List<MarkQuestion> markQuestionList = markQuestionService.listQuestionByExamIdAndPaperNumberAndPaperType(examId, paperNumber, null);
  197. if (CollectionUtils.isEmpty(markQuestionList)) {
  198. throw ExceptionResultEnum.ERROR.exception("未找到试卷结构");
  199. }
  200. paperStructDimensionResultList = new ArrayList<>(markQuestionList.size());
  201. for (MarkQuestion markQuestion : markQuestionList) {
  202. paperStructDimensionResultList.add(new PaperStructDimensionResult(markQuestion.getMainNumber(), markQuestion.getSubNumber(), markQuestion.getPaperNumber(), markQuestion.getTotalScore()));
  203. }
  204. } else {
  205. ObeCourseWeightResult obeCourseWeightResult = trBasicInfoService.findCourseWeightResultRmi(obeCourseOutline.getId());
  206. if (Objects.nonNull(tcPaperStruct.getDimensionSign()) && tcPaperStruct.getDimensionSign().longValue() != obeCourseWeightResult.getDimensionSign().longValue()) {
  207. trBasicInfoService.clearReportData(cultureProgramId, courseId, paperNumber, false);
  208. paperStructDimensionResultList = this.getPaperStructDimensionResult(tcPaperStruct, paperStructDimensionResultList);
  209. } else {
  210. paperStructDimensionResultList = this.getPaperStructDimensionResult(tcPaperStruct, paperStructDimensionResultList);
  211. }
  212. paperStructDimensionResultList.stream().peek(s -> s.setPaperNumber(tcPaperStruct.getPaperNumber())).collect(Collectors.toList());
  213. }
  214. return ResultUtil.ok(paperStructDimensionResultList);
  215. }
  216. /**
  217. * 获取试卷结构蓝图数据
  218. *
  219. * @param tcPaperStruct
  220. * @param paperStructDimensionResultList
  221. * @return
  222. */
  223. protected List<PaperStructDimensionResult> getPaperStructDimensionResult(TCPaperStruct tcPaperStruct,
  224. List<PaperStructDimensionResult> paperStructDimensionResultList) {
  225. if (Objects.nonNull(tcPaperStruct.getPaperStructDimension())) {
  226. paperStructDimensionResultList = GsonUtil.fromJson(tcPaperStruct.getPaperStructDimension(), new TypeToken<List<PaperStructDimensionResult>>() {
  227. }.getType());
  228. } else if (Objects.nonNull(tcPaperStruct.getPaperStruct())) {
  229. List<PaperStructDto> paperStructDtoList = GsonUtil.fromJson(tcPaperStruct.getPaperStruct(), new TypeToken<List<PaperStructDto>>() {
  230. }.getType());
  231. paperStructDimensionResultList = new ArrayList<>(paperStructDtoList.size());
  232. for (PaperStructDto paperStructDto : paperStructDtoList) {
  233. paperStructDimensionResultList.add(new PaperStructDimensionResult(paperStructDto.getMainNumber(), paperStructDto.getSubNumber(), tcPaperStruct.getPaperNumber(), paperStructDto.getScore()));
  234. }
  235. }
  236. return paperStructDimensionResultList;
  237. }
  238. }