diff --git a/src/main/java/club/joylink/rtss/controller/simulation/SimulationTrainingV2Controller.java b/src/main/java/club/joylink/rtss/controller/simulation/SimulationTrainingV2Controller.java index 47d3cf82d..ba5b9487f 100644 --- a/src/main/java/club/joylink/rtss/controller/simulation/SimulationTrainingV2Controller.java +++ b/src/main/java/club/joylink/rtss/controller/simulation/SimulationTrainingV2Controller.java @@ -99,4 +99,14 @@ public class SimulationTrainingV2Controller { public void drawTraining(@PathVariable String group, @PathVariable Long trainingId) { training2Service.drawTraining(group, trainingId); } + + /** + * 加载实训到第{stepId}步 + * @param group 仿真ID + * @param stepId 步数ID + */ + @PutMapping("/{group}/jumpTo/{stepId}") + public void jumpToStep(@PathVariable String group, @PathVariable Long stepId){ + training2Service.jumpToStep(group, stepId); + } } diff --git a/src/main/java/club/joylink/rtss/services/training2/Training2Service.java b/src/main/java/club/joylink/rtss/services/training2/Training2Service.java index 2aeec18aa..b2cd83332 100644 --- a/src/main/java/club/joylink/rtss/services/training2/Training2Service.java +++ b/src/main/java/club/joylink/rtss/services/training2/Training2Service.java @@ -9,9 +9,6 @@ import club.joylink.rtss.simulation.cbtc.ATS.ATSMessageCollectAndDispatcher; import club.joylink.rtss.simulation.cbtc.ATS.operation.AtsOperationDispatcher; import club.joylink.rtss.simulation.cbtc.ATS.operation.Operation; import club.joylink.rtss.simulation.cbtc.*; -import club.joylink.rtss.simulation.cbtc.conversation.Conversation; -import club.joylink.rtss.simulation.cbtc.conversation.ConversationManagerService; -import club.joylink.rtss.simulation.cbtc.conversation.ConversationMessage; import club.joylink.rtss.simulation.cbtc.data.map.Switch; import club.joylink.rtss.simulation.cbtc.data.vo.ConversationMessageVO; import club.joylink.rtss.simulation.cbtc.data.vo.Training2MessageVO; @@ -26,7 +23,6 @@ import club.joylink.rtss.simulation.cbtc.member.MemberManager; import club.joylink.rtss.simulation.cbtc.member.SimulationMember; import club.joylink.rtss.simulation.cbtc.script.ScriptBO; import club.joylink.rtss.simulation.cbtc.training2.Operation2; -import club.joylink.rtss.simulation.cbtc.training2.ScoringRule2; import club.joylink.rtss.simulation.cbtc.training2.Step2; import club.joylink.rtss.simulation.cbtc.training2.Training2; import club.joylink.rtss.simulation.cbtc.training2.index.Index; @@ -37,7 +33,6 @@ import club.joylink.rtss.vo.LoginUserInfoVO; import club.joylink.rtss.vo.client.SocketMessageVO; import club.joylink.rtss.vo.client.WebSocketMessageType; import club.joylink.rtss.vo.client.factory.SocketMessageFactory; -import club.joylink.rtss.vo.client.training2.ScoringRuleVO; import club.joylink.rtss.vo.paper.PaperTrainAnswerDetail; import club.joylink.rtss.websocket.StompMessageService; import lombok.extern.slf4j.Slf4j; @@ -48,6 +43,8 @@ import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestAttribute; import java.util.*; import java.util.concurrent.Semaphore; @@ -151,6 +148,18 @@ public class Training2Service { Step2 step = getNextStepAndCheckTrainingStatus(training2, simulation); // 如果步骤执行完毕 或者 步骤内操作全部是前端操作则直接返回交于前端操作 || step.allClientOperation() if (step == null) { + if (training2.haveJumpStep()) { // 当跳转步骤是最后一步时,结束需要做额外清空 + clearJumpStep(simulation); + } + return; + } + // 因为是跳转,前端不需要操作,直接置成成功 + if (training2.isJumpStep(step)) { + step.getOperations().forEach(Operation2::doSuccessVail); + } + // 如果跳转到目标步骤,停止加速并置空跳转步骤 + if (training2.haveJumpStep() && !training2.isJumpStep(step)) { + clearJumpStep(simulation); return; } // 尝试触发步骤 @@ -247,20 +256,7 @@ public class Training2Service { if (training2 == null) { throw new SimulationException(SimulationExceptionType.Invalid_Operation, "实训数据不存在"); } - if (!StringUtils.isEmpty(training2.getBgSceneJson())) { - if (training2.isNeedReloadScenes()) { - groupSimulationService.loadScenes(simulation.getId(), training2.getBgSceneJson()); - } - } else { - // 重置仿真状态 - simulationService.reset(simulation.getId()); - } - atsMessageCollectAndDispatcher.collectAllAndSend(simulation); - // 增加实训任务 - training2.start(mode); - addTrainingJob(simulation, training2); - // 启动仿真 - simulationLifeCycleService.resume(simulation); + doStartTraining(mode, simulation, training2); } /** @@ -437,6 +433,9 @@ public class Training2Service { simCommand2.doCompletion(); startFlag = Boolean.TRUE; } + if (training2.getJumpToStep() != null) { // 处于跳转状态下,下边步骤不执行 + return; + } // 指令执行后启动仿真 if (simulation.isPause() && startFlag) { simulation.start(); @@ -538,6 +537,26 @@ public class Training2Service { sendSimulationConversation(simulation); } + /** + * 加载实训到第几步 + * @param group 仿真 + * @param stepId 实训步数ID + */ + public void jumpToStep(String group, Long stepId) { + Simulation simulation = groupSimulationCache.getSimulationByGroup(group); + Training2 training2 = simulation.getTraining2(); + try { + Step2 step2 = training2.getStep(stepId.intValue()); // 跳转目标步骤 + training2.setJumpToStep(step2); + doStartTraining(null, simulation, training2); // 开始执行 + simulation.updateSpeed(Simulation.MAX_SPEED); + } catch (Exception e) { + log.error("loadTrainingToStep is error", e); + training2.finish(); + removeTrainingJob(simulation); + } + } + /** * 实训时创建仿真对象 */ @@ -591,7 +610,8 @@ public class Training2Service { */ private boolean checkTrainStepCompletion(Step2 step, Simulation simulation) { boolean result = step.doCompletionVail(); - if (result) { + // 如果实在跳过过程中,不需要发消息信息 + if (result && !simulation.getTraining2().isJumpStep(step)) { // 发送步骤完成信息 applicationContext.publishEvent(new SimulationStepFinishEvent(this, simulation, step)); } @@ -635,8 +655,8 @@ public class Training2Service { } } } - // 发送步骤提示信息 - if (!step.isPrompt()) { + // 发送步骤提示信息,需要跳过步骤不发消息 + if (!step.isPrompt() && !simulation.getTraining2().isJumpStep(step)) { step.setPrompt(true); // 标识已发送过消息 applicationContext.publishEvent(new SimulationStepTipEvent(this, simulation, step)); } @@ -676,7 +696,7 @@ public class Training2Service { isExec = (simCurTime == operation2.getSimTime() || operation2.getSimTime() < simCurTime); } if (isExec) { - if (isRobot || operation2.isSpecial()) { // 特殊操作直接执行 + if (isRobot || operation2.isSpecial() || simulation.getTraining2().isJumpStep(step)) { // 特殊操作直接执行 atsOperationDispatcher.execute(simulation, step.getSimulationMember(), operation2.getOperationType().name() , operation2.getParams()); return true; @@ -782,17 +802,19 @@ public class Training2Service { ConversationMessageVO message = (ConversationMessageVO) event.getResult(); String source = String.valueOf(simOperation2.getParams().get("content")); String target = message.getContent(); + boolean doCompletion = false; if (CONVERSATION_TEXT_LIST.contains(event.getOperate())) { - if (Objects.equals(source,target)) { - simOperation2.doOperated(); - } + doCompletion = Objects.equals(source,target); } else { - boolean result = StrUtils.isMatch(source, target, 20); - if (result) { - simOperation2.doOperated(); - } - // 发送步骤完成信息 - applicationContext.publishEvent(new SimulationTrainingAudioEvent(this, simulation, step, simOperation2, result)); + doCompletion = StrUtils.isMatch(source, target, 20); + } + if (doCompletion) { + simOperation2.doOperated(); + simOperation2.doCompletion(); + } + // 发送步骤完成信息 + if (!simulation.getTraining2().isJumpStep(step)) { + applicationContext.publishEvent(new SimulationTrainingAudioEvent(this, simulation, step, simOperation2, doCompletion)); } } @@ -866,4 +888,39 @@ public class Training2Service { } } + + /** + * 开始执行实训 + * + * @param mode 模式 + * @param simulation 仿真 + * @param training2 实训 + */ + private void doStartTraining(ScriptBO.Mode mode, Simulation simulation, Training2 training2) { + if (!StringUtils.isEmpty(training2.getBgSceneJson())) { + if (training2.isNeedReloadScenes() && training2.getJumpToStep() != null) { + groupSimulationService.loadScenes(simulation.getId(), training2.getBgSceneJson()); + } + } else { + // 重置仿真状态 + simulationService.reset(simulation.getId()); + } + if (training2.getJumpToStep() == null) { // 跳转步骤时不需要发送初始状态,减小交互 + atsMessageCollectAndDispatcher.collectAllAndSend(simulation); + } + // 增加实训任务 + training2.start(mode); + addTrainingJob(simulation, training2); + // 启动仿真 + simulationLifeCycleService.resume(simulation); + } + + /** + * 清除当前实训跳转步骤信息 + */ + private void clearJumpStep(Simulation simulation) { + simulation.updateSpeed(Simulation.MIN_SPEED); + simulation.getTraining2().setJumpToStep(null); + simulation.getTraining2().finish(); + } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/alarm/AtsAlarmService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/alarm/AtsAlarmService.java index c0fd4219f..c805311e1 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/alarm/AtsAlarmService.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/ATS/service/alarm/AtsAlarmService.java @@ -55,7 +55,7 @@ public class AtsAlarmService { Simulation simulation = event.getSimulation(); DeviceFaultInfo deviceFaultInfo = event.getDeviceFaultInfo(); List list = simulation.getRepository().getAlarmList().stream() - .filter(atsAlarm -> !atsAlarm.getRecovered() && atsAlarm.getDeviceCode().equals(deviceFaultInfo.getCode())) + .filter(atsAlarm -> (atsAlarm.getRecovered() == null || !atsAlarm.getRecovered()) && atsAlarm.getDeviceCode().equals(deviceFaultInfo.getCode())) .peek(atsAlarm -> atsAlarm.recover(simulation.getCorrectSystemTime())) .collect(Collectors.toList()); SocketMessageVO> messageVO = SocketMessageFactory diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/training2/Operation2.java b/src/main/java/club/joylink/rtss/simulation/cbtc/training2/Operation2.java index ac4bef2f4..fa8f3c304 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/training2/Operation2.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/training2/Operation2.java @@ -122,6 +122,10 @@ public abstract class Operation2 { this.operatedTime = LocalDateTime.now(); } + public boolean isSuccess() { + return Step2.StepStatus.isSuccess(this.status); + } + public void reset() { this.startTime = null; this.operatedTime = null; diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/training2/Training2.java b/src/main/java/club/joylink/rtss/simulation/cbtc/training2/Training2.java index 278f5c853..5ac0df707 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/training2/Training2.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/training2/Training2.java @@ -104,6 +104,10 @@ public class Training2 { */ private Map indexAlgorithmMap; + /** + * 跳转至第几步 + */ + private Step2 jumpToStep; public Training2(DraftTraining2WithBLOBs draftTraining2, Simulation simulation) { this.id = draftTraining2.getId(); @@ -232,6 +236,22 @@ public class Training2 { return Type.SCENE.equals(this.type); } + /** + * 是否是跳转步骤 + * + * @return true | false + */ + public boolean isJumpStep(Step2 step) { + if (jumpToStep == null) { + return false; + } + return steps.indexOf(step) <= steps.indexOf(jumpToStep); + } + + public boolean haveJumpStep() { + return jumpToStep != null; + } + private void resetStepAndIndex() { if (this.steps != null) { this.steps.forEach(Step2::reset);