|  | @@ -3,6 +3,7 @@ package com.ruoyi.sim.service.impl;
 | 
	
		
			
				|  |  |  import java.util.ArrayList;
 | 
	
		
			
				|  |  |  import java.util.List;
 | 
	
		
			
				|  |  |  import java.util.Objects;
 | 
	
		
			
				|  |  | +import java.util.Spliterator;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import com.ruoyi.common.core.domain.AjaxResult;
 | 
	
		
			
				|  |  |  import com.ruoyi.common.utils.DateUtils;
 | 
	
	
		
			
				|  | @@ -318,7 +319,24 @@ public class RealExamService {
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          RealExam re = selectRealExamByExamId(examId);
 | 
	
		
			
				|  |  | +        // check:考试状态
 | 
	
		
			
				|  |  | +        if (StringUtils.equals(re.getExamStatus(), RealExam.State.SUBMITTED) ||
 | 
	
		
			
				|  |  | +                StringUtils.equals(re.getExamStatus(), RealExam.State.CALCULATING_SCORE) ||
 | 
	
		
			
				|  |  | +                StringUtils.equals(re.getExamStatus(), RealExam.State.GOT_REPORT)) {
 | 
	
		
			
				|  |  | +            return AjaxResult.error("已经交卷,禁止重复开始考试!");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |          RealExamCollection rec = realExamCollectionService.selectRealExamCollectionByExamCollectionId(re.getExamCollectionId());
 | 
	
		
			
				|  |  | +        // Check:考试集合数据有效性。
 | 
	
		
			
				|  |  | +        if (rec == null) {
 | 
	
		
			
				|  |  | +            return AjaxResult.error("考试集合数据异常!");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        if (!StringUtils.equals(rec.getExamCollectionState(), RealExamCollection.State.OPENED)) {
 | 
	
		
			
				|  |  | +            return AjaxResult.error("教师端对应考试/训练尚未打开!<br/>请向教员说明情况。");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        // Check:检查参数examCollectionType有效性
 | 
	
		
			
				|  |  | +        if (!StringUtils.equals(examCollectionType, rec.getExamCollectionType())) {
 | 
	
		
			
				|  |  | +            return AjaxResult.error("考试集合类型不对应!");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |          // Check:检查参数studentBindIp有效性
 | 
	
		
			
				|  |  |          if (StringUtils.isBlank(studentBindIp)) {
 | 
	
		
			
				|  |  |              return AjaxResult.error("IP地址无效");
 | 
	
	
		
			
				|  | @@ -327,10 +345,6 @@ public class RealExamService {
 | 
	
		
			
				|  |  |          if (seat == null) {
 | 
	
		
			
				|  |  |              return AjaxResult.error("没有IP对应座次数据!");
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        // Check:检查参数examCollectionType有效性
 | 
	
		
			
				|  |  | -        if (!StringUtils.equals(examCollectionType, rec.getExamCollectionType())) {
 | 
	
		
			
				|  |  | -            return AjaxResult.error("考试集合类型不对应!");
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  |          // Check:ping通 路由器。
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              AjaxResult ar = commCheckService.checkRouterState(simConfig.getRouterIp());
 | 
	
	
		
			
				|  | @@ -373,12 +387,20 @@ public class RealExamService {
 | 
	
		
			
				|  |  |                  return ar;
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        // Step:正式开始考试。锁定 座次 和 模拟器。
 | 
	
		
			
				|  |  |          // Step:重新查询。已经确定simId和simState了。
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              // 修改exam表对应examId的一条数据,填充并锁定seat_id和sim_id值。
 | 
	
		
			
				|  |  |              // 设置上seatId和simId
 | 
	
		
			
				|  |  |              re = selectRealExamByExamId(examId);
 | 
	
		
			
				|  |  |              seat = seatService.uniqueByBindIp(studentBindIp);
 | 
	
		
			
				|  |  | +            if (seat.getCurrentSimId() == 0L) {
 | 
	
		
			
				|  |  | +                return AjaxResult.success("参数错误,座次上CurrentSimId = 0");
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            if (seat.getSeatId() == 0L) {
 | 
	
		
			
				|  |  | +                return AjaxResult.success("参数错误,座次上getSeatId = 0");
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            l.debug("seat = {}", seat);
 | 
	
		
			
				|  |  |              re.setSeatId(seat.getSeatId());
 | 
	
		
			
				|  |  |              re.setSimId(seat.getCurrentSimId());
 | 
	
		
			
				|  |  |              updateRealExam(re);
 | 
	
	
		
			
				|  | @@ -407,7 +429,6 @@ public class RealExamService {
 | 
	
		
			
				|  |  |                  return ar;
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        // Step:正式开始考试。
 | 
	
		
			
				|  |  |          // Step:清除对应一台模拟器 所有 真实的 故障部位故障。
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              commSendService.clearOneSimAllFaultByExam(re);
 | 
	
	
		
			
				|  | @@ -475,6 +496,8 @@ public class RealExamService {
 | 
	
		
			
				|  |  |          return AjaxResult.success(vo);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    public static final Long DURATION_10_MIN = 1000L * 60 * 10;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      /**
 | 
	
		
			
				|  |  |       * [学生]交卷考试
 | 
	
		
			
				|  |  |       *
 | 
	
	
		
			
				|  | @@ -491,10 +514,38 @@ public class RealExamService {
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          RealExam re = selectRealExamByExamId(examId);
 | 
	
		
			
				|  |  | +        if (re == null ||
 | 
	
		
			
				|  |  | +                re.getExamId() == 0L ||
 | 
	
		
			
				|  |  | +                re.getSimId() == null ||
 | 
	
		
			
				|  |  | +                re.getSimId() == 0L ||
 | 
	
		
			
				|  |  | +                re.getExamCollectionId() == null ||
 | 
	
		
			
				|  |  | +                re.getExamCollectionId() == 0L) {
 | 
	
		
			
				|  |  | +            l.debug("RealExam = {}", re);
 | 
	
		
			
				|  |  | +            return AjaxResult.error("交卷数据错误!");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        if (re.getStartTime() == null) {
 | 
	
		
			
				|  |  | +            return AjaxResult.error("考试开始时间异常!");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        // check:考试状态
 | 
	
		
			
				|  |  | +        if (StringUtils.equals(re.getExamStatus(), RealExam.State.SUBMITTED)) {
 | 
	
		
			
				|  |  | +            return AjaxResult.error("已经交卷,禁止重复交卷,<br/>请刷新自动结束考试!");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |          RealExamCollection rec = realExamCollectionService.selectRealExamCollectionByExamCollectionId(re.getExamCollectionId());
 | 
	
		
			
				|  |  | +        // 允许考试时长,毫秒
 | 
	
		
			
				|  |  | +        Long millisecondsAllowed = rec.getLimitDuration() * 60 * 1000 + DURATION_10_MIN;
 | 
	
		
			
				|  |  | +        // Check:已经超时的交卷。
 | 
	
		
			
				|  |  | +        if (DateUtils.getNowDate().getTime() > re.getStartTime().getTime() + millisecondsAllowed) {
 | 
	
		
			
				|  |  | +            // 修改考试状态
 | 
	
		
			
				|  |  | +            re.setExamStatus(RealExam.State.SUBMITTED);
 | 
	
		
			
				|  |  | +            // 修改真实考试结束时间。
 | 
	
		
			
				|  |  | +            re.setEndTime(DateUtils.getNowDate());
 | 
	
		
			
				|  |  | +            updateRealExam(re);
 | 
	
		
			
				|  |  | +            return AjaxResult.success("考试时间已经超时,自动结束考试!");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          // Check:检查参数studentBindIp有效性
 | 
	
		
			
				|  |  |          if (StringUtils.isBlank(studentBindIp)) {
 | 
	
		
			
				|  |  | -            return AjaxResult.error("IP地址无效");
 | 
	
		
			
				|  |  | +            return AjaxResult.error("IP地址无效!");
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          // 现在交卷的座次
 | 
	
		
			
				|  |  |          Seat seatNow = seatService.uniqueByBindIp(studentBindIp);
 |