新增:运行图加线、抽线功能(西铁院)

This commit is contained in:
joylink_zhangsai 2021-07-02 13:40:26 +08:00
parent 517f6bb536
commit 9468e2848b
21 changed files with 396 additions and 156 deletions

View File

@ -73,6 +73,14 @@ public class RunPlanUserDataController {
return iRunPlanRoutingService.getUserRoutingBy(user.getId(), mapId);
}
/**
* 查询用户交路数据
*/
@GetMapping("/{mapId}/routing/select")
public List<RunPlanRoutingVO> queryRoutings(@PathVariable Long mapId, RunPlanRoutingQueryVO queryVO, @RequestAttribute AccountVO user) {
return iRunPlanRoutingService.queryRoutes(mapId, queryVO, user);
}
/**
*获取用户交路详情
*/

View File

@ -6,6 +6,7 @@ import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.map.MapRoutingSectionVO;
import club.joylink.rtss.vo.client.runplan.*;
import club.joylink.rtss.vo.map.MapStationRunLevelVO;
import club.joylink.rtss.vo.map.MapVO;
import club.joylink.rtss.vo.runplan.RunPlanInputData;
import org.springframework.transaction.annotation.Transactional;
@ -147,6 +148,11 @@ public interface IRunPlanDraftService {
*/
void addRunPlanService(Long planId, RunPlanServiceConfigVO serviceConfig, AccountVO accountVO);
/**
* 构建车次计划
*/
RunPlanTripVO buildTripPlan(RunPlanServiceConfigVO serviceConfig, MapVO mapVO, RunPlanTripConfigVO tripConfigVO);
void generateRunPlanService(Long userId, Long planId, RunPlanInputData inputData);
/**

View File

@ -348,8 +348,6 @@ public class RunPlanDraftService implements IRunPlanDraftService {
RunPlanVO planVO = getRunPlanById(planId);
MapVO mapVO = this.iMapService.getMapDetail(planVO.getMapId());
List<RunPlanTripVO> newTripList = new ArrayList<>();
List<RunPlanRoutingVO> userRoutings = runPlanRoutingService.getUserRoutingBy(accountVO.getId(), mapVO.getId());
Map<Long, RunPlanRoutingVO> userRoutingMap = userRoutings.stream().collect(Collectors.toMap(RunPlanRoutingVO::getId, Function.identity(), (o, n) -> o));
for (RunPlanTripConfigVO tripConfigVO : serviceConfig.getTripConfigList()) {
if (StringUtils.hasText(tripConfigVO.getTripNumber())) {
RunPlanTripVO update = planVO.getTripList().stream()
@ -358,19 +356,17 @@ public class RunPlanDraftService implements IRunPlanDraftService {
return true;
}
return false;
}).findFirst().orElseThrow(() -> BusinessExceptionAssertEnum.DATA_NOT_EXIST.exception());
}).findFirst().orElseThrow(BusinessExceptionAssertEnum.DATA_NOT_EXIST::exception);
setTripTimes(tripConfigVO, update, mapVO);
newTripList.add(update);
} else {
// 查询交路
RunPlanRoutingVO routingData = userRoutingMap.get(tripConfigVO.getRoutingCode());
RunPlanTripVO tripVO = new RunPlanTripVO(routingData);
setDirectionCode(mapVO.getConfigVO().getUpRight(), tripVO);
// 构建类车到站数据
tripVO.setServiceNumber(serviceConfig.getServiceNumber());
setTripTimes(tripConfigVO, routingData, tripVO);
// List<RunPlanRoutingVO> userRoutings = runPlanRoutingService.getUserRoutingBy(accountVO.getId(), mapVO.getId());
// Map<Long, RunPlanRoutingVO> userRoutingMap = userRoutings.stream()
// .collect(Collectors.toMap(RunPlanRoutingVO::getId, Function.identity(), (o, n) -> o));
// // 查询交路
// RunPlanRoutingVO routingData = userRoutingMap.get(tripConfigVO.getRoutingCode());
RunPlanTripVO tripVO = buildTripPlan(serviceConfig, mapVO, tripConfigVO);
newTripList.add(tripVO);
}
}
@ -378,10 +374,18 @@ public class RunPlanDraftService implements IRunPlanDraftService {
this.sortAndResetServiceTripNumber(newTripList);
planVO.getTripList().removeAll(planVO.getTripList().stream().filter(tripVO -> tripVO.getServiceNumber().equals(serviceConfig.getServiceNumber())).collect(Collectors.toList()));
planVO.getTripList().addAll(newTripList);
RunPlanDraft planDraft = planVO.convert2Draft();
planDraft.setTrips(JsonUtils.writeValueAsString(planVO.getTripList()));
planDraft.setStatus(BusinessConsts.ReleaseReview.RELEASE_STATUS_01);
runPlanDraftDAO.updateByPrimaryKeySelective(planDraft);
}
@Override
public RunPlanTripVO buildTripPlan(RunPlanServiceConfigVO serviceConfig, MapVO mapVO, RunPlanTripConfigVO tripConfigVO) {
RunPlanRoutingVO routingData = runPlanRoutingService.getUserRouting(tripConfigVO.getRoutingCode());
RunPlanTripVO tripVO = new RunPlanTripVO(routingData);
setDirectionCode(mapVO.getConfigVO().getUpRight(), tripVO);
// 构建列车到站数据
tripVO.setServiceNumber(serviceConfig.getServiceNumber());
setTripTimes(tripConfigVO, routingData, tripVO);
return tripVO;
}
private void updateRunPlanTrip(RunPlanVO runPlanVO, String SDTNumber, RunPlanTripConfigVO tripConfig, MapVO mapVO) {

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.services.runplan;
import club.joylink.rtss.vo.AccountVO;
import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.runplan.user.RunPlanRoutingQueryVO;
import club.joylink.rtss.vo.client.runplan.user.RunPlanRoutingSection;
@ -40,4 +41,6 @@ public interface IRunPlanRoutingService {
void syncDefaultRoutingRefData(Long userId, Long mapId);
RunPlanRoutingVO generateUserRoutingData(RunPlanRoutingVO routingVO);
List<RunPlanRoutingVO> queryRoutes(Long mapId, RunPlanRoutingQueryVO queryVO, AccountVO user);
}

View File

@ -14,6 +14,7 @@ import club.joylink.rtss.simulation.cbtc.data.map.MapElement;
import club.joylink.rtss.simulation.cbtc.data.map.Section;
import club.joylink.rtss.simulation.cbtc.exception.SimulationException;
import club.joylink.rtss.util.JsonUtils;
import club.joylink.rtss.vo.AccountVO;
import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.runplan.RunPlanTripVO;
import club.joylink.rtss.vo.client.runplan.RunPlanVO;
@ -200,6 +201,13 @@ public class RunPlanRoutingService implements IRunPlanRoutingService {
return routingVO;
}
@Override
public List<RunPlanRoutingVO> queryRoutes(Long mapId, RunPlanRoutingQueryVO queryVO, AccountVO user) {
return getUserRoutingBy(user.getId(), mapId).stream()
.filter(routing -> Objects.equals(routing.getDestinationCode(), queryVO.getDestinationCode()))
.collect(Collectors.toList());
}
private void generateUserRoutingSections(RunPlanRoutingVO routingVO, Map<String, MapElement> deviceMap) {
Section startSection = (Section) deviceMap.get(routingVO.getStartSectionCode());
Section endSection = (Section) deviceMap.get(routingVO.getEndSectionCode());

View File

@ -3,6 +3,8 @@ package club.joylink.rtss.simulation.cbtc.ATS;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.data.map.MapElement;
import club.joylink.rtss.simulation.cbtc.data.support.TrainStopMessage;
import club.joylink.rtss.vo.AccountVO;
import club.joylink.rtss.vo.client.runplan.RunPlanServiceConfigVO;
import java.util.List;
@ -43,4 +45,14 @@ public interface AtsApiService {
void handleTrainOnTransfer(Simulation simulation, String groupNumber, String sectionCode);
void cancelStandSkipSetOfTrain(Simulation simulation, String groupNumber, String standCode);
/**
* 添加车次计划加线
*/
void addTripPlan(Simulation simulation, RunPlanServiceConfigVO serviceConfig, AccountVO user);
/**
* 删除车次计划抽线
*/
void deleteTripPlan(Simulation simulation, String serviceNumber, String tripNumber);
}

