package com.ruoyi.sim.service.impl; import java.util.ArrayList; import java.util.List; import java.util.Objects; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.sim.domain.*; import com.ruoyi.sim.domain.vo.RealExamVo; import com.ruoyi.sim.domain.vo.StudentRealExamIngVo; import com.ruoyi.sim.domain.vo.StudentRealExamPostVo; import com.ruoyi.sim.domain.vo.StudentRealExamPreVo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.ruoyi.sim.mapper.RealExamMapper; import org.springframework.transaction.annotation.Transactional; /** * 考试Service业务层处理 * * @author tom * @date 2024-12-15 */ @Service public class RealExamService { @Autowired private RealExamMapper realExamMapper; /** * 查询考试 * * @param examId 考试主键 * @return 考试 */ public RealExam selectRealExamByExamId(Long examId) { return realExamMapper.selectRealExamByExamId(examId); } /** * 查询考试列表 * * @param realExam 考试 * @return 考试 */ public List selectRealExamList(RealExam realExam) { return realExamMapper.selectRealExamList(realExam); } /** * 新增考试 * * @param realExam 考试 * @return 结果 */ public int insertRealExam(RealExam realExam) { realExam.setCreateTime(DateUtils.getNowDate()); return realExamMapper.insertRealExam(realExam); } /** * 修改考试 * * @param realExam 考试 * @return 结果 */ public int updateRealExam(RealExam realExam) { realExam.setUpdateTime(DateUtils.getNowDate()); return realExamMapper.updateRealExam(realExam); } /** * 批量删除考试 * * @param examIds 需要删除的考试主键 * @return 结果 */ public int deleteRealExamByExamIds(Long[] examIds) { return realExamMapper.deleteRealExamByExamIds(examIds); } /** * 删除考试信息 * * @param examId 考试主键 * @return 结果 */ public int deleteRealExamByExamId(Long examId) { return realExamMapper.deleteRealExamByExamId(examId); } // -------------------------------- tom add -------------------------------- private static final Logger l = LoggerFactory.getLogger(CommSendService.class); @Autowired private CommReceiveService commReceiveService; @Autowired private StudentService studentService; @Autowired private SimService simService; @Autowired private SeatService seatService; @Autowired private RealExamCollectionService realExamCollectionService; @Autowired private RealExamFaultService realExamFaultService; @Autowired private CommSendService commSendService; public List list(RealExam q) { List list = new ArrayList<>(); realExamMapper.selectRealExamList(q).forEach(re -> { RealExamVo v = new RealExamVo(); RealExamCollection rec = realExamCollectionService.selectRealExamCollectionByExamCollectionId(re.getExamCollectionId()); v.setRealExam(re); v.setRealExamCollection(rec); list.add(v); }); return list; } public List listAllByStatus(String state) { RealExam q = new RealExam(); q.setExamStatus(state); return selectRealExamList(q); } /** * 交卷自动修改关联状态 * * @param examId * @param state * @return */ @Transactional public int updateOneState(long examId, final String state) { RealExam q = selectRealExamByExamId(examId); // todo:屏蔽 if (false && RealExam.State.SUBMITTED.equals(state)) { // 关联故障list同步锁死。 realExamFaultService.listAllType2LoopReadStateByExamId(q.getExamId()) .forEach(ref -> { ref.setRefState(RealExamFault.State.FINISH); realExamFaultService.updateRealExamFault(ref); }); } q.setExamStatus(state); return updateRealExam(q); } /** * [学生]进入考试。 * * @return */ public AjaxResult studentEnterRealExam(Long examId) { RealExam re = selectRealExamByExamId(examId); if (re == null) { AjaxResult.error("realExamId error!"); } // todo:应该在登录位置实现 // todo: temp updateOneState(examId, RealExam.State.LOGGED_IN); // todo: temp realExamFaultService.resetAllType2(examId); return AjaxResult.success(re); } /** * [轮询][学生]准备考试界面。 * * @param realExamId * @return */ public AjaxResult studentLoopPrepareRealExam(Long realExamId) { l.info("studentLoopPrepareRealExam"); // check if (realExamId == null || realExamId == 0) { // todo: } // RealExam re = selectRealExamByExamId(realExamId); if (re == null) { // todo: } // todo: 日期,不可进入考试。 // // todo: 验证学生登录身份 Objects.requireNonNull(re); RealExamCollection collection = realExamCollectionService.selectRealExamCollectionByExamCollectionId(re.getExamCollectionId()); // check collection Sim sim = simService.selectSimBySimId(re.getSimId()); // check sim Student student = studentService.selectStudentByUserId(re.getUserId()); // check student Seat seat = seatService.selectSeatBySeatId(re.getSeatId()); // check seat StudentRealExamPreVo vo = new StudentRealExamPreVo(); vo.setRealExam(re); vo.setRealExamCollection(collection); vo.setSim(sim); vo.setStudent(student); vo.setSeat(seat); // todo:多人请求同时进入的问题 boolean next = studentPrepareRealExamCheck(vo); vo.setNext(next); if (!next) { // 执行模拟器通信,让模拟器准备好。 // 异步执行 commSendService.clearListFaultByRealExamAsync(re); } l.info("vo = {}", vo); return AjaxResult.success(vo); } public boolean studentPrepareRealExamCheck(StudentRealExamPreVo v) { if (v == null || v.getRealExam() == null || v.getRealExamCollection() == null || v.getSim() == null || v.getStudent() == null || v.getSeat() == null) { return false; } // todo:在考试日期内。 // check 一个模拟器的所有选中故障点位都下发成功,准备是否可以 // // todo:?? // 学生答题中可以再次进入。 String examStatus = v.getRealExam().getExamStatus(); String simStatus = v.getSim().getSimState(); if ((RealExam.State.SIM_PREPARE_OK.equals(examStatus) || RealExam.State.ANSWERING.equals(examStatus)) && Sim.State.ONLINE.equals(simStatus) ) { return true; } return false; } /** * [学生]开始考试 * * @param examId * @return */ @Transactional public AjaxResult studentStartRealExam(Long examId) { l.info("studentStartRealExam"); RealExam re = selectRealExamByExamId(examId); l.info("re = {}", re); re.setExamStatus(RealExam.State.ANSWERING); re.setStartTime(DateUtils.getNowDate()); updateRealExam(re); return AjaxResult.success(re); } /** * [轮询][学生]正在考试界面。 * * @param realExamId * @return */ public AjaxResult studentLoopAnsweringRealExam(Long realExamId) { RealExam re = selectRealExamByExamId(realExamId); RealExamCollection rec = realExamCollectionService.selectRealExamCollectionByExamCollectionId(re.getExamCollectionId()); StudentRealExamIngVo vo = new StudentRealExamIngVo(); vo.setRealExam(re); long remaining = (re.getStartTime().getTime() + rec.getLimitDuration() * 60 * 1000) - DateUtils.getNowDate().getTime(); vo.setRemainingMilliseconds(remaining); vo.setCompulsiveSubmit(remaining >= RealExam.EXAM_TIMEOUT_LIMIT); l.info("studentLoopAnsweringRealExam vo = {}", vo); return AjaxResult.success(vo); } /** * [学生]交卷 * * @param examId * @return */ public AjaxResult studentSubmitRealExam(Long examId) { // 最后检查一下模拟器状态。 // 最后读取一下模拟器电阻值。 // todo: RealExam re1 = selectRealExamByExamId(examId); commSendService.readOneExamAtLastAsync(re1); submit(examId); return AjaxResult.success(re1); } /** * @param examId */ @Transactional public void submit(long examId) { l.info("submit"); RealExam re2 = selectRealExamByExamId(examId); re2.setExamStatus(RealExam.State.SUBMITTED); re2.setEndTime(DateUtils.getNowDate()); updateRealExam(re2); } /** * [轮询][学生]结束考试界面。 * * @param examId * @return */ public AjaxResult studentLoopPostRealExam(Long examId) { RealExam re = selectRealExamByExamId(examId); StudentRealExamPostVo vo = new StudentRealExamPostVo(); { } vo.setRealExam(re); vo.setListPart1(realExamFaultService.getReportListPart1(examId)); return AjaxResult.success(vo); } }