|  | @@ -381,6 +381,12 @@ public class RealExamService {
 | 
	
		
			
				|  |  |                  return ar;
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        // 针对练习(自主练习),进行特殊检查。
 | 
	
		
			
				|  |  | +        if (StringUtils.equals(RealExamCollection.Type.SELF_EXERCISE, examCollectionType)) {
 | 
	
		
			
				|  |  | +            // 已经open的考试。
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // 已经open的训练。
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |          // Step:可换件检查,读取对应一台模拟器 所有故障部位值。
 | 
	
		
			
				|  |  |          //      检查模拟器所有的 真实的 故障部位 是否异常 或者 空值。特殊的故障部位要单独判断。
 | 
	
		
			
				|  |  |          if (SimDebugConfig.CHECK_REPLACE_EMPTY) {
 | 
	
	
		
			
				|  | @@ -389,6 +395,7 @@ public class RealExamService {
 | 
	
		
			
				|  |  |                  return ar;
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        // Step:正式开始考试。
 | 
	
		
			
				|  |  |          // Step:清除对应一台模拟器 所有 真实的 故障部位故障。
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              commSendService.clearOneSimAllFaultByExam(re);
 | 
	
	
		
			
				|  | @@ -464,34 +471,89 @@ public class RealExamService {
 | 
	
		
			
				|  |  |       */
 | 
	
		
			
				|  |  |      @Transactional
 | 
	
		
			
				|  |  |      public AjaxResult studentSubmitRealExam(final Long examId, final String studentBindIp, final String examCollectionType) {
 | 
	
		
			
				|  |  | +        // Check:检查参数examId有效性
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            AjaxResult ar = checkExamId(examId);
 | 
	
		
			
				|  |  | +            if (ar.isError()) {
 | 
	
		
			
				|  |  | +                return ar;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |          RealExam re = selectRealExamByExamId(examId);
 | 
	
		
			
				|  |  | -        // Step :检查参数examId有效性
 | 
	
		
			
				|  |  | -        // Step :检查参数studentBindIp有效性
 | 
	
		
			
				|  |  | -        // Step :检查参数examCollectionType有效性
 | 
	
		
			
				|  |  | -        // check part.
 | 
	
		
			
				|  |  | +        RealExamCollection rec = realExamCollectionService.selectRealExamCollectionByExamCollectionId(re.getExamCollectionId());
 | 
	
		
			
				|  |  | +        // Check:检查参数studentBindIp有效性
 | 
	
		
			
				|  |  | +        if (StringUtils.isBlank(studentBindIp)) {
 | 
	
		
			
				|  |  | +            return AjaxResult.error("IP地址无效");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        // 现在交卷的座次
 | 
	
		
			
				|  |  | +        Seat seatNow = seatService.uniqueByBindIp(studentBindIp);
 | 
	
		
			
				|  |  | +        // 开始考试的座次
 | 
	
		
			
				|  |  | +        Seat seatStart = seatService.selectSeatBySeatId(re.getSeatId());
 | 
	
		
			
				|  |  | +        if (seatNow == null || seatStart == null) {
 | 
	
		
			
				|  |  | +            return AjaxResult.error("没有IP对应座次数据!");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        // Check:防止换座位交卷。
 | 
	
		
			
				|  |  | +        if (!Objects.equals(seatStart.getSeatId(), seatNow.getSeatId())) {
 | 
	
		
			
				|  |  | +            return AjaxResult.error("没有在原始座次上交卷,请回到原座次[" + seatStart.getSeatNum() + "]上进行交卷!");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Check:检查参数examCollectionType有效性
 | 
	
		
			
				|  |  | +        if (!StringUtils.equals(examCollectionType, rec.getExamCollectionType())) {
 | 
	
		
			
				|  |  | +            return AjaxResult.error("考试集合类型不对应!");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        // Check:ping通 RS485。
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            AjaxResult ar = commCheckService.checkPingRs485State(seatStart.getSeatRs485Ip());
 | 
	
		
			
				|  |  | +            if (ar.isError()) {
 | 
	
		
			
				|  |  | +                // todo:重复
 | 
	
		
			
				|  |  | +                // 更新SimId
 | 
	
		
			
				|  |  | +                seatService.updateSimIdBySeatNum(seatStart.getSeatNum(), Seat.ID_0);
 | 
	
		
			
				|  |  | +                // 更新SocketState
 | 
	
		
			
				|  |  | +                seatService.updateSocketStateBySeatNum(seatStart.getSeatNum(), Seat.SocketState.OFFLINE);
 | 
	
		
			
				|  |  | +                return ar;
 | 
	
		
			
				|  |  | +            } else {
 | 
	
		
			
				|  |  | +                // Ping通不代表在线,Socket连接建立表示在线。
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        // Check:如果有缓存Socket并且可用,使用缓存Socket,检查并建立Socket连接;否则返回对应错误。
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            AjaxResult arE1 = checkExamId(examId);
 | 
	
		
			
				|  |  | -            if (arE1.isError()) {
 | 
	
		
			
				|  |  | -                return arE1;
 | 
	
		
			
				|  |  | +            AjaxResult ar = socketService.openOne(seatStart.toSimSocketParamVo(), true);
 | 
	
		
			
				|  |  | +            if (ar.isError()) {
 | 
	
		
			
				|  |  | +                return ar;
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        // 检查一下模拟器状态。
 | 
	
		
			
				|  |  | -        Seat seat = seatService.selectSeatBySeatId(re.getSeatId());
 | 
	
		
			
				|  |  | +        // Check:发送通用询问指令,询问是连接的哪种型号的哪一台模拟器;否则返回对应错误。
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            AjaxResult ar = commCheckService.checkOneSeatState(seatStart, true);
 | 
	
		
			
				|  |  | +            if (ar.isError()) {
 | 
	
		
			
				|  |  | +                return ar;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        // Step:查询模拟器在线状态,纯DB查询。
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            AjaxResult ar = commCheckService.checkOneSimOnlineState(seatStart.getCurrentSimId());
 | 
	
		
			
				|  |  | +            if (ar.isError()) {
 | 
	
		
			
				|  |  | +                return ar;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        // Check:检查是否是出题值使用的模拟器。防止换机器交卷。
 | 
	
		
			
				|  |  | +        re = selectRealExamByExamId(examId);
 | 
	
		
			
				|  |  | +        if (!Objects.equals(re.getSimId(), seatNow.getCurrentSimId())) {
 | 
	
		
			
				|  |  | +            return AjaxResult.error("没有使用原始模拟器交卷,请使用模拟器[" +
 | 
	
		
			
				|  |  | +                    simService.selectSimBySimId(re.getSimId()).getSimNum() +
 | 
	
		
			
				|  |  | +                    "]进行交卷!");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // todo:检查一下模拟器状态。
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        // 检查换学生端交卷的情况。
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Check:检查换学生端交卷的情况。
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          //
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        // 如果模拟器离线
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            // AjaxResult arE3 = commSendService.checkOneSimStateActive(seat);
 | 
	
		
			
				|  |  | -            AjaxResult arE3 = commCheckService.checkOneSeatState(seat, true);
 | 
	
		
			
				|  |  | -            if (arE3.isError()) {
 | 
	
		
			
				|  |  | -                return arE3;
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        // 最后读取一下模拟器电阻值。
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Step:最后读取一下模拟器电阻值。
 | 
	
		
			
				|  |  |          commSendService.readOneExamAtLast(re);
 | 
	
		
			
				|  |  | +        // Step:
 | 
	
		
			
				|  |  |          if (realExamFaultService.isType2ExamPrepareSubmitOk(re.getExamId())) {
 | 
	
		
			
				|  |  |              re.setExamStatus(RealExam.State.SUBMITTED);
 | 
	
		
			
				|  |  |              // 修改真实考试结束时间。
 |