View File

@ -1,25 +1,34 @@
package club.joylink.rtss.simulation.cbtc.ATS;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.services.IRunPlanDraftService;
import club.joylink.rtss.simulation.cbtc.ATS.service.AtsPlanService;
import club.joylink.rtss.simulation.cbtc.ATS.service.AtsStandService;
import club.joylink.rtss.simulation.cbtc.ATS.service.AtsTrainService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.build.RunPlanBuilder;
import club.joylink.rtss.simulation.cbtc.build.SimulationBuilder;
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
import club.joylink.rtss.simulation.cbtc.data.map.MapElement;
import club.joylink.rtss.simulation.cbtc.data.map.Section;
import club.joylink.rtss.simulation.cbtc.data.map.Stand;
import club.joylink.rtss.simulation.cbtc.data.map.Station;
import club.joylink.rtss.simulation.cbtc.data.plan.SchedulingTrainPlan;
import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;
import club.joylink.rtss.simulation.cbtc.data.support.DeviationInfo;
import club.joylink.rtss.simulation.cbtc.data.support.TrainStopMessage;
import club.joylink.rtss.simulation.cbtc.data.vo.TrainInfo;
import club.joylink.rtss.simulation.cbtc.event.SimulationTripPlanChangeEvent;
import club.joylink.rtss.util.JsonUtils;
import club.joylink.rtss.vo.AccountVO;
import club.joylink.rtss.vo.client.runplan.RunPlanServiceConfigVO;
import club.joylink.rtss.vo.client.runplan.RunPlanTripConfigVO;
import club.joylink.rtss.vo.client.runplan.RunPlanTripVO;
import club.joylink.rtss.vo.client.runplan.RunPlanVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@ -42,6 +51,12 @@ public class AtsApiServiceImpl implements AtsApiService {
@Autowired
private AtsTrainService atsTrainService;
@Autowired
private IRunPlanDraftService iRunPlanDraftService;
@Autowired
private ApplicationContext applicationContext;
@Override
public void handleDeviceStatus(Simulation simulation, List<? extends MapElement> deviceList) {
this.atsMessageCollectAndDispatcher.collectDeviceStatusAndSend(simulation, deviceList);
@ -117,7 +132,42 @@ public class AtsApiServiceImpl implements AtsApiService {
if (Objects.isNull(train)) {
return;
}
atsStandService.cancelJumpStop(simulation, standCode,groupNumber);
atsStandService.cancelJumpStop(simulation, standCode, groupNumber);
}
@Override
public void addTripPlan(Simulation simulation, RunPlanServiceConfigVO serviceConfig, AccountVO user) {
RunPlanTripConfigVO tripConfig = serviceConfig.getTripConfigList().get(0);
String serviceNumber = serviceConfig.getServiceNumber();
String tripNumber = tripConfig.getTripNumber();
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED
.assertNull(simulation.getRepository().findTripPlan(serviceNumber, tripNumber),
String.format("车次计划[%s-%s]已存在", serviceNumber, tripNumber));
RunPlanTripVO tripPlanVO = iRunPlanDraftService.buildTripPlan(serviceConfig, simulation.getBuildParams().getMap(), tripConfig);
tripPlanVO.setTripNumber(tripConfig.getTripNumber());
tripPlanVO.setAdd(true);
RunPlanVO runPlan = simulation.getBuildParams().getRunPlan();
runPlan.getTripList().add(tripPlanVO);
try {
List<String> errMsgList = new ArrayList<>();
TripPlan tripPlan = RunPlanBuilder.buildTripPlan(simulation.getRepository().getDeviceMap(), errMsgList, tripPlanVO);
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotNull(tripPlan, JsonUtils.writeValueAsString(errMsgList));
simulation.getRepository().addTrip(tripPlan);
} catch (RuntimeException e) {
runPlan.getTripList().remove(tripPlanVO);
throw e;
}
applicationContext.publishEvent(new SimulationTripPlanChangeEvent(this, simulation, List.of(tripPlanVO)));
}
@Override
public void deleteTripPlan(Simulation simulation, String serviceNumber, String tripNumber) {
List<TripPlan> invalidList = simulation.getRepository().invalidPlanFrom(serviceNumber, tripNumber);
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertCollectionNotEmpty(invalidList, "车次计划不存在");
RunPlanVO runPlan = simulation.getBuildParams().getRunPlan();
List<RunPlanTripVO> changeTrips = runPlan.invalidTripPlan(invalidList);
simulation.getRepository().addChangeTrips(changeTrips);
applicationContext.publishEvent(new SimulationTripPlanChangeEvent(this, simulation, changeTrips));
}
}

View File

@ -1,24 +1,30 @@
package club.joylink.rtss.simulation.cbtc.ATS.operation.handler;
import club.joylink.rtss.simulation.cbtc.ATS.AtsApiService;
import club.joylink.rtss.simulation.cbtc.ATS.operation.Operation;
import club.joylink.rtss.simulation.cbtc.ATS.operation.annotation.OperateHandler;
import club.joylink.rtss.simulation.cbtc.ATS.operation.annotation.OperateHandlerMapping;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.vo.AccountVO;
import club.joylink.rtss.vo.client.runplan.RunPlanServiceConfigVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@Slf4j
@OperateHandler
public class RunPlanOperateHandler {
@OperateHandlerMapping(type = Operation.Type.RunPlan_Add_Trip)
public void addTripPlan(Simulation simulation) {
@Autowired
private AtsApiService atsApiService;
@OperateHandlerMapping(type = Operation.Type.RunPlan_Add_Trip)
public void addTripPlan(Simulation simulation, RunPlanServiceConfigVO serviceConfig, AccountVO user) {
atsApiService.addTripPlan(simulation, serviceConfig, user);
}
@OperateHandlerMapping(type = Operation.Type.RunPlan_Delete_Trip)
public void deleteTripPlan(Simulation simulation, String serviceNumber,
String tripNumber, String stationCode) {
public void deleteTripPlan(Simulation simulation, String serviceNumber, String tripNumber) {
atsApiService.deleteTripPlan(simulation, serviceNumber, tripNumber);
}
}

View File

@ -643,6 +643,7 @@ public class GroupSimulationServiceImpl implements GroupSimulationService {
SchedulingPlanNewVO schedulingPlan = this.schedulingService
.querySchedulingPlanUserFirst(userId, templateId, SimulationConstants.getRunPlanDate());
this.simulationLifeCycleService.reloadRunPlan(simulation, runPlan, schedulingPlan);
simulation.getRepository().clearChangeTrips(); //清除掉之前的车次计划变化信息
}
@Override

View File

@ -28,6 +28,7 @@ import club.joylink.rtss.simulation.cbtc.script.ScriptBO;
import club.joylink.rtss.simulation.vo.SimulationInfoVO;
import club.joylink.rtss.vo.AccountVO;
import club.joylink.rtss.vo.client.fault.FaultRuleVO;
import club.joylink.rtss.vo.client.runplan.RunPlanTripVO;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
@ -39,6 +40,7 @@ import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
/**

View File

@ -13,8 +13,6 @@ import club.joylink.rtss.simulation.cbtc.communication.Joylink3DMessageService;
import club.joylink.rtss.simulation.cbtc.communication.vo.fault.DeviceFaultInfo;
import club.joylink.rtss.simulation.cbtc.competition.CompetitionAndScriptManager;
import club.joylink.rtss.simulation.cbtc.competition.ScriptExecuteService;
import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants;
import club.joylink.rtss.simulation.cbtc.constant.SimulationModule;
import club.joylink.rtss.simulation.cbtc.conversation.Conversation;
import club.joylink.rtss.simulation.cbtc.conversation.ConversationMessage;
import club.joylink.rtss.simulation.cbtc.data.plan.RealRun;
@ -28,8 +26,6 @@ import club.joylink.rtss.simulation.cbtc.device.real.modbustcp.SimulationRealDev
import club.joylink.rtss.simulation.cbtc.device.virtual.VRDeviceLogicLoop;
import club.joylink.rtss.simulation.cbtc.device.virtual.VRTrainRunningService;
import club.joylink.rtss.simulation.cbtc.event.*;
import club.joylink.rtss.simulation.cbtc.exception.SimulationException;
import club.joylink.rtss.simulation.cbtc.exception.SimulationExceptionType;
import club.joylink.rtss.simulation.cbtc.fault.FaultGenerator;
import club.joylink.rtss.simulation.cbtc.member.SimulationMember;
import club.joylink.rtss.simulation.cbtc.member.SimulationUser;
@ -40,6 +36,8 @@ 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.psl.PslStatus;
import club.joylink.rtss.vo.client.runplan.RunPlanEChartsDataVO;
import club.joylink.rtss.vo.client.runplan.RunPlanTripVO;
import club.joylink.rtss.vo.client.script.ScriptActionVO;
import club.joylink.rtss.vo.client.simulationv1.SimulationMemberMessageVO;
import club.joylink.rtss.vo.client.simulationv1.SimulationUserMessageVO;
@ -497,6 +495,12 @@ public class SimulationMainThread {
group, realRunRecordList);
this.stompMessageService.sendToUser(String.valueOf(event.getUserId()), allTrainRealRunRecord);
}
// 将车次计划变化信息同步给用户
List<RunPlanTripVO> changeTrips = simulation.getRepository().getChangeTrips();
if (!CollectionUtils.isEmpty(changeTrips)) {
SocketMessageVO<RunPlanEChartsDataVO> tripPlanChangeMessage = SocketMessageFactory.buildTripPlanChangeMessage(event.getGroup(), changeTrips);
this.stompMessageService.sendToUser(String.valueOf(event.getUserId()), tripPlanChangeMessage);
}
}
}
@ -849,4 +853,10 @@ public class SimulationMainThread {
SocketMessageVO<String> message = SocketMessageFactory.buildOrderPaySuccessMessage(event.getOrderCode());
this.stompMessageService.sendToUser(event.getUserId(), message);
}
@EventListener
public void handleTripPlanChangeEvent(SimulationTripPlanChangeEvent event) {
SocketMessageVO<RunPlanEChartsDataVO> message = SocketMessageFactory.buildTripPlanChangeMessage(event.getSimulation().getId(), event.getChangeTrips());
this.stompMessageService.sendToUser(event.getSimulation().getSimulationUserIds(), message);
}
}

View File

@ -56,103 +56,8 @@ public class RunPlanBuilder {
List<RunPlanTripVO> tripList = runPlan.getTripList();
if (!CollectionUtils.isEmpty(tripList)) {
tripList.forEach(runPlanTripVO -> {
TripPlan.TripPlanBuilder tripBuilder = TripPlan.builder();
tripBuilder.serviceNumber(runPlanTripVO.getServiceNumber())
.tripNumber(runPlanTripVO.getTripNumber())
.destinationCode(runPlanTripVO.getDestinationCode())
.right(runPlanTripVO.getRight())
.startTime(runPlanTripVO.getStartTime())
.endTime(runPlanTripVO.getEndTime());
MapElement start = deviceMap.get(runPlanTripVO.getStartSectionCode());
if (Objects.isNull(start) ||
!Objects.equals(MapElement.DeviceType.SECTION, start.getDeviceType())) {
errMsgList.add(String.format("计划车次[%s|%s|%s]起始区段[%s]数据不存在或不是区段",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode(),
runPlanTripVO.getStartSectionCode()));
} else {
tripBuilder.startSection((Section) start);
}
MapElement end = deviceMap.get(runPlanTripVO.getEndSectionCode());
if (Objects.isNull(end) ||
!Objects.equals(MapElement.DeviceType.SECTION, end.getDeviceType())) {
errMsgList.add(String.format("计划车次[%s|%s|%s]终点区段[%s]数据不存在或不是区段",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode(),
runPlanTripVO.getStartSectionCode()));
} else {
Section section = (Section) end;
tripBuilder.endSection(section);
}
boolean outbound = Objects.nonNull(runPlanTripVO.getIsOutbound()) ? runPlanTripVO.getIsOutbound() : false;
tripBuilder.outbound(outbound);
boolean inbound = Objects.nonNull(runPlanTripVO.getIsInbound()) ? runPlanTripVO.getIsInbound() : false;
tripBuilder.inbound(inbound);
boolean backup = Objects.nonNull(runPlanTripVO.getIsBackUp()) ? runPlanTripVO.getIsBackUp() : false;
tripBuilder.backup(backup);
boolean turnBack = Objects.nonNull(runPlanTripVO.getIsReentry()) ? runPlanTripVO.getIsReentry() : false;
tripBuilder.turnBack(turnBack);
// 车站到发时刻表
List<StationPlan> stationPlanList = new ArrayList<>();
tripBuilder.planList(stationPlanList);
List<RunPlanTripTimeVO> timeList = runPlanTripVO.getTimeList();
if (CollectionUtils.isEmpty(timeList)) {
errMsgList.add(String.format("计划车次[%s|%s|%s]没有车站到发时刻表",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode()));
} else {
timeList.forEach(runPlanTripTimeVO -> {
StationPlan.StationPlanBuilder builder = StationPlan.builder();
MapElement station = deviceMap.get(runPlanTripTimeVO.getStationCode());
if (Objects.isNull(station) ||
!Objects.equals(MapElement.DeviceType.STATION, station.getDeviceType())) {
errMsgList.add(String.format("计划车次[%s|%s|%s]车站到发时刻表车站[%s]数据不存在或不是车站",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode(),
runPlanTripTimeVO.getStationCode()));
} else {
builder.station((Station) station);
}
MapElement section = deviceMap.get(runPlanTripTimeVO.getSectionCode());
if (Objects.isNull(section) ||
!Objects.equals(MapElement.DeviceType.SECTION, section.getDeviceType())) {
errMsgList.add(String.format("计划车次[%s|%s|%s]车站到发时刻表区段[%s]数据不存在或不是区段",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode(),
runPlanTripTimeVO.getSectionCode()));
} else {
builder.section((Section) section);
}
LocalTime arrivalTime = runPlanTripTimeVO.getArrivalTime();
LocalTime departureTime = runPlanTripTimeVO.getDepartureTime();
if (Objects.isNull(arrivalTime) || Objects.isNull(departureTime)) {
errMsgList.add(String.format("计划车次[%s|%s|%s]车站到发时刻表计划到达时间和计划发车时间不能为空",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode()));
} else if (arrivalTime.isAfter(departureTime)) {
errMsgList.add(String.format("计划车次[%s|%s|%s]车站到发时刻表计划到达时间不能比计划发车时间晚",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode()));
} else {
builder.arriveTime(arrivalTime);
builder.leaveTime(departureTime);
int parkTime = departureTime.toSecondOfDay() - arrivalTime.toSecondOfDay();
if (parkTime <= 0) {
builder.park(false);
builder.parkTime(0);
} else {
builder.park(true);
builder.parkTime(parkTime);
}
}
StationPlan plan = builder.build();
stationPlanList.add(plan);
});
if (CollectionUtils.isEmpty(errMsgList)) {
// 排序
stationPlanList.sort(Comparator.comparing(StationPlan::getArriveTime));
}
TripPlan tripPlan = tripBuilder.build();
TripPlan tripPlan = buildTripPlan(deviceMap, errMsgList, runPlanTripVO);
if (tripPlan != null) {
List<TripPlan> tripPlanList = serverTripMap.get(tripPlan.getServiceNumber());
if (Objects.isNull(tripPlanList)) {
tripPlanList = new ArrayList<>();
@ -299,4 +204,106 @@ public class RunPlanBuilder {
}
return result;
}
public static TripPlan buildTripPlan(Map<String, ? extends MapElement> deviceMap, List<String> errMsgList, RunPlanTripVO runPlanTripVO) {
TripPlan.TripPlanBuilder tripBuilder = TripPlan.builder();
tripBuilder.serviceNumber(runPlanTripVO.getServiceNumber())
.tripNumber(runPlanTripVO.getTripNumber())
.destinationCode(runPlanTripVO.getDestinationCode())
.right(runPlanTripVO.getRight())
.startTime(runPlanTripVO.getStartTime())
.endTime(runPlanTripVO.getEndTime());
MapElement start = deviceMap.get(runPlanTripVO.getStartSectionCode());
if (Objects.isNull(start) ||
!Objects.equals(MapElement.DeviceType.SECTION, start.getDeviceType())) {
errMsgList.add(String.format("计划车次[%s|%s|%s]起始区段[%s]数据不存在或不是区段",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode(),
runPlanTripVO.getStartSectionCode()));
} else {
tripBuilder.startSection((Section) start);
}
MapElement end = deviceMap.get(runPlanTripVO.getEndSectionCode());
if (Objects.isNull(end) ||
!Objects.equals(MapElement.DeviceType.SECTION, end.getDeviceType())) {
errMsgList.add(String.format("计划车次[%s|%s|%s]终点区段[%s]数据不存在或不是区段",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode(),
runPlanTripVO.getStartSectionCode()));
} else {
Section section = (Section) end;
tripBuilder.endSection(section);
}
boolean outbound = Objects.nonNull(runPlanTripVO.getIsOutbound()) ? runPlanTripVO.getIsOutbound() : false;
tripBuilder.outbound(outbound);
boolean inbound = Objects.nonNull(runPlanTripVO.getIsInbound()) ? runPlanTripVO.getIsInbound() : false;
tripBuilder.inbound(inbound);
boolean backup = Objects.nonNull(runPlanTripVO.getIsBackUp()) ? runPlanTripVO.getIsBackUp() : false;
tripBuilder.backup(backup);
boolean turnBack = Objects.nonNull(runPlanTripVO.getIsReentry()) ? runPlanTripVO.getIsReentry() : false;
tripBuilder.turnBack(turnBack);
// 车站到发时刻表
List<StationPlan> stationPlanList = new ArrayList<>();
tripBuilder.planList(stationPlanList);
List<RunPlanTripTimeVO> timeList = runPlanTripVO.getTimeList();
if (CollectionUtils.isEmpty(timeList)) {
errMsgList.add(String.format("计划车次[%s|%s|%s]没有车站到发时刻表",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode()));
return null;
} else {
timeList.forEach(runPlanTripTimeVO -> {
StationPlan.StationPlanBuilder builder = StationPlan.builder();
MapElement station = deviceMap.get(runPlanTripTimeVO.getStationCode());
if (Objects.isNull(station) ||
!Objects.equals(MapElement.DeviceType.STATION, station.getDeviceType())) {
errMsgList.add(String.format("计划车次[%s|%s|%s]车站到发时刻表车站[%s]数据不存在或不是车站",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode(),
runPlanTripTimeVO.getStationCode()));
} else {
builder.station((Station) station);
}
MapElement section = deviceMap.get(runPlanTripTimeVO.getSectionCode());
if (Objects.isNull(section) ||
!Objects.equals(MapElement.DeviceType.SECTION, section.getDeviceType())) {
errMsgList.add(String.format("计划车次[%s|%s|%s]车站到发时刻表区段[%s]数据不存在或不是区段",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode(),
runPlanTripTimeVO.getSectionCode()));
} else {
builder.section((Section) section);
}
LocalTime arrivalTime = runPlanTripTimeVO.getArrivalTime();
LocalTime departureTime = runPlanTripTimeVO.getDepartureTime();
if (Objects.isNull(arrivalTime) || Objects.isNull(departureTime)) {
errMsgList.add(String.format("计划车次[%s|%s|%s]车站到发时刻表计划到达时间和计划发车时间不能为空",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode()));
} else if (arrivalTime.isAfter(departureTime)) {
errMsgList.add(String.format("计划车次[%s|%s|%s]车站到发时刻表计划到达时间不能比计划发车时间晚",
runPlanTripVO.getServiceNumber(), runPlanTripVO.getTripNumber(),
runPlanTripVO.getDestinationCode()));
} else {
builder.arriveTime(arrivalTime);
builder.leaveTime(departureTime);
int parkTime = departureTime.toSecondOfDay() - arrivalTime.toSecondOfDay();
if (parkTime <= 0) {
builder.park(false);
builder.parkTime(0);
} else {
builder.park(true);
builder.parkTime(parkTime);
}
}
StationPlan plan = builder.build();
stationPlanList.add(plan);
});
if (CollectionUtils.isEmpty(errMsgList)) {
// 排序
stationPlanList.sort(Comparator.comparing(StationPlan::getArriveTime));
}
return tripBuilder.build();
}
}
}

View File

@ -19,6 +19,7 @@ import club.joylink.rtss.simulation.cbtc.exception.SimulationException;
import club.joylink.rtss.simulation.cbtc.exception.SimulationExceptionType;
import club.joylink.rtss.util.StrUtils;
import club.joylink.rtss.vo.client.psl.PslStatus;
import club.joylink.rtss.vo.client.runplan.RunPlanTripVO;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
@ -205,7 +206,7 @@ public class SimulationDataRepository {
*/
private final Map<String, Set<Catenary>> catenaryMap = new ConcurrentHashMap<>();
private Map<Section,List<Responder>> sectionRespondersMap = new HashMap<>();
private Map<Section, List<Responder>> sectionRespondersMap = new HashMap<>();
/**
* ats用户设置的列车偏离操作信息
@ -213,6 +214,17 @@ public class SimulationDataRepository {
*/
private final Map<String, DeviationInfo> deviationInfoMap = new ConcurrentHashMap<>();
/** 加线、抽线的计划 */
private List<RunPlanTripVO> changeTrips = new CopyOnWriteArrayList<>();
public void addChangeTrips(Collection<RunPlanTripVO> trips) {
this.changeTrips.addAll(trips);
}
public void clearChangeTrips() {
this.changeTrips.clear();
}
public void addDeviationInfo(DeviationInfo deviationInfo) {
deviationInfoMap.put(deviationInfo.getStartStand().getCode(), deviationInfo);
deviationInfoMap.put(deviationInfo.getEndStand().getCode(), deviationInfo);
@ -314,6 +326,7 @@ public class SimulationDataRepository {
/**
* 根据设备集中站的code获取设备集中站下的道岔
*
* @param code
* @return
*/
@ -458,6 +471,7 @@ public class SimulationDataRepository {
/**
* 查找路径
*
* @param start
* @param end
* @return
@ -468,6 +482,7 @@ public class SimulationDataRepository {
/**
* 根据终到区段查找路径
*
* @param start
* @return
*/
@ -483,6 +498,7 @@ public class SimulationDataRepository {
/**
* 根据终到区段查找路径
*
* @param end
* @return
*/
@ -702,6 +718,18 @@ public class SimulationDataRepository {
this.deviceInfoMap.clear();
this.trainHmiMap.clear();
this.tdtStatusMap.clear();
// 运行图
this.changeTrips.clear();
serviceTripsMap.forEach((k, v) -> {
for (Iterator<TripPlan> iterator = v.iterator(); iterator.hasNext(); ) {
TripPlan tripPlan = iterator.next();
if (tripPlan.isAdd()) {
iterator.remove();
} else if (tripPlan.isInvalid()) {
tripPlan.setInvalid(false);
}
}
});
}
/**
@ -759,7 +787,7 @@ public class SimulationDataRepository {
// tripPlans.sort(Comparator.comparing(TripPlan::getStartTime));
TripPlan next = null;
for (int i = 0; i < tripPlans.size(); i++) {
if (Objects.equals(tripPlans.get(i).getTripNumber(), tripNumber) && i+1<tripPlans.size()) {
if (Objects.equals(tripPlans.get(i).getTripNumber(), tripNumber) && i + 1 < tripPlans.size()) {
next = tripPlans.get(i + 1);
break;
}
@ -825,6 +853,7 @@ public class SimulationDataRepository {
/**
* 此方法只能用于计划车次号唯一的线路比如西门子风格的运行计划
*
* @param tripNumber
* @return
*/
@ -1075,6 +1104,7 @@ public class SimulationDataRepository {
/**
* 查询指定时间范围内的出库计划
*
* @param start
* @param end
* @return
@ -1138,4 +1168,35 @@ public class SimulationDataRepository {
}
return null;
}
public List<TripPlan> invalidPlanFrom(String serviceNumber, String tripNumber) {
List<TripPlan> invalidList = new ArrayList<>();
TripPlan tripPlan = findTripPlan(serviceNumber, tripNumber);
if (tripPlan != null) {
TrainInfo trainInfo = findSupervisedTrainByTrip(serviceNumber, tripNumber);
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED
.assertNull(trainInfo, String.format("车次计划[%s-%s]已在运行", serviceNumber, tripNumber));
invalidList.add(tripPlan);
List<TripPlan> tripPlans = serviceTripsMap.get(serviceNumber);
for (TripPlan plan : tripPlans) {
if (plan.getStartTime().isAfter(tripPlan.getStartTime())) {
trainInfo = findSupervisedTrainByTrip(plan.getServiceNumber(), plan.getTripNumber());
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED
.assertNull(trainInfo, String.format("车次计划[%s-%s]已在运行", plan.getServiceNumber(), plan.getTripNumber()));
invalidList.add(plan);
}
}
invalidList.forEach(plan -> plan.setInvalid(true));
}
return invalidList;
}
public void addTrip(TripPlan tripPlan) {
List<TripPlan> trips = this.serviceTripsMap.get(tripPlan.getServiceNumber());
if (trips == null) {
trips = new ArrayList<>();
serviceTripsMap.put(tripPlan.getServiceNumber(), trips);
}
trips.add(tripPlan);
}
}

View File

@ -5,6 +5,7 @@ import club.joylink.rtss.simulation.cbtc.data.map.Stand;
import club.joylink.rtss.simulation.cbtc.data.map.Station;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalTime;
import java.util.ArrayList;
@ -63,6 +64,14 @@ public class TripPlan {
/** 是否发车 */
private boolean departure;
/** 失效(抽线) */
@Setter
private boolean invalid;
/** 加线 */
@Setter
private boolean add;
/**
* 获取正线车站运行计划起始时间
* @return

View File

@ -0,0 +1,19 @@
package club.joylink.rtss.simulation.cbtc.event;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.vo.client.runplan.RunPlanTripVO;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class SimulationTripPlanChangeEvent extends AbstractSimulationEvent{
List<RunPlanTripVO> changeTrips;
public SimulationTripPlanChangeEvent(Object source, Simulation simulation, List<RunPlanTripVO> changeTrips) {
super(source, simulation);
this.changeTrips = changeTrips;
}
}

View File

@ -65,6 +65,8 @@ public enum WebSocketMessageType {
Simulation_Reset,
/** 仿真-仿真运行计划重新加载消息 */
Simulation_Run_Plan_Reload,
/** 车次计划变化消息 */
Simulation_Trip_Plan_Change,
/** 仿真-仿真场景重新加载 */
Simulation_Scenes_Reload,
/** 仿真-仿真成员改变消息 */

View File

@ -14,6 +14,8 @@ import club.joylink.rtss.vo.client.SocketMessageVO;
import club.joylink.rtss.vo.client.WebSocketMessageType;
import club.joylink.rtss.vo.client.passenger.PassengerFlowMessage2TD;
import club.joylink.rtss.vo.client.psl.PslStatus;
import club.joylink.rtss.vo.client.runplan.RunPlanEChartsDataVO;
import club.joylink.rtss.vo.client.runplan.RunPlanTripVO;
import club.joylink.rtss.vo.client.script.ScriptActionVO;
import club.joylink.rtss.vo.client.simulationv1.SimulationMemberMessageVO;
import club.joylink.rtss.vo.client.simulationv1.SimulationUserMessageVO;
@ -89,6 +91,7 @@ public class SocketMessageFactory {
case Simulation_Control_Pause:
case Simulation_Permission_Over:
case Simulation_Run_Plan_Reload:
case Simulation_Trip_Plan_Change:
case Simulation_Scenes_Reload:
case Simulation_Quest_Finish:
case Simulation_PlayBack_Finish:
@ -366,4 +369,12 @@ public class SocketMessageFactory {
public static SocketMessageVO<String> buildOrderPaySuccessMessage(String orderCode) {
return build(WebSocketMessageType.Order_Pay_Result, null, orderCode);
}
/**
* 车次计划变化
*/
public static SocketMessageVO<RunPlanEChartsDataVO> buildTripPlanChangeMessage(String simulationId, List<RunPlanTripVO> changeTrips) {
RunPlanEChartsDataVO eChartsDataVO = new RunPlanEChartsDataVO(changeTrips);
return build(WebSocketMessageType.Simulation_Trip_Plan_Change, simulationId, eChartsDataVO);
}
}

View File

@ -103,6 +103,12 @@ public class RunPlanEChartsDataVO {
List<StationTime> stationTimeList;
Boolean add;
Boolean firstInvalid;
Boolean invalid;
TripNumberData(RunPlanTripVO runPlanTripVO) {
this.startSectionCode = runPlanTripVO.getStartSectionCode();
this.startSecondTime = runPlanTripVO.getStartTime().toSecondOfDay();
@ -117,6 +123,9 @@ public class RunPlanEChartsDataVO {
this.outbound = runPlanTripVO.getIsOutbound();
this.backup = runPlanTripVO.getIsBackUp();
this.stationTimeList = new ArrayList<>();
this.add = runPlanTripVO.isAdd() ? true : null;
this.firstInvalid = runPlanTripVO.isFirstInvalid() ? true : null;
this.invalid = runPlanTripVO.isInvalid() ? true : null;
}
}

View File

@ -106,6 +106,12 @@ public class RunPlanTripVO {
@JsonProperty(value = "n")
private Boolean right;
private boolean add;
private boolean firstInvalid;
private boolean invalid;
public RunPlanTripVO(RunPlanImport runPlanImport) {
this.serviceNumber = runPlanImport.getServiceNumber();
this.tripNumber = runPlanImport.getTripNumber();

View File

@ -3,6 +3,7 @@ package club.joylink.rtss.vo.client.runplan;
import club.joylink.rtss.entity.RunPlanDaily;
import club.joylink.rtss.entity.RunPlanDraft;
import club.joylink.rtss.entity.RunPlanTemplate;
import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;
import club.joylink.rtss.util.JsonUtils;
import club.joylink.rtss.vo.client.validGroup.RunPlanCreateCheck;
import club.joylink.rtss.vo.client.validGroup.RunPlanNameCheck;
@ -20,10 +21,9 @@ import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;
@Getter
@Setter
@ -213,28 +213,30 @@ public class RunPlanVO {
return vo;
}
// public void setStationDiagramList(List<RunPlanStationTimeVO> stationDiagramList) {
// stationDiagramList.sort(Comparator.comparing(RunPlanStationTimeVO::getArriveTime));
// this.stationDiagramList = stationDiagramList;
// if(!CollectionUtils.isEmpty(stationDiagramList)) {
// Set<String> serverNoList = new HashSet<>();
// Set<String> trainNoList = new HashSet<>();
// Map<String, Set<String>> serverNoTrainNoRelMap = new HashMap<>();
// Map<String, List<RunPlanStationTimeVO>> serverStationMap = new HashMap<>();
// Map<String, List<RunPlanStationTimeVO>> trainStationMap = new HashMap<>();
// stationDiagramList.forEach(diagram -> {
// serverNoList.add(diagram.getServiceNumber());
// trainNoList.add(diagram.getTripNumber());
// Set<String> trainNoSet = serverNoTrainNoRelMap.computeIfAbsent(diagram.getServiceNumber(), k -> new HashSet<>());
// trainNoSet.add(diagram.getTripNumber());
// List<RunPlanStationTimeVO> tsList = trainStationMap.computeIfAbsent(diagram.getTripNumber(), k -> new ArrayList<>());
// tsList.add(diagram);
// List<RunPlanStationTimeVO> ssList = serverStationMap.computeIfAbsent(diagram.getServiceNumber(), k -> new ArrayList<>());
// ssList.add(diagram);
// });
// this.serverNoList = serverNoList;
// this.trainNoList = trainNoList;
// this.serverStationMap = serverStationMap;
// }
// }
public List<RunPlanTripVO> invalidTripPlan(List<TripPlan> removeList) {
TripPlan first = removeList.get(0);
String serviceNumber = first.getServiceNumber();
LocalTime startTime = first.getStartTime();
return this.tripList.stream()
.filter(plan -> {
if (!plan.getServiceNumber().equals(serviceNumber))
return false;
if (plan.getStartTime().isBefore(startTime))
return false;
if (plan.isInvalid() && !plan.isFirstInvalid())
return false;
return true;
})
.peek(plan -> {
if (!plan.getStartTime().isBefore(startTime)) {
if (plan.isFirstInvalid())
plan.setFirstInvalid(false);
plan.setInvalid(true);
if (plan.getTripNumber().equals(first.getTripNumber())) {
plan.setFirstInvalid(true);
}
}
})
.collect(Collectors.toList());
}
}

View File

@ -23,4 +23,8 @@ public class RunPlanRoutingQueryVO extends PageQueryVO {
* 终到站台区段code
*/
private String endSectionCode;
/**
* 目的地码
*/
private String destinationCode;
}