package com.qmth.distributed.print.api; import com.google.gson.reflect.TypeToken; import com.qmth.boot.api.constant.ApiConstant; import com.qmth.boot.api.exception.ApiException; import com.qmth.distributed.print.business.bean.dto.CourseWeightDto; import com.qmth.distributed.print.business.bean.excel.PaperStructDto; import com.qmth.distributed.print.business.bean.params.report.PaperStructParams; import com.qmth.distributed.print.business.bean.result.CourseWeightResult; import com.qmth.distributed.print.business.bean.result.EditResult; import com.qmth.distributed.print.business.bean.result.report.PaperStructDimensionResult; import com.qmth.distributed.print.business.entity.TCPaperStruct; import com.qmth.distributed.print.business.service.PrintCommonService; import com.qmth.distributed.print.business.service.TCPaperStructService; import com.qmth.distributed.print.business.service.TRBasicInfoService; import com.qmth.teachcloud.common.annotation.OperationLogDetail; import com.qmth.teachcloud.common.contant.SystemConstant; import com.qmth.teachcloud.common.entity.MarkQuestion; import com.qmth.teachcloud.common.entity.SysUser; import com.qmth.teachcloud.common.enums.ExceptionResultEnum; import com.qmth.teachcloud.common.enums.log.CustomizedOperationTypeEnum; import com.qmth.teachcloud.common.util.*; import com.qmth.teachcloud.mark.entity.MarkPaper; import com.qmth.teachcloud.mark.service.MarkQuestionService; import io.swagger.annotations.*; import org.apache.commons.collections4.CollectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.validation.Valid; import java.io.IOException; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; /** *

* 试卷结构 前端控制器 *

* * @author wangliang * @since 2024-02-18 */ @Api(tags = "课程目标达成度-成绩管理-试卷结构Controller") @RestController @RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + SystemConstant.PREFIX_URL_COURSE_DEGREE) public class TCPaperStructController { private final static Logger log = LoggerFactory.getLogger(TCPaperStructController.class); @Resource MarkQuestionService markQuestionService; @Resource TCPaperStructService tcPaperStructService; @Resource TRBasicInfoService trBasicInfoService; @Resource PrintCommonService printCommonService; @Resource RedisUtil redisUtil; @ApiOperation(value = "导入试卷结构") @RequestMapping(value = "/final_score/paper_struct/import", method = RequestMethod.POST) @OperationLogDetail(customizedOperationType = CustomizedOperationTypeEnum.IMPORT) @ApiResponses({@ApiResponse(code = 200, message = "导入成功", response = EditResult.class)}) public Result finalScorePaperStructImport(@ApiParam(value = "上传文件", required = true) @RequestParam MultipartFile file, @ApiParam(value = "考试id", required = true) @RequestParam Long examId, @ApiParam(value = "科目编码", required = true) @RequestParam String courseCode, @ApiParam(value = "试卷编号", required = true) @RequestParam String paperNumber) throws IOException { printCommonService.getLock(examId, courseCode, paperNumber); String lockKey = SystemConstant.REDIS_PAPER_STRUCT_FLOW_PREFIX + SystemConstant.IMPORT + examId + "_" + courseCode + "_" + paperNumber; boolean lock = redisUtil.lock(lockKey, SystemConstant.REDIS_PAPER_STRUCT_TIME_OUT); if (!lock) { throw ExceptionResultEnum.ERROR.exception("正在导入数据,请稍候再试!"); } Map map = null; try { map = tcPaperStructService.paperStructExcelImport(file, examId, courseCode, paperNumber); } catch (Exception e) { log.error(SystemConstant.LOG_ERROR, e); if (e instanceof ApiException) { ResultUtil.error((ApiException) e, ((ApiException) e).getCode(), e.getMessage()); } else { ResultUtil.error(e.getMessage()); } } finally { redisUtil.releaseLock(lockKey); } return ResultUtil.ok(map); } @ApiOperation(value = "同步试卷蓝图结构") @RequestMapping(value = "/final_score/paper_struct_dimension/sync", method = RequestMethod.POST) @OperationLogDetail(customizedOperationType = CustomizedOperationTypeEnum.PUSH) @ApiResponses({@ApiResponse(code = 200, message = "同步成功", response = EditResult.class)}) public Result finalScorePaperStructDimensionSync(@ApiParam(value = "考试id", required = true) @RequestParam Long examId, @ApiParam(value = "科目编码", required = true) @RequestParam String courseCode, @ApiParam(value = "试卷编号", required = true) @RequestParam String paperNumber) throws IOException { printCommonService.getLock(examId, courseCode, paperNumber); String lockKey = SystemConstant.REDIS_PAPER_STRUCT_FLOW_PREFIX + SystemConstant.SYNC + examId + "_" + courseCode + "_" + paperNumber; boolean lock = redisUtil.lock(lockKey, SystemConstant.REDIS_PAPER_STRUCT_TIME_OUT); if (!lock) { throw ExceptionResultEnum.ERROR.exception("正在同步数据,请稍候再试!"); } Map map = null; try { map = tcPaperStructService.paperStructSync(examId, courseCode, paperNumber); } catch (Exception e) { log.error(SystemConstant.LOG_ERROR, e); if (e instanceof ApiException) { ResultUtil.error((ApiException) e, ((ApiException) e).getCode(), e.getMessage()); } else { ResultUtil.error(e.getMessage()); } } finally { redisUtil.releaseLock(lockKey); } return ResultUtil.ok(map); } @ApiOperation(value = "期末成绩试卷蓝图保存") @RequestMapping(value = "/final_score/paper_struct/save", method = RequestMethod.POST) @OperationLogDetail(customizedOperationType = CustomizedOperationTypeEnum.UPDATE) @ApiResponses({@ApiResponse(code = 200, message = "试卷蓝图保存", response = Object.class)}) @Transactional public Result finalScorePaperStructSave(@ApiParam(value = "试卷蓝图结构", required = true) @Valid @RequestBody PaperStructParams paperStructParams, BindingResult bindingResult) throws IOException { if (bindingResult.hasErrors()) { return ResultUtil.error(bindingResult.getAllErrors().get(0).getDefaultMessage()); } printCommonService.getLock(paperStructParams.getExamId(), paperStructParams.getCourseCode(), paperStructParams.getPaperNumber()); CourseWeightResult courseWeightResult = trBasicInfoService.findCourseWeightResultRmi(paperStructParams.getExamId(), paperStructParams.getCourseCode()); for (CourseWeightDto c : courseWeightResult.getSubmitForm()) { for (PaperStructDimensionResult paperStructDimensionResult : paperStructParams.getPaperStruct()) { Objects.requireNonNull(paperStructDimensionResult.getMainNumber(), "大题号为空"); Objects.requireNonNull(paperStructDimensionResult.getSubNumber(), "小题号为空"); if (!CollectionUtils.isEmpty(paperStructDimensionResult.getTargetList()) && paperStructDimensionResult.getTargetList().size() > 1) { throw ExceptionResultEnum.ERROR.exception("一个题只能属于一个目标"); } } List paperStructDimensionResultList = paperStructParams.getPaperStruct(); Double score = paperStructDimensionResultList.stream().filter(s -> Objects.equals(s.getCourseTargetName(), c.getCourseTargetName())).mapToDouble(PaperStructDimensionResult::getScore).sum(); if (new BigDecimal(score).compareTo(c.getTotalWeight()) == 1) { throw ExceptionResultEnum.ERROR.exception("[" + c.getCourseTargetName() + "]知识点小题总分大于该课程目标分,请重新设置"); } paperStructDimensionResultList.stream().filter(s -> { if (Objects.equals(s.getCourseTargetName(), c.getCourseTargetName())) { s.getTargetList().stream().peek(e -> e.setFinalScoreQuestionScoreSum(score)).collect(Collectors.toList()); return true; } return false; }).collect(Collectors.toList()); } SysUser sysUser = (SysUser) ServletUtil.getRequestUser(); TCPaperStruct tcPaperStructDb = tcPaperStructService.queryByExamIdAndCourseCodeAndPaperNumber(paperStructParams.getExamId(), paperStructParams.getCourseCode(), paperStructParams.getPaperNumber()); if (Objects.isNull(tcPaperStructDb)) { MarkPaper markPaper = printCommonService.getMarkPaper(paperStructParams.getExamId(), paperStructParams.getPaperNumber()); tcPaperStructDb = new TCPaperStruct(paperStructParams.getExamId(), paperStructParams.getCourseCode(), markPaper.getCourseName(), paperStructParams.getPaperNumber(), JacksonUtil.parseJson(paperStructParams.getPaperStruct()), sysUser.getId(), courseWeightResult.getDimensionSign()); tcPaperStructService.save(tcPaperStructDb); } else { TCPaperStruct tcPaperStructSource = new TCPaperStruct(); BeanUtils.copyProperties(tcPaperStructDb, tcPaperStructSource); tcPaperStructDb.updateInfo(JacksonUtil.parseJson(paperStructParams.getPaperStruct()), sysUser.getId()); if (!tcPaperStructDb.equals(tcPaperStructSource)) { trBasicInfoService.clearReportData(tcPaperStructDb.getExamId(), tcPaperStructDb.getCourseCode(), tcPaperStructDb.getPaperNumber(), false); tcPaperStructDb.setDimensionSign(courseWeightResult.getDimensionSign()); tcPaperStructService.updateById(tcPaperStructDb); } } return ResultUtil.ok(true); } @ApiOperation(value = "期末成绩试卷蓝图查询") @RequestMapping(value = "/final_score/paper_struct/query", method = RequestMethod.POST) @OperationLogDetail(customizedOperationType = CustomizedOperationTypeEnum.SEARCH) @ApiResponses({@ApiResponse(code = 200, message = "试卷蓝图保存", response = PaperStructDimensionResult.class)}) public Result finalScorePaperStructQuery(@ApiParam(value = "考试id", required = true) @RequestParam Long examId, @ApiParam(value = "科目编码", required = true) @RequestParam String courseCode, @ApiParam(value = "试卷编号", required = true) @RequestParam String paperNumber) throws IOException { printCommonService.getLock(examId, courseCode, paperNumber); List paperStructDimensionResultList = null; TCPaperStruct tcPaperStruct = tcPaperStructService.queryByExamIdAndCourseCodeAndPaperNumber(examId, courseCode, paperNumber); if (Objects.isNull(tcPaperStruct) || Objects.isNull(tcPaperStruct.getPaperStruct())) { List markQuestionList = markQuestionService.listQuestionByExamIdAndPaperNumberAndPaperType(examId, paperNumber, null); if (CollectionUtils.isEmpty(markQuestionList)) { throw ExceptionResultEnum.ERROR.exception("未找到试卷结构"); } paperStructDimensionResultList = new ArrayList<>(markQuestionList.size()); for (MarkQuestion markQuestion : markQuestionList) { paperStructDimensionResultList.add(new PaperStructDimensionResult(markQuestion.getMainNumber(), markQuestion.getSubNumber(), markQuestion.getTotalScore())); } } else { CourseWeightResult courseWeightResult = trBasicInfoService.findCourseWeightResultRmi(examId, courseCode); if (Objects.nonNull(tcPaperStruct.getDimensionSign()) && tcPaperStruct.getDimensionSign().longValue() != courseWeightResult.getDimensionSign().longValue()) { trBasicInfoService.clearReportData(examId, courseCode, paperNumber, false); paperStructDimensionResultList = this.getPaperStructDimensionResult(tcPaperStruct, paperStructDimensionResultList); } else { paperStructDimensionResultList = this.getPaperStructDimensionResult(tcPaperStruct, paperStructDimensionResultList); } } return ResultUtil.ok(paperStructDimensionResultList); } /** * 获取试卷结构蓝图数据 * * @param tcPaperStruct * @param paperStructDimensionResultList * @return */ protected List getPaperStructDimensionResult(TCPaperStruct tcPaperStruct, List paperStructDimensionResultList) { if (Objects.nonNull(tcPaperStruct.getPaperStructDimension())) { paperStructDimensionResultList = GsonUtil.fromJson(tcPaperStruct.getPaperStructDimension(), new TypeToken>() { }.getType()); } else if (Objects.nonNull(tcPaperStruct.getPaperStruct())) { List paperStructDtoList = GsonUtil.fromJson(tcPaperStruct.getPaperStruct(), new TypeToken>() { }.getType()); paperStructDimensionResultList = new ArrayList<>(paperStructDtoList.size()); for (PaperStructDto paperStructDto : paperStructDtoList) { paperStructDimensionResultList.add(new PaperStructDimensionResult(paperStructDto.getMainNumber(), paperStructDto.getSubNumber(), paperStructDto.getScore())); } } return paperStructDimensionResultList; } }