This commit is contained in:
DU 2020-12-09 16:52:38 +08:00
commit 0590008813
35 changed files with 591 additions and 273 deletions

2
sql/20201208.sql Normal file
View File

@ -0,0 +1,2 @@
alter table user_simulation_stats modify role varchar(32) null comment '用户角色';

View File

@ -107,8 +107,9 @@ public class CompanyService implements ICompanyService {
@Override @Override
public void deleteUserCompanyRel(Long userId) { public void deleteUserCompanyRel(Long userId) {
UserCompanyRel ucr = getUserCompanyRelEntity(userId); UserCompanyRelExample example = new UserCompanyRelExample();
userCompanyRelDAO.deleteByPrimaryKey(ucr.getId()); example.createCriteria().andUserIdEqualTo(userId);
userCompanyRelDAO.deleteByExample(example);
} }
@Override @Override

View File

@ -536,6 +536,13 @@ public class ExamService implements IExamService{
// } // }
} }
@Override
public List<ExamDefinition> findEntities(Long lessonId) {
ExamDefinitionExample example = new ExamDefinitionExample();
example.createCriteria().andLessonIdEqualTo(lessonId);
return examDefinitionDAO.selectByExample(example);
}
private List<ExamDefinition> findEntityByLessonIdList(ArrayList<Long> lessonIdList) { private List<ExamDefinition> findEntityByLessonIdList(ArrayList<Long> lessonIdList) {
ExamDefinitionExample example = new ExamDefinitionExample(); ExamDefinitionExample example = new ExamDefinitionExample();
example.createCriteria().andLessonIdIn(lessonIdList); example.createCriteria().andLessonIdIn(lessonIdList);

View File

@ -1,7 +1,11 @@
package club.joylink.rtss.services; package club.joylink.rtss.services;
import club.joylink.rtss.entity.ExamDefinition;
import club.joylink.rtss.vo.UserVO; import club.joylink.rtss.vo.UserVO;
import club.joylink.rtss.vo.client.*; import club.joylink.rtss.vo.client.ExamDefinitionQueryVO;
import club.joylink.rtss.vo.client.ExamDefinitionVO;
import club.joylink.rtss.vo.client.ExamsLessonVO;
import club.joylink.rtss.vo.client.PageVO;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -26,14 +30,11 @@ public interface IExamService {
/** /**
* 查询课程所属产品下有实训的实训类型 * 查询课程所属产品下有实训的实训类型
* @param lessonId
* @return
*/ */
List<String> queryTrainingTypes(Long lessonId); List<String> queryTrainingTypes(Long lessonId);
/** /**
* 查询试题定义的详细信息 * 查询试题定义的详细信息
* @param examId
*/ */
ExamDefinitionVO queryExamInfo(Long examId); ExamDefinitionVO queryExamInfo(Long examId);
@ -59,32 +60,28 @@ public interface IExamService {
/** /**
* 根据课程和实训类型查询实训数量 * 根据课程和实训类型查询实训数量
* @param lessonId
* @param trainingType
* @return
*/ */
Long queryTrainingNum(Long lessonId, String trainingType, String operateType); Long queryTrainingNum(Long lessonId, String trainingType, String operateType);
/** /**
* 试题上线 * 试题上线
* @param id
* @param userVO
*/ */
void onLine(Long id, UserVO userVO); void onLine(Long id, UserVO userVO);
/** /**
* 试题下线 * 试题下线
* @param id
* @param userVO
*/ */
void offLine(Long id, UserVO userVO); void offLine(Long id, UserVO userVO);
/** /**
* 更新试题 * 更新试题
* @param id
* @param examDefinitionVO
*/ */
void update(Long id, ExamDefinitionVO examDefinitionVO); void update(Long id, ExamDefinitionVO examDefinitionVO);
void copy(Map<Long, Long> lessonRelationMap, UserVO user); void copy(Map<Long, Long> lessonRelationMap, UserVO user);
/**
* 根据课程id查询考试
*/
List<ExamDefinition> findEntities(Long lessonId);
} }

View File

@ -4,8 +4,6 @@ package club.joylink.rtss.services;
import club.joylink.rtss.vo.UserVO; import club.joylink.rtss.vo.UserVO;
import club.joylink.rtss.vo.client.*; import club.joylink.rtss.vo.client.*;
import java.util.List;
public interface IUserExamService { public interface IUserExamService {
/** /**
@ -46,18 +44,6 @@ public interface IUserExamService {
*/ */
void abandon(long id, UserVO user); void abandon(long id, UserVO user);
/**
* 根据实训id删除用户考试记录
* @param trainingId
*/
void deleteUserExamRecordByTrainingId(Long trainingId);
/**
* 根据实训id列表删除用户考试记录
* @param trainingIdList
*/
void deleteUserExamRecordsByTrainingIdList(List<Long> trainingIdList);
/** /**
* 分页查询用户考试数据 * 分页查询用户考试数据
* @param queryVO * @param queryVO

View File

@ -619,7 +619,7 @@ public class LessonService implements ILessonService {
if (Objects.nonNull(existedDefaultLesson)) { if (Objects.nonNull(existedDefaultLesson)) {
lesson.setId(existedDefaultLesson.getId()); lesson.setId(existedDefaultLesson.getId());
lessonDAO.updateByPrimaryKey(lesson); lessonDAO.updateByPrimaryKey(lesson);
//存在默认课程删除旧版本章节考试及关联实训数据 //存在默认课程删除旧版本章节章节关联的实训
LsLessonVersionExample versionExample = new LsLessonVersionExample(); LsLessonVersionExample versionExample = new LsLessonVersionExample();
versionExample.createCriteria().andLessonIdEqualTo(existedDefaultLesson.getId()); versionExample.createCriteria().andLessonIdEqualTo(existedDefaultLesson.getId());
lessonVersionDAO.deleteByExample(versionExample); lessonVersionDAO.deleteByExample(versionExample);
@ -632,21 +632,21 @@ public class LessonService implements ILessonService {
chapterExample.createCriteria().andLessonIdEqualTo(existedDefaultLesson.getId()); chapterExample.createCriteria().andLessonIdEqualTo(existedDefaultLesson.getId());
lessonChapterDAO.deleteByExample(chapterExample); lessonChapterDAO.deleteByExample(chapterExample);
ExamDefinitionExample examDefinitionExample = new ExamDefinitionExample(); // ExamDefinitionExample examDefinitionExample = new ExamDefinitionExample();
examDefinitionExample.createCriteria().andLessonIdEqualTo(existedDefaultLesson.getId()); // examDefinitionExample.createCriteria().andLessonIdEqualTo(existedDefaultLesson.getId());
List<ExamDefinition> examDefinitions = examDefinitionDAO.selectByExample(examDefinitionExample); // List<ExamDefinition> examDefinitions = examDefinitionDAO.selectByExample(examDefinitionExample);
if (!CollectionUtils.isEmpty(examDefinitions)) { // if (!CollectionUtils.isEmpty(examDefinitions)) {
List<Long> list = examDefinitions.stream().map(ExamDefinition::getId).collect(Collectors.toList()); // List<Long> list = examDefinitions.stream().map(ExamDefinition::getId).collect(Collectors.toList());
ExamDefinitionRulesExample rulesExample = new ExamDefinitionRulesExample(); // ExamDefinitionRulesExample rulesExample = new ExamDefinitionRulesExample();
rulesExample.createCriteria().andExamIdIn(list); // rulesExample.createCriteria().andExamIdIn(list);
definitionRulesDAO.deleteByExample(rulesExample); // definitionRulesDAO.deleteByExample(rulesExample);
examDefinitionDAO.deleteByExample(examDefinitionExample); // examDefinitionDAO.deleteByExample(examDefinitionExample);
} // }
} else { } else {
lessonDAO.insert(lesson); lessonDAO.insert(lesson);
} }
//版本0.0 //课程版本0.0
LsLessonVersion lessonVersion = new LsLessonVersion(); LsLessonVersion lessonVersion = new LsLessonVersion();
lessonVersion.setLessonId(lesson.getId()); lessonVersion.setLessonId(lesson.getId());
lessonVersion.setCreatorId(lesson.getCreatorId()); lessonVersion.setCreatorId(lesson.getCreatorId());
@ -654,6 +654,7 @@ public class LessonService implements ILessonService {
lessonVersion.setVersion(BusinessConsts.Lesson.Version.originalVersion); lessonVersion.setVersion(BusinessConsts.Lesson.Version.originalVersion);
lessonVersionDAO.insert(lessonVersion); lessonVersionDAO.insert(lessonVersion);
//生成课程的章节
List<Training> examTrainings = new ArrayList<>(20); List<Training> examTrainings = new ArrayList<>(20);
int orderNum = 1; int orderNum = 1;
Random random = new Random(); Random random = new Random();
@ -687,49 +688,51 @@ public class LessonService implements ILessonService {
} }
}); });
} }
//试卷定义 List<ExamDefinition> exams = iExamService.findEntities(lesson.getId());
if (CollectionUtils.isEmpty(examTrainings)) { if (CollectionUtils.isEmpty(exams)) {
return; //试卷定义
} if (CollectionUtils.isEmpty(examTrainings)) {
ExamDefinition examDefinition = new ExamDefinition(); return;
examDefinition.setLessonId(lesson.getId()); }
examDefinition.setName(lesson.getName() + "试卷"); ExamDefinition examDefinition = new ExamDefinition();
examDefinition.setDuration(1800); examDefinition.setLessonId(lesson.getId());
examDefinition.setCreatorId(userVO.getId()); examDefinition.setName(lesson.getName() + "试卷");
examDefinition.setCreateTime(LocalDateTime.now()); examDefinition.setDuration(1800);
examDefinition.setRemarks(examDefinition.getName() + "-默认试卷"); examDefinition.setCreatorId(userVO.getId());
examDefinition.setStatus("1"); examDefinition.setCreateTime(LocalDateTime.now());
examDefinition.setTrial(true); examDefinition.setRemarks(examDefinition.getName() + "-默认试卷");
//试卷规则 取20道题每中实训类型取一道 examDefinition.setStatus("1");
if (examTrainings.size() < 20) { examDefinition.setTrial(true);
examDefinition.setFullPoint(examTrainings.size() * 5); //试卷规则 取20道题每中实训类型取一道
examDefinition.setPassingPoint(Double.valueOf(examDefinition.getFullPoint() * 0.6).intValue()); if (examTrainings.size() < 20) {
examDefinitionDAO.insert(examDefinition); examDefinition.setFullPoint(examTrainings.size() * 5);
examTrainings.forEach(training -> { examDefinition.setPassingPoint(Double.valueOf(examDefinition.getFullPoint() * 0.6).intValue());
ExamDefinitionRules examRules = new ExamDefinitionRules(); examDefinitionDAO.insert(examDefinition);
examRules.setExamId(examDefinition.getId()); examTrainings.forEach(training -> {
examRules.setNum(1); ExamDefinitionRules examRules = new ExamDefinitionRules();
examRules.setPoint(5); examRules.setExamId(examDefinition.getId());
examRules.setTrainingType(training.getType()); examRules.setNum(1);
examRules.setOperateType(training.getOperateType()); examRules.setPoint(5);
definitionRulesDAO.insert(examRules); examRules.setTrainingType(training.getType());
}); examRules.setOperateType(training.getOperateType());
definitionRulesDAO.insert(examRules);
} else { });
examDefinition.setFullPoint(100); } else {
examDefinition.setPassingPoint(60); examDefinition.setFullPoint(100);
examDefinitionDAO.insert(examDefinition); examDefinition.setPassingPoint(60);
int i = 1; examDefinitionDAO.insert(examDefinition);
do { int i = 1;
ExamDefinitionRules examRules = new ExamDefinitionRules(); do {
examRules.setExamId(examDefinition.getId()); ExamDefinitionRules examRules = new ExamDefinitionRules();
examRules.setNum(1); examRules.setExamId(examDefinition.getId());
examRules.setPoint(5); examRules.setNum(1);
Training training = examTrainings.remove(random.nextInt(examTrainings.size())); examRules.setPoint(5);
examRules.setTrainingType(training.getType()); Training training = examTrainings.remove(random.nextInt(examTrainings.size()));
examRules.setOperateType(training.getOperateType()); examRules.setTrainingType(training.getType());
definitionRulesDAO.insert(examRules); examRules.setOperateType(training.getOperateType());
} while (i++ < 20); definitionRulesDAO.insert(examRules);
} while (i++ < 20);
}
} }
} }
} }

View File

@ -15,7 +15,6 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.time.Duration; import java.time.Duration;
@ -234,26 +233,6 @@ public class UserExamService implements IUserExamService {
this.userExamMapper.updateByPrimaryKey(userExam); this.userExamMapper.updateByPrimaryKey(userExam);
} }
@Override
public void deleteUserExamRecordByTrainingId(Long trainingId) {
UserExamQuestionsExample example = new UserExamQuestionsExample();
example.createCriteria().andTrainingIdEqualTo(trainingId);
List<UserExamQuestions> userExamQuestions = this.userExamQuestionsMapper.selectByExample(example);
if (!CollectionUtils.isEmpty(userExamQuestions)) {
List<Long> userExamIdList = userExamQuestions.stream().mapToLong(UserExamQuestions::getUserExamId)
.distinct().boxed().collect(Collectors.toList());
UserExamExample examExample = new UserExamExample();
examExample.createCriteria().andIdIn(userExamIdList);
List<UserExam> userExams = this.userExamMapper.selectByExample(examExample);
if (!CollectionUtils.isEmpty(userExams)) {
for (UserExam userExam : userExams) {
this.deleteUserExam(userExam);
}
}
}
}
/** /**
* 删除用户考试 * 删除用户考试
* *
@ -269,16 +248,6 @@ public class UserExamService implements IUserExamService {
this.userExamMapper.deleteByPrimaryKey(userExam.getId()); this.userExamMapper.deleteByPrimaryKey(userExam.getId());
} }
@Override
public void deleteUserExamRecordsByTrainingIdList(List<Long> trainingIdList) {
UserExamQuestionsExample example = new UserExamQuestionsExample();
example.createCriteria().andTrainingIdIn(trainingIdList);
List<Long> userExamIds = this.userExamQuestionsMapper.selectUserExamIdsByExample(example);
if (!CollectionUtils.isEmpty(userExamIds)) {
this.deleteUserExamByIds(userExamIds);
}
}
private void deleteUserExamByIds(List<Long> userExamIds) { private void deleteUserExamByIds(List<Long> userExamIds) {
// 根据用户考试记录id删除用户考试题目 // 根据用户考试记录id删除用户考试题目
UserExamQuestionsExample questionsExample = new UserExamQuestionsExample(); UserExamQuestionsExample questionsExample = new UserExamQuestionsExample();

View File

@ -36,7 +36,7 @@ public class DraftMapCiDataGeneratorImpl implements DraftMapCiDataGenerator {
MapVO mapVO = this.draftMapService.getDraftMapData(mapId); MapVO mapVO = this.draftMapService.getDraftMapData(mapId);
SimulationBuilder.SimulationDeviceBuildResult buildResult = SimulationBuilder.checkAndBuildBasicMapData(mapVO); SimulationBuilder.SimulationDeviceBuildResult buildResult = SimulationBuilder.checkAndBuildBasicMapData(mapVO);
BusinessExceptionAssertEnum.DATA_ERROR.assertCollectionEmpty(buildResult.getErrMsgList(), BusinessExceptionAssertEnum.DATA_ERROR.assertCollectionEmpty(buildResult.getErrMsgList(),
String.format("地图基础数据有错误")); String.format("地图基础数据有错误: %s", JsonUtils.writeValueAsString(buildResult.getErrMsgList())));
MapCiGenerateConfig generateConfig = mapVO.getGraphDataNew().getGenerateConfig(); MapCiGenerateConfig generateConfig = mapVO.getGraphDataNew().getGenerateConfig();
Map<String, MapElement> deviceMap = buildResult.getDeviceMap(); Map<String, MapElement> deviceMap = buildResult.getDeviceMap();
// 联锁关系数据生成 // 联锁关系数据生成

View File

@ -1,6 +1,7 @@
package club.joylink.rtss.services.script; package club.joylink.rtss.services.script;
import club.joylink.rtss.services.script.IScriptSimulationService; import club.joylink.rtss.entity.ScriptDraftWithBLOBs;
import club.joylink.rtss.services.IScriptDraftService;
import club.joylink.rtss.simulation.cbtc.ATS.ATSMessageCollectAndDispatcher; import club.joylink.rtss.simulation.cbtc.ATS.ATSMessageCollectAndDispatcher;
import club.joylink.rtss.simulation.cbtc.ATS.operation.Operation; import club.joylink.rtss.simulation.cbtc.ATS.operation.Operation;
import club.joylink.rtss.simulation.cbtc.GroupSimulationCache; import club.joylink.rtss.simulation.cbtc.GroupSimulationCache;
@ -22,9 +23,6 @@ import club.joylink.rtss.simulation.cbtc.member.SimulationMember;
import club.joylink.rtss.simulation.cbtc.robot.RobotLogicLoop; import club.joylink.rtss.simulation.cbtc.robot.RobotLogicLoop;
import club.joylink.rtss.simulation.cbtc.script.ScriptActionBO; import club.joylink.rtss.simulation.cbtc.script.ScriptActionBO;
import club.joylink.rtss.simulation.cbtc.script.ScriptBO; import club.joylink.rtss.simulation.cbtc.script.ScriptBO;
import club.joylink.rtss.entity.ScriptDraftWithBLOBs;
import club.joylink.rtss.services.IScriptDraftService;
import club.joylink.rtss.services.script.IScriptService;
import club.joylink.rtss.vo.LoginUserInfoVO; import club.joylink.rtss.vo.LoginUserInfoVO;
import club.joylink.rtss.vo.UserVO; import club.joylink.rtss.vo.UserVO;
import club.joylink.rtss.vo.client.SocketMessageVO; import club.joylink.rtss.vo.client.SocketMessageVO;
@ -36,11 +34,11 @@ import club.joylink.rtss.vo.client.script.ScriptActionVO;
import club.joylink.rtss.vo.client.script.ScriptVO; import club.joylink.rtss.vo.client.script.ScriptVO;
import club.joylink.rtss.vo.client.simulationv1.SimulationMemberVO; import club.joylink.rtss.vo.client.simulationv1.SimulationMemberVO;
import club.joylink.rtss.websocket.StompMessageService; import club.joylink.rtss.websocket.StompMessageService;
import org.springframework.context.event.EventListener;
import org.springframework.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -195,7 +193,7 @@ public class ScriptSimulationService implements IScriptSimulationService {
} }
// 构建一个仿真 // 构建一个仿真
Simulation simulation = this.groupSimulationService.create(loginUserInfoVO, draftScript.getMapId(), null, Simulation simulation = this.groupSimulationService.create(loginUserInfoVO, draftScript.getMapId(), null,
Simulation.FunctionalType.SIMULATION); Simulation.FunctionalType.SCRIPT_PREVIEW);
loadDraftScript(simulation, draftScriptId); loadDraftScript(simulation, draftScriptId);
return simulation.getGroup(); return simulation.getGroup();
} }

View File

@ -500,8 +500,8 @@ public class TrainingV1Service implements ITrainingV1Service {
// 删除实训=章节关系 // 删除实训=章节关系
this.iLessonDraftService.deleteChapterRelByTrainingIdList(ids); this.iLessonDraftService.deleteChapterRelByTrainingIdList(ids);
this.iLessonService.deleteChapterRelByTrainingIdList(ids); this.iLessonService.deleteChapterRelByTrainingIdList(ids);
// 删除用户考试记录 // // 删除用户考试记录
this.iUserExamService.deleteUserExamRecordsByTrainingIdList(ids); // this.iUserExamService.deleteUserExamRecordsByTrainingIdList(ids);
// 删除用户实训记录 // 删除用户实训记录
this.deleteUserTrainingRecordByTrainingIds(ids); this.deleteUserTrainingRecordByTrainingIds(ids);
// 删除实训数据 // 删除实训数据
@ -591,8 +591,8 @@ public class TrainingV1Service implements ITrainingV1Service {
this.iLessonService.deleteChapterRelByTrainingId(training.getId()); this.iLessonService.deleteChapterRelByTrainingId(training.getId());
// 删除用户实训记录 // 删除用户实训记录
this.deleteUserTrainingRecordByTrainingId(training.getId()); this.deleteUserTrainingRecordByTrainingId(training.getId());
// 删除用户考试 // // 删除用户考试
this.iUserExamService.deleteUserExamRecordByTrainingId(training.getId()); // this.iUserExamService.deleteUserExamRecordByTrainingId(training.getId());
// 删除实训状态/步骤 // 删除实训状态/步骤
this.clear(training.getId()); this.clear(training.getId());

View File

@ -16,12 +16,11 @@ import org.springframework.stereotype.Service;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
public class UserSimulationStatStatService implements IUserSimulationStatService { public class UserSimulationStatService implements IUserSimulationStatService {
@Autowired @Autowired
private UserSimulationStatsDAO userSimulationStatsDAO; private UserSimulationStatsDAO userSimulationStatsDAO;

View File

@ -54,7 +54,7 @@ public class ZCLogicLoop {
} else if (RunLevel.CBTC.equals(defaultRunLevel)) { } else if (RunLevel.CBTC.equals(defaultRunLevel)) {
//更新ITC ma //更新ITC ma
Float distance2NextSignal = train.calculateDistance2NextNormalOpenSignal(); Float distance2NextSignal = train.calculateDistance2NextNormalOpenSignal();
if (distance2NextSignal != null && distance2NextSignal <= 100) { if (distance2NextSignal != null && distance2NextSignal <= 5) {
this.calculateMAOfITC(simulation, train, trainList); this.calculateMAOfITC(simulation, train, trainList);
} }
//更新CBTC ma //更新CBTC ma
@ -105,6 +105,17 @@ public class ZCLogicLoop {
this.groundAtpApiService.handleTrainStopMessage(simulation, trainStopMessage); this.groundAtpApiService.handleTrainStopMessage(simulation, trainStopMessage);
} }
private void calculateMaOfCtc(Simulation simulation, VirtualRealityTrain train,
List<VirtualRealityTrain> trainList) {
// 查找移动授权终端列表
List<MovementAuthority.End> endList = this.findCtcMaEnd(simulation, train, trainList);
}
private List<MovementAuthority.End> findCtcMaEnd(Simulation simulation, VirtualRealityTrain train,
List<VirtualRealityTrain> trainList) {
return null;
}
private void calculateMAOfCBTC(Simulation simulation, VirtualRealityTrain train, private void calculateMAOfCBTC(Simulation simulation, VirtualRealityTrain train,
List<VirtualRealityTrain> trainList) { List<VirtualRealityTrain> trainList) {
// 查找移动授权终端列表 // 查找移动授权终端列表

View File

@ -275,8 +275,10 @@ public class AtsPlanService {
//找不到计划不处理 //找不到计划不处理
return; return;
} }
//有计划折返 if (simulation.getSystemTime().toLocalTime().plusSeconds(60).isAfter(nextTripPlan.getStartTime())) {
this.turnBackTrain(simulation, train, nextTripPlan); //有计划折返且到发车时间
this.turnBackTrain(simulation, train, nextTripPlan);
}
} }
/** /**
@ -621,23 +623,20 @@ public class AtsPlanService {
// 更新追踪列车到站状态 // 更新追踪列车到站状态
StationPlan stationPlan = tripPlan.queryStationPlanByStation(station); StationPlan stationPlan = tripPlan.queryStationPlanByStation(station);
if (parkTime < 0) { if (parkTime < 0) {
parkTime = stationPlan.getLeaveTime().toSecondOfDay() - systemTime.toSecondOfDay();
int planParkTime = stationPlan.getParkTime();
if (this.checkIfFrontTurnBack(simulation, train, section, tripPlan, stationPlan)) { if (this.checkIfFrontTurnBack(simulation, train, section, tripPlan, stationPlan)) {
//是站台折返车 //是站台折返车
//如果停车时间为0 ,则取后一个车次计划的首站发车时间 //如果停车时间为0 ,则取后一个车次计划的首站发车时间
TripPlan nextTripPlan = repository.queryServiceNextTripPlan(tripPlan.getServiceNumber(), tripPlan.getTripNumber()); TripPlan nextTripPlan = repository.queryServiceNextTripPlan(tripPlan.getServiceNumber(), tripPlan.getTripNumber());
StationPlan nextFirstStationPlan = nextTripPlan.queryStationPlanByStation(station); StationPlan nextFirstStationPlan = nextTripPlan.queryStationPlanByStation(station);
planParkTime = nextFirstStationPlan.getLeaveTime().toSecondOfDay() - stationPlan.getArriveTime().toSecondOfDay(); parkTime = nextFirstStationPlan.getLeaveTime().toSecondOfDay() - systemTime.toSecondOfDay();
} }
parkTime = planParkTime;
}
} else {
if (parkTime < 0) {
// 头码车和人工车默认给30s
parkTime = 30;
} }
} }
if (parkTime < 10) {
// 头码车和人工车默认给25s
parkTime = 25;
}
LocalTime leaveTime = systemTime.plusSeconds(parkTime); LocalTime leaveTime = systemTime.plusSeconds(parkTime);
train.updateEstimatedLeaveInfo(section, leaveTime); train.updateEstimatedLeaveInfo(section, leaveTime);
this.atsStandService.updateStandParkTime(section, parkTime); this.atsStandService.updateStandParkTime(section, parkTime);

View File

@ -222,10 +222,6 @@ public class AtsRouteSettingService {
// 处理站前折返的进路排列 // 处理站前折返的进路排列
routePaths = repository.queryRoutePaths(trainSection, nextSection); routePaths = repository.queryRoutePaths(trainSection, nextSection);
} else if (train.isStop() && !trainSection.isNormalStandTrack() && (trainSection.isTurnBackTrack() || trainSection.isTransferTrack())) { // 折返轨停车 } else if (train.isStop() && !trainSection.isNormalStandTrack() && (trainSection.isTurnBackTrack() || trainSection.isTransferTrack())) { // 折返轨停车
if (tripPlan.getStartSection().isSamePhysical(trainSection.getCode()) &&
!simulation.getSystemTime().toLocalTime().plusSeconds(60).isAfter(train.getPlanArriveTime())) {
return null;
}
List<RoutePath> routePaths1 = repository.queryRoutePaths(trainSection, nextSection); List<RoutePath> routePaths1 = repository.queryRoutePaths(trainSection, nextSection);
if (!CollectionUtils.isEmpty(routePaths1)) { if (!CollectionUtils.isEmpty(routePaths1)) {
routePaths = routePaths1; routePaths = routePaths1;
@ -287,9 +283,7 @@ public class AtsRouteSettingService {
if (route.isTurnBack() && firstChoiceRoutePath.getEnd().isNormalStandTrack()) { if (route.isTurnBack() && firstChoiceRoutePath.getEnd().isNormalStandTrack()) {
continue; continue;
} }
if (this.isAtsTrigger(simulation, train, route, false, trainList)) { triggerList.add(route);
triggerList.add(route);
}
} }
} }
if (CollectionUtils.isEmpty(triggerList)) { if (CollectionUtils.isEmpty(triggerList)) {
@ -297,9 +291,12 @@ public class AtsRouteSettingService {
} else if (triggerList.size() > 1) { } else if (triggerList.size() > 1) {
if (this.hasSameEnd(triggerList)) { if (this.hasSameEnd(triggerList)) {
// 多延续保护进路取延续保护是定位的那条 // 多延续保护进路取延续保护是定位的那条
// todo 暂时逻辑定为只触发定位保护进路后需完善为根据接下来的运行目的选择延续保护
for (Route route : triggerList) { for (Route route : triggerList) {
if (this.isOverlapStraight(route)) { if (this.isOverlapStraight(route)) {
return route; if (this.isAtsTrigger(simulation, train, route, false, trainList)) {
return route;
}
} }
} }
} }

View File

@ -279,8 +279,15 @@ public class AtsStationService {
* @param station * @param station
*/ */
public void surrenderControl(Simulation simulation, SimulationMember member, Station station) { public void surrenderControl(Simulation simulation, SimulationMember member, Station station) {
Station controlModeStation = station.getControlModeStation(); Station deviceStation;
controlModeStation.surrenderControl(); if (station.isCentralized()) {
deviceStation = station;
} else {
deviceStation = station.getDeviceStation();
}
SimulationDataRepository repository = simulation.getRepository();
Set<Station> stations = repository.getStationsByDeviceStations(deviceStation);
stations.forEach(Station::surrenderControl);
} }
/** /**
@ -291,13 +298,18 @@ public class AtsStationService {
* @param station * @param station
*/ */
public void receiveControl(Simulation simulation, SimulationMember member, Station station) { public void receiveControl(Simulation simulation, SimulationMember member, Station station) {
Station controlModeStation = station.getControlModeStation(); Station deviceStation;
if (station.isCentralized()) {
deviceStation = station;
} else {
deviceStation = station.getDeviceStation();
}
SimulationDataRepository repository = simulation.getRepository();
Set<Station> stations = repository.getStationsByDeviceStations(deviceStation);
if (member.isDispatcher()) { if (member.isDispatcher()) {
// 行调 stations.forEach(Station::occControl);
controlModeStation.occControl();
} else if (member.isStationSupervisor()) { } else if (member.isStationSupervisor()) {
// 车站 stations.forEach(Station::localControl);
controlModeStation.localControl();
} }
} }

View File

@ -853,7 +853,7 @@ public class RouteService {
Collections.reverse(logicList); Collections.reverse(logicList);
} }
for (Section logic : logicList) { for (Section logic : logicList) {
if (!logic.isCtOccupied()) { if (!logic.isOccupied()) {
logic.routeUnlocking(right); logic.routeUnlocking(right);
} else { } else {
break; break;
@ -968,18 +968,18 @@ public class RouteService {
} }
SectionPath sectionPath = overlap.selectPath(); SectionPath sectionPath = overlap.selectPath();
if (Objects.nonNull(sectionPath)) { if (Objects.nonNull(sectionPath)) {
boolean routeLock = true; // boolean routeLock = true;
for (Section section : sectionPath.getSectionList()) { // for (Section section : sectionPath.getSectionList()) {
if (!section.isRouteLock()) { // if (!section.isRouteLock()) {
routeLock = false; // routeLock = false;
break; // break;
} // }
} // }
if (routeLock) { // 延续保护区段进路锁闭立即解锁 // if (routeLock) { // 延续保护区段进路锁闭立即解锁
overlap.releaseImmediately(); // overlap.releaseImmediately();
} else if (overlap.getSection().isRouteLock() && // } else
if (overlap.getSection().isRouteLock() &&
overlap.getSection().isOccupied()) { // 前方进路最后子进路占用触发/解锁执行 overlap.getSection().isOccupied()) { // 前方进路最后子进路占用触发/解锁执行
if (!overlap.isReleasing()) { if (!overlap.isReleasing()) {
log.debug(String.format("[%s]延续保护[%s],触发区段[%s(%s)]触发开始解锁", log.debug(String.format("[%s]延续保护[%s],触发区段[%s(%s)]触发开始解锁",
overlap.isRight() ? "右向" : "左向", overlap.getName(), overlap.isRight() ? "右向" : "左向", overlap.getName(),
@ -991,6 +991,17 @@ public class RouteService {
} else if (!overlap.getSection().isRouteLock()) { } else if (!overlap.getSection().isRouteLock()) {
// 最后子进路解锁则延续保护解锁 // 最后子进路解锁则延续保护解锁
overlap.releaseImmediately(); overlap.releaseImmediately();
} else {
boolean allUnlock = true;
for (Section section : sectionPath.getSectionList()) {
if (section.isOverlapLock()) {
allUnlock = false;
break;
}
}
if (allUnlock) {
overlap.releaseImmediately();
}
} }
} }
} }

View File

@ -211,6 +211,10 @@ public class Simulation {
return Objects.equals(this.buildParams.getFunctionalType(), FunctionalType.SCRIPT_MAKING); return Objects.equals(this.buildParams.getFunctionalType(), FunctionalType.SCRIPT_MAKING);
} }
public boolean isScriptPreviewSimulation() {
return FunctionalType.SCRIPT_PREVIEW.equals(buildParams.getFunctionalType());
}
/** /**
* 获取该角色类型的所有成员 * 获取该角色类型的所有成员
*/ */
@ -484,7 +488,11 @@ public class Simulation {
/** /**
* 剧本编制 * 剧本编制
*/ */
SCRIPT_MAKING; SCRIPT_MAKING,
/**
* 剧本预览
*/
SCRIPT_PREVIEW;
} }

View File

@ -148,6 +148,7 @@ public class InterlockBuilder2 {
route.setDestinationButtonSignal(endButtonSignal); route.setDestinationButtonSignal(endButtonSignal);
} }
} }
if (route.getStart() == null) continue;
route.setTurnBack(mapRouteVO.isTurnBack()); route.setTurnBack(mapRouteVO.isTurnBack());
route.setAtp(mapRouteVO.isAtp()); route.setAtp(mapRouteVO.isAtp());
route.setGround(mapRouteVO.isGround()); route.setGround(mapRouteVO.isGround());

View File

@ -23,9 +23,6 @@ public class MapDeviceBuilder {
/** /**
* 校验并构建设备数据 * 校验并构建设备数据
*
* @param graphData
* @param mapDataBuildResult
*/ */
static void checkAndBuildMapDeviceData(MapGraphDataNewVO graphData, SimulationBuilder.SimulationDeviceBuildResult mapDataBuildResult) { static void checkAndBuildMapDeviceData(MapGraphDataNewVO graphData, SimulationBuilder.SimulationDeviceBuildResult mapDataBuildResult) {
Map<String, MapElement> elementMap = mapDataBuildResult.getDeviceMap(); Map<String, MapElement> elementMap = mapDataBuildResult.getDeviceMap();
@ -41,65 +38,7 @@ public class MapDeviceBuilder {
elementMap.put(zc.getCode(), zc); elementMap.put(zc.getCode(), zc);
}); });
// 车站 // 车站
List<MapStationNewVO> stationList = graphData.getStationList(); buildStation(graphData, elementMap, errMsgList);
stationList.forEach(stationVO -> {
Station station = new Station(stationVO.getCode(), stationVO.getName());
if (Objects.nonNull(elementMap.get(station.getCode()))) {
errMsgList.add(String.format("编码为[%s]的车站不唯一", station.getCode()));
}
elementMap.put(station.getCode(), station);
station.setCentralized(stationVO.isCentralized());
if (station.isCentralized()) {
ZC zc = (ZC) elementMap.get(stationVO.getZcCode());
if (Objects.isNull(zc)) {
errMsgList.add(String.format("车站[%s(%s)]未关联ZC或ZC不存在请在ZC设备处选择管理的集中站列表", station.getName(), station.getCode()));
} else {
station.setZc(zc);
}
}
if (Objects.isNull(stationVO.getKmRange())) {
errMsgList.add(String.format("车站[%s(%s)]未设置距离", stationVO.getName(), stationVO.getCode()));
} else {
station.setKmPostVal(stationVO.getKmRange());
}
if (Objects.isNull(stationVO.getSn())) {
errMsgList.add(String.format("车站[%s(%s)]序号未设置", stationVO.getName(), stationVO.getCode()));
} else {
station.setSn(stationVO.getSn());
}
station.setInterlock(stationVO.isCiStation());
station.setHasControlMode(stationVO.isCreateControlMode());
station.setDepot(stationVO.isDepot());
station.setRoutingStationList(stationVO.getRoutingStationList());
station.setTurnBack(stationVO.isReentry());
station.setSmallRouting(stationVO.isSmallRouting());
if (station.isDepot() && station.isTurnBack()) {
errMsgList.add(String.format("车站[%s(%s)]不能既是停车场,又是折返车站",
stationVO.getName(), stationVO.getCode()));
}
if (station.isHasControlMode()) { // 有控制模式初始化为中控
station.setControlMode(Station.ControlMode.Center);
}
});
// 设备集中站下的车站关联ZC
stationList.forEach(stationVO -> {
Station station = (Station) elementMap.get(stationVO.getCode());
if (station.isCentralized()) { // 如果是设备集中站
List<String> stationCodeList = stationVO.getChargeStationCodeList();
if (!CollectionUtils.isEmpty(stationCodeList)) {
stationCodeList.forEach(code -> {
Station normal = (Station) elementMap.get(code);
if (Objects.isNull(normal)) {
errMsgList.add(String.format("设备集中站车站[%s(%s)]管理车站数据异常:编码为[%s]的车站不存在",
station.getName(), station.getCode(), code));
} else {
normal.setDeviceStation(station);
normal.setZc(station.getZc());
}
});
}
}
});
// 区段 // 区段
List<MapSectionNewVO> sectionList = graphData.getSectionList(); List<MapSectionNewVO> sectionList = graphData.getSectionList();
Map<String, Section> desCodeSectionMap = new HashMap<>(); Map<String, Section> desCodeSectionMap = new HashMap<>();
@ -930,6 +869,72 @@ public class MapDeviceBuilder {
buildCatenary(graphData, elementMap, errMsgList, mapDataBuildResult.getCatenaryMap()); buildCatenary(graphData, elementMap, errMsgList, mapDataBuildResult.getCatenaryMap());
} }
/**
* 构建车站数据
*/
private static void buildStation(MapGraphDataNewVO graphData, Map<String, MapElement> elementMap, List<String> errMsgList) {
// 车站
List<MapStationNewVO> stationList = graphData.getStationList();
stationList.forEach(stationVO -> {
Station station = new Station(stationVO.getCode(), stationVO.getName());
if (Objects.nonNull(elementMap.get(station.getCode()))) {
errMsgList.add(String.format("编码为[%s]的车站不唯一", station.getCode()));
}
elementMap.put(station.getCode(), station);
station.setCentralized(stationVO.isCentralized());
if (station.isCentralized()) {
ZC zc = (ZC) elementMap.get(stationVO.getZcCode());
if (Objects.isNull(zc)) {
errMsgList.add(String.format("车站[%s(%s)]未关联ZC或ZC不存在请在ZC设备处选择管理的集中站列表", station.getName(), station.getCode()));
} else {
station.setZc(zc);
}
}
if (Objects.isNull(stationVO.getKmRange())) {
errMsgList.add(String.format("车站[%s(%s)]未设置距离", stationVO.getName(), stationVO.getCode()));
} else {
station.setKmPostVal(stationVO.getKmRange());
}
if (Objects.isNull(stationVO.getSn())) {
errMsgList.add(String.format("车站[%s(%s)]序号未设置", stationVO.getName(), stationVO.getCode()));
} else {
station.setSn(stationVO.getSn());
}
station.setInterlock(stationVO.isCiStation());
station.setHasControlMode(stationVO.isCreateControlMode());
station.setDepot(stationVO.isDepot());
station.setRoutingStationList(stationVO.getRoutingStationList());
station.setTurnBack(stationVO.isReentry());
station.setSmallRouting(stationVO.isSmallRouting());
if (station.isDepot() && station.isTurnBack()) {
errMsgList.add(String.format("车站[%s(%s)]不能既是停车场,又是折返车站",
stationVO.getName(), stationVO.getCode()));
}
if (station.isHasControlMode()) { // 有控制模式初始化为中控
station.setControlMode(Station.ControlMode.Center);
}
});
// 设备集中站下的车站关联ZC联锁站下的车站关联联锁站
stationList.forEach(stationVO -> {
Station station = (Station) elementMap.get(stationVO.getCode());
if (station.isCentralized()) { // 如果是设备集中站
List<String> stationCodeList = stationVO.getChargeStationCodeList();
if (!CollectionUtils.isEmpty(stationCodeList)) {
stationCodeList.forEach(code -> {
Station normal = (Station) elementMap.get(code);
if (Objects.isNull(normal)) {
errMsgList.add(String.format("设备集中站车站[%s(%s)]管理车站数据异常:编码为[%s]的车站不存在",
station.getName(), station.getCode(), code));
} else {
normal.setDeviceStation(station);
normal.setZc(station.getZc());
}
});
}
}
});
}
/** /**
* 构建接触网数据 * 构建接触网数据
*/ */

View File

@ -13,7 +13,6 @@ import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySignal;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySwitch; import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealitySwitch;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain; import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain;
import club.joylink.rtss.simulation.cbtc.event.*; import club.joylink.rtss.simulation.cbtc.event.*;
import club.joylink.rtss.simulation.cbtc.member.MemberManager;
import club.joylink.rtss.simulation.cbtc.member.SimulationMember; import club.joylink.rtss.simulation.cbtc.member.SimulationMember;
import club.joylink.rtss.vo.client.SocketMessageVO; import club.joylink.rtss.vo.client.SocketMessageVO;
import club.joylink.rtss.vo.client.WebSocketMessageType; import club.joylink.rtss.vo.client.WebSocketMessageType;
@ -38,9 +37,6 @@ public class Joylink3DMessageService {
@Autowired @Autowired
private StompMessageService stompMessageService; private StompMessageService stompMessageService;
@Autowired
private MemberManager memberManager;
@Autowired @Autowired
private GroupSimulationService groupSimulationService; private GroupSimulationService groupSimulationService;

View File

@ -370,10 +370,10 @@ public class Route extends MapNamedElement {
* 排列失败 * 排列失败
*/ */
public void settingFailed() { public void settingFailed() {
this.lock = false; // this.lock = false;
if (Objects.equals(this.start.getLockedRoute(), this)) { // if (Objects.equals(this.start.getLockedRoute(), this)) {
this.start.setLockedRoute(null); // this.start.setLockedRoute(null);
} // }
this.setting = false; this.setting = false;
if (Objects.nonNull(this.overlap)) { if (Objects.nonNull(this.overlap)) {
this.overlap.settingFailed(); this.overlap.settingFailed();
@ -447,8 +447,8 @@ public class Route extends MapNamedElement {
Switch aSwitch = element.getASwitch(); Switch aSwitch = element.getASwitch();
if (aSwitch.isFault() && if (aSwitch.isFault() &&
(Switch.SwitchFault.SPLIT.equals(aSwitch.getFault()) || (Switch.SwitchFault.SPLIT.equals(aSwitch.getFault()) ||
(element.isNormal() && Switch.SwitchFault.NORMAL_SPLIT.equals(aSwitch.getFault())) || (element.isNormal() && !aSwitch.isReversePosition() && Switch.SwitchFault.NORMAL_SPLIT.equals(aSwitch.getFault())) ||
(!element.isNormal() && Switch.SwitchFault.REVERSE_SPLIT.equals(aSwitch.getFault())))) { (!element.isNormal() && !aSwitch.isNormalPosition() && Switch.SwitchFault.REVERSE_SPLIT.equals(aSwitch.getFault())))) {
return true; return true;
} }
} }

View File

@ -219,7 +219,7 @@ public class RouteOverlap extends MapNamedElement {
} }
public void settingFailed() { public void settingFailed() {
this.lock = false; // this.lock = false;
this.setting = false; this.setting = false;
this.settingStartTime = null; this.settingStartTime = null;
} }

View File

@ -373,14 +373,6 @@ public class Station extends MapNamedElement {
} }
public Station getControlModeStation() {
if (Objects.nonNull(this.hasControlMode)) {
return this;
} else {
return this.deviceStation;
}
}
/** /**
* 是否中控 * 是否中控
*/ */

View File

@ -0,0 +1,19 @@
package club.joylink.rtss.simulation.cbtc.event;
import lombok.Getter;
import lombok.Setter;
import org.springframework.context.ApplicationEvent;
@Getter
@Setter
public class SimulationSubscribeEvent extends ApplicationEvent {
private Long userId;
private String group;
public SimulationSubscribeEvent(Object source, Long userId, String group) {
super(source);
this.userId = userId;
this.group = group;
}
}

View File

@ -0,0 +1,22 @@
package club.joylink.rtss.simulation.cbtc.event;
import lombok.Getter;
import lombok.Setter;
import org.springframework.context.ApplicationEvent;
/**
* 用户退订仿真的所有订阅路径
*/
@Getter
@Setter
public class SimulationUnsubscribeAllEvent extends ApplicationEvent {
private Long userId;
private String group;
public SimulationUnsubscribeAllEvent(Object source, Long userId, String group) {
super(source);
this.userId = userId;
this.group = group;
}
}

View File

@ -0,0 +1,35 @@
package club.joylink.rtss.simulation.cbtc.message;
import club.joylink.rtss.simulation.cbtc.event.SimulationDestroyEvent;
import club.joylink.rtss.simulation.cbtc.event.SimulationSubscribeEvent;
import club.joylink.rtss.simulation.cbtc.event.SimulationUnsubscribeAllEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
public class UserSimulationStatsListen {
@Autowired
private UserSimulationStatsManager userSimulationStatsManager;
@Async("nsExecutor")
@EventListener
public void subscribeSimulation(SimulationSubscribeEvent event) {
userSimulationStatsManager.subscribeSimulation(event.getUserId(), event.getGroup());
}
@Async("nsExecutor")
@EventListener
public void unsubscribeAll(SimulationUnsubscribeAllEvent event) {
userSimulationStatsManager.unsubscribeAll(event.getUserId(), event.getGroup());
}
@Async("nsExecutor")
@EventListener
public void simulationDestroy(SimulationDestroyEvent event) {
userSimulationStatsManager.simulationDestroy(event.getSimulation());
}
}

View File

@ -0,0 +1,161 @@
package club.joylink.rtss.simulation.cbtc.message;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.services.user.IUserSimulationStatService;
import club.joylink.rtss.simulation.cbtc.GroupSimulationService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.build.SimulationBuildParams;
import club.joylink.rtss.simulation.cbtc.member.SimulationMember;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* 用户使用仿真情况记录
*/
@Slf4j
@Component
public class UserSimulationStatsManager {
@Autowired
private GroupSimulationService groupSimulationService;
@Autowired
private IUserSimulationStatService iUserSimulationStatService;
/**
* k - userId
* v - 用户订阅的仿真的groups
*/
private final Map<Long, Set<SimulationUseInfo>> userAndUseInfosMap = new ConcurrentHashMap<>();
/**
* k - group
* v - 仿真使用记录
*/
private final Map<String, Set<SimulationUseInfo>> simulationAndUseInfosMap = new ConcurrentHashMap<>();
/**
* 仿真被订阅记录仿真使用记录
*/
public void subscribeSimulation(Long userId, String group) {
Simulation simulation = groupSimulationService.getSimulationByGroup(group);
if (simulation.isScriptMakingSimulation() || simulation.isScriptPreviewSimulation()) {
return;
}
Set<SimulationUseInfo> useInfos = userAndUseInfosMap.computeIfAbsent(userId, k -> new HashSet<>());
Optional<SimulationUseInfo> infoOptional = useInfos.stream().filter(info -> group.equals(info.getGroup())).limit(1).findFirst();
if (infoOptional.isPresent()) { //如果记录已经存在
SimulationUseInfo useInfo = infoOptional.get();
useInfo.restart();
} else { //如果记录不存在
SimulationUseInfo newInfo = new SimulationUseInfo(group, userId);
useInfos.add(newInfo);
Set<SimulationUseInfo> groupKeyUseInfos = simulationAndUseInfosMap.computeIfAbsent(group, k -> new HashSet<>());
groupKeyUseInfos.add(newInfo);
}
}
/**
* 用户将仿真所有订阅退订则仿真使用记录暂停
*/
public void unsubscribeAll(Long userId, String group) {
Simulation simulation = groupSimulationService.getSimulationByGroup(group);
if (simulation.isScriptMakingSimulation() || simulation.isScriptPreviewSimulation()) {
return;
}
SimulationUseInfo useInfo = findUseInfo(userId, group);
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotNull(useInfo, String.format("仿真[%s]的使用未被记录", group));
useInfo.pause();
}
/**
* 仿真销毁持久化数据
*/
public void simulationDestroy(Simulation simulation) {
if (simulation.isScriptMakingSimulation() || simulation.isScriptPreviewSimulation()) { //剧本编制和预览仿真不记录
return;
}
//暂停并从map中移除仿真使用记录
String group = simulation.getGroup();
Set<SimulationUseInfo> useInfos = simulationAndUseInfosMap.remove(group);
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertCollectionNotEmpty(useInfos, String.format("仿真[%s]的使用未被记录", group));
useInfos.forEach(info -> {
info.pause();
Set<SimulationUseInfo> infos = userAndUseInfosMap.get(info.getUserId());
infos.removeIf(i -> group.equals(i.getGroup()));
});
SimulationBuildParams buildParams = simulation.getBuildParams();
useInfos.forEach(info -> {
Long userId = info.getUserId();
SimulationMember member = simulation.findMemberByUserId(userId);
String memberType = member == null ? null : member.getType().name();
String prdType = buildParams.getProdType() == null ? null : buildParams.getProdType().getCode();
iUserSimulationStatService.addUserSimulationStats(userId, buildParams.getMap().getId(),
prdType, info.getDuration(), memberType);
});
}
private SimulationUseInfo findUseInfo(Long userId, String group) {
Set<SimulationUseInfo> infos = userAndUseInfosMap.get(userId);
if (CollectionUtils.isEmpty(infos)) {
return null;
} else {
Optional<SimulationUseInfo> optional = infos.stream().filter(info -> group.equals(info.getGroup())).limit(1).findFirst();
return optional.orElse(null);
}
}
/**
* 仿真使用信息
*/
@Getter
@Setter
public class SimulationUseInfo {
private String group;
private Long userId;
private LocalDateTime startTime = LocalDateTime.now();
private int duration;
private boolean pause;
public SimulationUseInfo(String group, Long userId) {
this.group = group;
this.userId = userId;
}
/**
* 暂停计时
*/
public void pause() {
if (!pause) {
duration = (int) (duration + Duration.between(startTime, LocalDateTime.now()).toSeconds());
this.pause = true;
}
}
/**
* 重新开始计时
*/
public void restart() {
if (pause) {
startTime = LocalDateTime.now();
pause = false;
}
}
}
}

View File

@ -2,6 +2,7 @@ package club.joylink.rtss.simulation.cbtc.message.websocket;
import club.joylink.rtss.simulation.cbtc.event.*; import club.joylink.rtss.simulation.cbtc.event.*;
import club.joylink.rtss.websocket.WebsocketConfig; import club.joylink.rtss.websocket.WebsocketConfig;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
@ -48,6 +49,7 @@ public class SimulationSubscribeManager {
/** /**
* 发布仿真连接/断连事件 * 发布仿真连接/断连事件
*
* @param user * @param user
* @param subscribeTopic * @param subscribeTopic
* @param destination * @param destination
@ -58,12 +60,18 @@ public class SimulationSubscribeManager {
String destination, boolean sub) { String destination, boolean sub) {
if (sub) { if (sub) {
log.info(String.format("用户[%s]订阅仿真[%s]", user.getName(), destination)); log.info(String.format("用户[%s]订阅仿真[%s]", user.getName(), destination));
this.applicationContext.publishEvent(new SimulationSubscribeEvent(this, user.getUser().getId(), subscribeTopic.getId(destination)));
} else { } else {
log.info(String.format("用户[%s]取消订阅仿真[%s]", user.getName(), destination)); log.info(String.format("用户[%s]取消订阅仿真[%s]", user.getName(), destination));
//如果某个仿真的所有订阅都被取消
SimulationUserSubscribeInfo simulationUserSubscribeInfo = userSubInfoMap.get(user.getName());
if (simulationUserSubscribeInfo == null || simulationUserSubscribeInfo.isSubscribeInfoEmpty(destination)) {
this.applicationContext.publishEvent(new SimulationUnsubscribeAllEvent(this, user.getUser().getId(), subscribeTopic.getId(destination)));
}
} }
switch (subscribeTopic) { switch (subscribeTopic) {
case Main: case Main:
case WeChatMini:{ case WeChatMini: {
if (sub) { if (sub) {
this.applicationContext.publishEvent(new SimulationUserConnectEvent(user.getUser().getId(), subscribeTopic.getId(destination), this)); this.applicationContext.publishEvent(new SimulationUserConnectEvent(user.getUser().getId(), subscribeTopic.getId(destination), this));
} else { } else {
@ -71,7 +79,7 @@ public class SimulationSubscribeManager {
} }
break; break;
} }
case SandBox:{ case SandBox: {
if (sub) { if (sub) {
this.applicationContext.publishEvent(new SandboxUserConnectEvent(user.getUser().getId(), subscribeTopic.getId(destination), this)); this.applicationContext.publishEvent(new SandboxUserConnectEvent(user.getUser().getId(), subscribeTopic.getId(destination), this));
} else { } else {
@ -79,7 +87,7 @@ public class SimulationSubscribeManager {
} }
break; break;
} }
case Drive:{ case Drive: {
if (sub) { if (sub) {
this.applicationContext.publishEvent(new Drive3DUserConnectEvent(user.getUser().getId(), subscribeTopic.getId(destination), this)); this.applicationContext.publishEvent(new Drive3DUserConnectEvent(user.getUser().getId(), subscribeTopic.getId(destination), this));
} else { } else {
@ -144,12 +152,13 @@ public class SimulationSubscribeManager {
} }
subscribeInfos.removeAll(removeList); subscribeInfos.removeAll(removeList);
return set.stream() return set.stream()
.filter(dest -> this.containsSubDestination(dest) ? false : true) .filter(dest -> !this.containsSubDestination(dest))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
/** /**
* 断开连接删除此连接的所有订阅并查询此用户所有客户端都不再订阅的路径返回 * 断开连接删除此连接的所有订阅并查询此用户所有客户端都不再订阅的路径返回
*
* @param wsSessionId * @param wsSessionId
* @return 此用户所有客户端都没有订阅的路径 * @return 此用户所有客户端都没有订阅的路径
*/ */
@ -162,7 +171,7 @@ public class SimulationSubscribeManager {
.map(subscribeInfo -> subscribeInfo.destination) .map(subscribeInfo -> subscribeInfo.destination)
.collect(Collectors.toSet()) .collect(Collectors.toSet())
.stream() .stream()
.filter(dest -> this.containsSubDestination(dest) ? false : true) .filter(dest -> !this.containsSubDestination(dest))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@ -177,9 +186,24 @@ public class SimulationSubscribeManager {
return false; return false;
} }
public boolean isSubscribeInfoEmpty(String destination) {
if (sessionSubMap == null || sessionSubMap.isEmpty()) {
return true;
}
for (Set<SubscribeInfo> infos : sessionSubMap.values()) {
for (SubscribeInfo info : infos) {
if (destination.equals(info.getDestination())) {
return false;
}
}
}
return true;
}
class SubscribeInfo { class SubscribeInfo {
String wsSessionId; String wsSessionId;
String subId; String subId;
@Getter
String destination; String destination;
public SubscribeInfo(String wsSessionId, String subId, String destination) { public SubscribeInfo(String wsSessionId, String subId, String destination) {

View File

@ -189,6 +189,13 @@ public class ATPLogicLoop {
private void handleStandParkedTrain(Simulation simulation, VirtualRealityTrain train) { private void handleStandParkedTrain(Simulation simulation, VirtualRealityTrain train) {
StandParkedTrainActivity activity = train.getStandParkedTrainActivity(); StandParkedTrainActivity activity = train.getStandParkedTrainActivity();
int parkRemainTime = train.getParkRemainTime();
if (parkRemainTime > 0) {
parkRemainTime -= SimulationModule.ATP.getRateMs();
train.setParkRemainTime(parkRemainTime);
} else {
train.setParkRemainTime(0);
}
switch (activity) { switch (activity) {
case PARK: // 停靠 case PARK: // 停靠
train.nextParkedTrainActivity(); train.nextParkedTrainActivity();
@ -204,11 +211,7 @@ public class ATPLogicLoop {
} }
break; break;
case BOARD: // 乘客乘降 case BOARD: // 乘客乘降
int parkRemainTime = train.getParkRemainTime(); if (parkRemainTime < 10000) { // 小于10秒关门
if (parkRemainTime >= 0) {
parkRemainTime -= SimulationModule.ATP.getRateMs();
train.setParkRemainTime(parkRemainTime);
} else {
train.nextParkedTrainActivity(); train.nextParkedTrainActivity();
} }
break; break;

View File

@ -80,10 +80,10 @@ public class OnboardAtpApiServiceImpl implements OnboardAtpApiService {
train.park(parkTime); train.park(parkTime);
log.debug(String.format("列车[%s]停站时间[%s s]", log.debug(String.format("列车[%s]停站时间[%s s]",
train.getGroupNumber(), parkTime)); train.getGroupNumber(), parkTime));
if (parkTime > 0) { // if (parkTime > 0) {
// 开屏蔽门 // // 开屏蔽门
this.ATOService.syncOpenDoor(simulation, train); // this.ATOService.syncOpenDoor(simulation, train);
} // }
} }
@Override @Override
@ -112,7 +112,7 @@ public class OnboardAtpApiServiceImpl implements OnboardAtpApiService {
train.updateNextStationPlan(nextStation, targetSection, parking); train.updateNextStationPlan(nextStation, targetSection, parking);
this.checkAndChangeDirection(simulation, train, targetSection); this.checkAndChangeDirection(simulation, train, targetSection);
//根据时间控制速度 //根据时间控制速度
runningTime -= 10; //减去开关门和延迟启动耗费的时间 // runningTime -= 10; //减去开关门和延迟启动耗费的时间
Float atoMaxSpeed = CalculateService.calculateAtoSpeedMax4RunTime(train, runningTime); Float atoMaxSpeed = CalculateService.calculateAtoSpeedMax4RunTime(train, runningTime);
if (atoMaxSpeed != null) { if (atoMaxSpeed != null) {
train.setAtoSpeedMax(atoMaxSpeed); train.setAtoSpeedMax(atoMaxSpeed);

View File

@ -114,9 +114,31 @@ public class PassengerFlowSimulateService {
// 发送初始化数据 // 发送初始化数据
this.sendStandPassengerFlowData(simulation, standPassengerFlowMap); this.sendStandPassengerFlowData(simulation, standPassengerFlowMap);
this.sendTrainPassengerFlowData(simulation, trainPassengerFlowMap); this.sendTrainPassengerFlowData(simulation, trainPassengerFlowMap);
// 发送列车pis数据
this.sendTrainInitPisData(simulation, trainPassengerFlowMap);
log.debug(String.format("客流初始化成功")); log.debug(String.format("客流初始化成功"));
} }
private void sendTrainInitPisData(Simulation simulation, Map<String, TrainPassengerFlow> trainPassengerFlowMap) {
List<Map<String, Object>> trainPisList = new ArrayList<>();
for (TrainPassengerFlow tpf : trainPassengerFlowMap.values()) {
VirtualRealityTrain train = tpf.getTrain();
Map<String, Object> pisInfo = new HashMap<>();
pisInfo.put("code", train.getGroupNumber());
pisInfo.put("nextStation", train.getNextStation() != null ? train.getNextStation().getCode() : null);
pisInfo.put("endStation", train.getTerminalStation() != null ? train.getTerminalStation().getCode() : null);
trainPisList.add(pisInfo);
}
if (!trainPisList.isEmpty()) {
Set<String> users = simulation.getSimulationUserIds();
String json = JsonUtils.writeValueNullableFieldAsString(trainPisList);
SocketMessageVO<String> message = SocketMessageFactory.build(
WebSocketMessageType.TRAIN_PIS,
simulation.getGroup(), json);
this.stompMessageService.sendToUser(users, message);
}
}
private void sendTrainPassengerFlowData(Simulation simulation, Map<String, TrainPassengerFlow> trainPassengerFlowMap) { private void sendTrainPassengerFlowData(Simulation simulation, Map<String, TrainPassengerFlow> trainPassengerFlowMap) {
List<Map<String, Object>> trainPFNumList = new ArrayList<>(); List<Map<String, Object>> trainPFNumList = new ArrayList<>();
for (TrainPassengerFlow flow : trainPassengerFlowMap.values()) { for (TrainPassengerFlow flow : trainPassengerFlowMap.values()) {
@ -162,6 +184,8 @@ public class PassengerFlowSimulateService {
} }
this.sendStandPassengerFlowData(simulation, passengerFlowSimulationData.getStandPassengerFlowMap()); this.sendStandPassengerFlowData(simulation, passengerFlowSimulationData.getStandPassengerFlowMap());
this.sendTrainPassengerFlowData(simulation, passengerFlowSimulationData.getTrainPassengerFlowMap()); this.sendTrainPassengerFlowData(simulation, passengerFlowSimulationData.getTrainPassengerFlowMap());
// 发生列车pis数据
this.sendTrainInitPisData(simulation, passengerFlowSimulationData.getTrainPassengerFlowMap());
} }
private Map<String, TrainPassengerFlow> loadTrainPassengerFlow(Simulation simulation, PassengerFlowData passengerFlowData) { private Map<String, TrainPassengerFlow> loadTrainPassengerFlow(Simulation simulation, PassengerFlowData passengerFlowData) {
@ -289,6 +313,7 @@ public class PassengerFlowSimulateService {
SimulationDataRepository repository = simulation.getRepository(); SimulationDataRepository repository = simulation.getRepository();
List<TrainPassengerFlow> allTrainPassengerFlows = passengerFlowSimulationData.getAllTrainPassengerFlow(); List<TrainPassengerFlow> allTrainPassengerFlows = passengerFlowSimulationData.getAllTrainPassengerFlow();
PassengerFlowData passengerFlowData = passengerFlowSimulationData.getPassengerFlowData(); PassengerFlowData passengerFlowData = passengerFlowSimulationData.getPassengerFlowData();
Set<String> users = simulation.getSimulationUserIds();
for (TrainPassengerFlow trainPassengerFlow : allTrainPassengerFlows) { for (TrainPassengerFlow trainPassengerFlow : allTrainPassengerFlows) {
VirtualRealityTrain train = trainPassengerFlow.getTrain(); VirtualRealityTrain train = trainPassengerFlow.getTrain();
TrainInfo trainInfo = repository.findSupervisedTrainByGroup(train.getGroupNumber()); TrainInfo trainInfo = repository.findSupervisedTrainByGroup(train.getGroupNumber());
@ -328,14 +353,46 @@ public class PassengerFlowSimulateService {
sendData.put("out", tripStationPassengerFlowData.getDown()); sendData.put("out", tripStationPassengerFlowData.getDown());
trainPassengerFlow.startBoarding(station, tripStationPassengerFlowData); trainPassengerFlow.startBoarding(station, tripStationPassengerFlowData);
Set<String> users = simulation.getSimulationUserIds();
String json = JsonUtils.writeValueNullableFieldAsString(sendData); String json = JsonUtils.writeValueNullableFieldAsString(sendData);
SocketMessageVO<String> message = SocketMessageFactory.build( SocketMessageVO<String> message = SocketMessageFactory.build(
WebSocketMessageType.TRAIN_PFI_BL, WebSocketMessageType.TRAIN_PFI_BL,
simulation.getGroup(), json); simulation.getGroup(), json);
this.stompMessageService.sendToUser(users, message); this.stompMessageService.sendToUser(users, message);
} }
});
}
@Async("nsExecutor")
@Scheduled(fixedRate = 5000)
public void trainPis() {
passengerFlowSimulationDataMap.forEach((group, passengerFlowSimulationData) -> {
Simulation simulation = this.groupSimulationCache.getSimulationByGroup(group);
SimulationDataRepository repository = simulation.getRepository();
List<TrainPassengerFlow> allTrainPassengerFlows = passengerFlowSimulationData.getAllTrainPassengerFlow();
List<Map<String, Object>> trainPisList = new ArrayList<>();
for (TrainPassengerFlow trainPassengerFlow : allTrainPassengerFlows) {
VirtualRealityTrain train = trainPassengerFlow.getTrain();
TrainInfo trainInfo = repository.findSupervisedTrainByGroup(train.getGroupNumber());
if (Objects.isNull(trainInfo) || !trainInfo.isPlanTrain() || !trainInfo.isParking()) {
continue;
}
if (train.isStandReadyStart()) {
Map<String, Object> pisInfo = new HashMap<>();
pisInfo.put("code", train.getGroupNumber());
pisInfo.put("nextStation", train.getNextStation() != null ? train.getNextStation().getCode() : null);
pisInfo.put("endStation", train.getTerminalStation() != null ? train.getTerminalStation().getCode() : null);
trainPisList.add(pisInfo);
}
}
if (trainPisList.isEmpty()) {
return;
}
Set<String> users = simulation.getSimulationUserIds();
String json = JsonUtils.writeValueNullableFieldAsString(trainPisList);
SocketMessageVO<String> message = SocketMessageFactory.build(
WebSocketMessageType.TRAIN_PIS,
simulation.getGroup(), json);
this.stompMessageService.sendToUser(users, message);
}); });
} }

View File

@ -164,6 +164,8 @@ public enum WebSocketMessageType {
TRAIN_PFI_NUM, TRAIN_PFI_NUM,
/** 列车客流乘降人数信息 */ /** 列车客流乘降人数信息 */
TRAIN_PFI_BL, TRAIN_PFI_BL,
/** 列车位置信息 */
TRAIN_PIS,
/** 车站客流当前人数信息 */ /** 车站客流当前人数信息 */
STATION_PFI_NUM, STATION_PFI_NUM,
// ------------客流消息end------------ // ------------客流消息end------------

View File

@ -131,6 +131,7 @@ public class SocketMessageFactory {
case STAND_PFI: case STAND_PFI:
case TRAIN_PFI_NUM: case TRAIN_PFI_NUM:
case TRAIN_PFI_BL: case TRAIN_PFI_BL:
case TRAIN_PIS:
case PFV: case PFV:
case SJL3D_TrainStatus: { case SJL3D_TrainStatus: {
topicList.add(String.format(WebSocketSubscribeTopic.Sandbox3D, group)); topicList.add(String.format(WebSocketSubscribeTopic.Sandbox3D, group));

View File

@ -1,7 +1,7 @@
package club.joylink.rtss.vo.client.map.newmap; package club.joylink.rtss.vo.client.map.newmap;
import com.fasterxml.jackson.annotation.JsonIgnore;
import club.joylink.rtss.vo.client.Point; import club.joylink.rtss.vo.client.Point;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Getter; import lombok.Getter;
@ -155,7 +155,7 @@ public class MapStationNewVO {
private boolean centralized; private boolean centralized;
/** /**
* 是否锁站 * 是否锁站
*/ */
private boolean ciStation; private boolean ciStation;

View File

@ -444,16 +444,16 @@
from sys_user left join user_company_rel ucr on sys_user.id = ucr.user_id left join company on ucr.company_id = company.id from sys_user left join user_company_rel ucr on sys_user.id = ucr.user_id left join company on ucr.company_id = company.id
<where> <where>
<if test="name != null and name != ''"> <if test="name != null and name != ''">
and sys_user.`name` like '%#{name}%' and sys_user.`name` like concat('%', #{name}, '%')
</if> </if>
<if test="nickname != null and nickname != ''"> <if test="nickname != null and nickname != ''">
and sys_user.`nickname` like '%#{nickname}%' and sys_user.`nickname` like concat('%', #{nickname}, '%')
</if> </if>
<if test="mobile != null and mobile != ''"> <if test="mobile != null and mobile != ''">
and sys_user.`mobile` like '%#{mobile}%' and sys_user.`mobile` like concat('%', #{mobile}, '%')
</if> </if>
<if test="rolesStr != null and rolesStr != ''"> <if test="rolesStr != null and rolesStr != ''">
and sys_user.`roles` like '%${rolesStr}%' and sys_user.`roles` like concat('%', #{rolesStr}, '%')
</if> </if>
<if test="companyId != null"> <if test="companyId != null">
and company.id = #{companyId} and company.id = #{companyId}