Merge branch 'test' of https://git.code.tencent.com/lian-cbtc/rtss-server into test
This commit is contained in:
commit
0590008813
2
sql/20201208.sql
Normal file
2
sql/20201208.sql
Normal file
@ -0,0 +1,2 @@
|
||||
alter table user_simulation_stats modify role varchar(32) null comment '用户角色';
|
||||
|
@ -107,8 +107,9 @@ public class CompanyService implements ICompanyService {
|
||||
|
||||
@Override
|
||||
public void deleteUserCompanyRel(Long userId) {
|
||||
UserCompanyRel ucr = getUserCompanyRelEntity(userId);
|
||||
userCompanyRelDAO.deleteByPrimaryKey(ucr.getId());
|
||||
UserCompanyRelExample example = new UserCompanyRelExample();
|
||||
example.createCriteria().andUserIdEqualTo(userId);
|
||||
userCompanyRelDAO.deleteByExample(example);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -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) {
|
||||
ExamDefinitionExample example = new ExamDefinitionExample();
|
||||
example.createCriteria().andLessonIdIn(lessonIdList);
|
||||
|
@ -1,7 +1,11 @@
|
||||
package club.joylink.rtss.services;
|
||||
|
||||
import club.joylink.rtss.entity.ExamDefinition;
|
||||
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.Map;
|
||||
@ -26,14 +30,11 @@ public interface IExamService {
|
||||
|
||||
/**
|
||||
* 查询课程所属产品下有实训的实训类型
|
||||
* @param lessonId
|
||||
* @return
|
||||
*/
|
||||
List<String> queryTrainingTypes(Long lessonId);
|
||||
|
||||
/**
|
||||
* 查询试题定义的详细信息
|
||||
* @param 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);
|
||||
|
||||
/**
|
||||
* 试题上线
|
||||
* @param id
|
||||
* @param userVO
|
||||
*/
|
||||
void onLine(Long id, UserVO userVO);
|
||||
|
||||
/**
|
||||
* 试题下线
|
||||
* @param id
|
||||
* @param userVO
|
||||
*/
|
||||
void offLine(Long id, UserVO userVO);
|
||||
|
||||
/**
|
||||
* 更新试题
|
||||
* @param id
|
||||
* @param examDefinitionVO
|
||||
*/
|
||||
void update(Long id, ExamDefinitionVO examDefinitionVO);
|
||||
|
||||
void copy(Map<Long, Long> lessonRelationMap, UserVO user);
|
||||
|
||||
/**
|
||||
* 根据课程id查询考试
|
||||
*/
|
||||
List<ExamDefinition> findEntities(Long lessonId);
|
||||
}
|
||||
|
@ -4,8 +4,6 @@ package club.joylink.rtss.services;
|
||||
import club.joylink.rtss.vo.UserVO;
|
||||
import club.joylink.rtss.vo.client.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IUserExamService {
|
||||
|
||||
/**
|
||||
@ -46,18 +44,6 @@ public interface IUserExamService {
|
||||
*/
|
||||
void abandon(long id, UserVO user);
|
||||
|
||||
/**
|
||||
* 根据实训id删除用户考试记录
|
||||
* @param trainingId
|
||||
*/
|
||||
void deleteUserExamRecordByTrainingId(Long trainingId);
|
||||
|
||||
/**
|
||||
* 根据实训id列表删除用户考试记录
|
||||
* @param trainingIdList
|
||||
*/
|
||||
void deleteUserExamRecordsByTrainingIdList(List<Long> trainingIdList);
|
||||
|
||||
/**
|
||||
* 分页查询用户考试数据
|
||||
* @param queryVO
|
||||
|
@ -619,7 +619,7 @@ public class LessonService implements ILessonService {
|
||||
if (Objects.nonNull(existedDefaultLesson)) {
|
||||
lesson.setId(existedDefaultLesson.getId());
|
||||
lessonDAO.updateByPrimaryKey(lesson);
|
||||
//存在默认课程删除旧版本、章节、考试及关联实训数据
|
||||
//存在默认课程删除旧版本、章节、章节关联的实训
|
||||
LsLessonVersionExample versionExample = new LsLessonVersionExample();
|
||||
versionExample.createCriteria().andLessonIdEqualTo(existedDefaultLesson.getId());
|
||||
lessonVersionDAO.deleteByExample(versionExample);
|
||||
@ -632,21 +632,21 @@ public class LessonService implements ILessonService {
|
||||
chapterExample.createCriteria().andLessonIdEqualTo(existedDefaultLesson.getId());
|
||||
lessonChapterDAO.deleteByExample(chapterExample);
|
||||
|
||||
ExamDefinitionExample examDefinitionExample = new ExamDefinitionExample();
|
||||
examDefinitionExample.createCriteria().andLessonIdEqualTo(existedDefaultLesson.getId());
|
||||
List<ExamDefinition> examDefinitions = examDefinitionDAO.selectByExample(examDefinitionExample);
|
||||
if (!CollectionUtils.isEmpty(examDefinitions)) {
|
||||
List<Long> list = examDefinitions.stream().map(ExamDefinition::getId).collect(Collectors.toList());
|
||||
ExamDefinitionRulesExample rulesExample = new ExamDefinitionRulesExample();
|
||||
rulesExample.createCriteria().andExamIdIn(list);
|
||||
definitionRulesDAO.deleteByExample(rulesExample);
|
||||
examDefinitionDAO.deleteByExample(examDefinitionExample);
|
||||
}
|
||||
// ExamDefinitionExample examDefinitionExample = new ExamDefinitionExample();
|
||||
// examDefinitionExample.createCriteria().andLessonIdEqualTo(existedDefaultLesson.getId());
|
||||
// List<ExamDefinition> examDefinitions = examDefinitionDAO.selectByExample(examDefinitionExample);
|
||||
// if (!CollectionUtils.isEmpty(examDefinitions)) {
|
||||
// List<Long> list = examDefinitions.stream().map(ExamDefinition::getId).collect(Collectors.toList());
|
||||
// ExamDefinitionRulesExample rulesExample = new ExamDefinitionRulesExample();
|
||||
// rulesExample.createCriteria().andExamIdIn(list);
|
||||
// definitionRulesDAO.deleteByExample(rulesExample);
|
||||
// examDefinitionDAO.deleteByExample(examDefinitionExample);
|
||||
// }
|
||||
|
||||
} else {
|
||||
lessonDAO.insert(lesson);
|
||||
}
|
||||
//版本0.0
|
||||
//课程版本0.0
|
||||
LsLessonVersion lessonVersion = new LsLessonVersion();
|
||||
lessonVersion.setLessonId(lesson.getId());
|
||||
lessonVersion.setCreatorId(lesson.getCreatorId());
|
||||
@ -654,6 +654,7 @@ public class LessonService implements ILessonService {
|
||||
lessonVersion.setVersion(BusinessConsts.Lesson.Version.originalVersion);
|
||||
lessonVersionDAO.insert(lessonVersion);
|
||||
|
||||
//生成课程的章节
|
||||
List<Training> examTrainings = new ArrayList<>(20);
|
||||
int orderNum = 1;
|
||||
Random random = new Random();
|
||||
@ -687,49 +688,51 @@ public class LessonService implements ILessonService {
|
||||
}
|
||||
});
|
||||
}
|
||||
//试卷定义
|
||||
if (CollectionUtils.isEmpty(examTrainings)) {
|
||||
return;
|
||||
}
|
||||
ExamDefinition examDefinition = new ExamDefinition();
|
||||
examDefinition.setLessonId(lesson.getId());
|
||||
examDefinition.setName(lesson.getName() + "试卷");
|
||||
examDefinition.setDuration(1800);
|
||||
examDefinition.setCreatorId(userVO.getId());
|
||||
examDefinition.setCreateTime(LocalDateTime.now());
|
||||
examDefinition.setRemarks(examDefinition.getName() + "-默认试卷");
|
||||
examDefinition.setStatus("1");
|
||||
examDefinition.setTrial(true);
|
||||
//试卷规则 取20道题,每中实训类型取一道
|
||||
if (examTrainings.size() < 20) {
|
||||
examDefinition.setFullPoint(examTrainings.size() * 5);
|
||||
examDefinition.setPassingPoint(Double.valueOf(examDefinition.getFullPoint() * 0.6).intValue());
|
||||
examDefinitionDAO.insert(examDefinition);
|
||||
examTrainings.forEach(training -> {
|
||||
ExamDefinitionRules examRules = new ExamDefinitionRules();
|
||||
examRules.setExamId(examDefinition.getId());
|
||||
examRules.setNum(1);
|
||||
examRules.setPoint(5);
|
||||
examRules.setTrainingType(training.getType());
|
||||
examRules.setOperateType(training.getOperateType());
|
||||
definitionRulesDAO.insert(examRules);
|
||||
});
|
||||
|
||||
} else {
|
||||
examDefinition.setFullPoint(100);
|
||||
examDefinition.setPassingPoint(60);
|
||||
examDefinitionDAO.insert(examDefinition);
|
||||
int i = 1;
|
||||
do {
|
||||
ExamDefinitionRules examRules = new ExamDefinitionRules();
|
||||
examRules.setExamId(examDefinition.getId());
|
||||
examRules.setNum(1);
|
||||
examRules.setPoint(5);
|
||||
Training training = examTrainings.remove(random.nextInt(examTrainings.size()));
|
||||
examRules.setTrainingType(training.getType());
|
||||
examRules.setOperateType(training.getOperateType());
|
||||
definitionRulesDAO.insert(examRules);
|
||||
} while (i++ < 20);
|
||||
List<ExamDefinition> exams = iExamService.findEntities(lesson.getId());
|
||||
if (CollectionUtils.isEmpty(exams)) {
|
||||
//试卷定义
|
||||
if (CollectionUtils.isEmpty(examTrainings)) {
|
||||
return;
|
||||
}
|
||||
ExamDefinition examDefinition = new ExamDefinition();
|
||||
examDefinition.setLessonId(lesson.getId());
|
||||
examDefinition.setName(lesson.getName() + "试卷");
|
||||
examDefinition.setDuration(1800);
|
||||
examDefinition.setCreatorId(userVO.getId());
|
||||
examDefinition.setCreateTime(LocalDateTime.now());
|
||||
examDefinition.setRemarks(examDefinition.getName() + "-默认试卷");
|
||||
examDefinition.setStatus("1");
|
||||
examDefinition.setTrial(true);
|
||||
//试卷规则 取20道题,每中实训类型取一道
|
||||
if (examTrainings.size() < 20) {
|
||||
examDefinition.setFullPoint(examTrainings.size() * 5);
|
||||
examDefinition.setPassingPoint(Double.valueOf(examDefinition.getFullPoint() * 0.6).intValue());
|
||||
examDefinitionDAO.insert(examDefinition);
|
||||
examTrainings.forEach(training -> {
|
||||
ExamDefinitionRules examRules = new ExamDefinitionRules();
|
||||
examRules.setExamId(examDefinition.getId());
|
||||
examRules.setNum(1);
|
||||
examRules.setPoint(5);
|
||||
examRules.setTrainingType(training.getType());
|
||||
examRules.setOperateType(training.getOperateType());
|
||||
definitionRulesDAO.insert(examRules);
|
||||
});
|
||||
} else {
|
||||
examDefinition.setFullPoint(100);
|
||||
examDefinition.setPassingPoint(60);
|
||||
examDefinitionDAO.insert(examDefinition);
|
||||
int i = 1;
|
||||
do {
|
||||
ExamDefinitionRules examRules = new ExamDefinitionRules();
|
||||
examRules.setExamId(examDefinition.getId());
|
||||
examRules.setNum(1);
|
||||
examRules.setPoint(5);
|
||||
Training training = examTrainings.remove(random.nextInt(examTrainings.size()));
|
||||
examRules.setTrainingType(training.getType());
|
||||
examRules.setOperateType(training.getOperateType());
|
||||
definitionRulesDAO.insert(examRules);
|
||||
} while (i++ < 20);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.Duration;
|
||||
@ -234,26 +233,6 @@ public class UserExamService implements IUserExamService {
|
||||
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());
|
||||
}
|
||||
|
||||
@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) {
|
||||
// 根据用户考试记录id删除用户考试题目
|
||||
UserExamQuestionsExample questionsExample = new UserExamQuestionsExample();
|
||||
|
@ -36,7 +36,7 @@ public class DraftMapCiDataGeneratorImpl implements DraftMapCiDataGenerator {
|
||||
MapVO mapVO = this.draftMapService.getDraftMapData(mapId);
|
||||
SimulationBuilder.SimulationDeviceBuildResult buildResult = SimulationBuilder.checkAndBuildBasicMapData(mapVO);
|
||||
BusinessExceptionAssertEnum.DATA_ERROR.assertCollectionEmpty(buildResult.getErrMsgList(),
|
||||
String.format("地图基础数据有错误"));
|
||||
String.format("地图基础数据有错误: %s", JsonUtils.writeValueAsString(buildResult.getErrMsgList())));
|
||||
MapCiGenerateConfig generateConfig = mapVO.getGraphDataNew().getGenerateConfig();
|
||||
Map<String, MapElement> deviceMap = buildResult.getDeviceMap();
|
||||
// 联锁关系数据生成
|
||||
|
@ -1,6 +1,7 @@
|
||||
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.operation.Operation;
|
||||
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.script.ScriptActionBO;
|
||||
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.UserVO;
|
||||
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.simulationv1.SimulationMemberVO;
|
||||
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.context.event.EventListener;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -195,7 +193,7 @@ public class ScriptSimulationService implements IScriptSimulationService {
|
||||
}
|
||||
// 构建一个仿真
|
||||
Simulation simulation = this.groupSimulationService.create(loginUserInfoVO, draftScript.getMapId(), null,
|
||||
Simulation.FunctionalType.SIMULATION);
|
||||
Simulation.FunctionalType.SCRIPT_PREVIEW);
|
||||
loadDraftScript(simulation, draftScriptId);
|
||||
return simulation.getGroup();
|
||||
}
|
||||
|
@ -500,8 +500,8 @@ public class TrainingV1Service implements ITrainingV1Service {
|
||||
// 删除实训=章节关系
|
||||
this.iLessonDraftService.deleteChapterRelByTrainingIdList(ids);
|
||||
this.iLessonService.deleteChapterRelByTrainingIdList(ids);
|
||||
// 删除用户考试记录
|
||||
this.iUserExamService.deleteUserExamRecordsByTrainingIdList(ids);
|
||||
// // 删除用户考试记录
|
||||
// this.iUserExamService.deleteUserExamRecordsByTrainingIdList(ids);
|
||||
// 删除用户实训记录
|
||||
this.deleteUserTrainingRecordByTrainingIds(ids);
|
||||
// 删除实训数据
|
||||
@ -591,8 +591,8 @@ public class TrainingV1Service implements ITrainingV1Service {
|
||||
this.iLessonService.deleteChapterRelByTrainingId(training.getId());
|
||||
// 删除用户实训记录
|
||||
this.deleteUserTrainingRecordByTrainingId(training.getId());
|
||||
// 删除用户考试
|
||||
this.iUserExamService.deleteUserExamRecordByTrainingId(training.getId());
|
||||
// // 删除用户考试
|
||||
// this.iUserExamService.deleteUserExamRecordByTrainingId(training.getId());
|
||||
|
||||
// 删除实训状态/步骤
|
||||
this.clear(training.getId());
|
||||
|
@ -16,12 +16,11 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class UserSimulationStatStatService implements IUserSimulationStatService {
|
||||
public class UserSimulationStatService implements IUserSimulationStatService {
|
||||
|
||||
@Autowired
|
||||
private UserSimulationStatsDAO userSimulationStatsDAO;
|
@ -54,7 +54,7 @@ public class ZCLogicLoop {
|
||||
} else if (RunLevel.CBTC.equals(defaultRunLevel)) {
|
||||
//更新ITC ma
|
||||
Float distance2NextSignal = train.calculateDistance2NextNormalOpenSignal();
|
||||
if (distance2NextSignal != null && distance2NextSignal <= 100) {
|
||||
if (distance2NextSignal != null && distance2NextSignal <= 5) {
|
||||
this.calculateMAOfITC(simulation, train, trainList);
|
||||
}
|
||||
//更新CBTC ma
|
||||
@ -105,6 +105,17 @@ public class ZCLogicLoop {
|
||||
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,
|
||||
List<VirtualRealityTrain> trainList) {
|
||||
// 查找移动授权终端列表
|
||||
|
@ -275,8 +275,10 @@ public class AtsPlanService {
|
||||
//找不到计划,不处理
|
||||
return;
|
||||
}
|
||||
//有计划折返
|
||||
this.turnBackTrain(simulation, train, nextTripPlan);
|
||||
if (simulation.getSystemTime().toLocalTime().plusSeconds(60).isAfter(nextTripPlan.getStartTime())) {
|
||||
//有计划折返,且到发车时间
|
||||
this.turnBackTrain(simulation, train, nextTripPlan);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -621,23 +623,20 @@ public class AtsPlanService {
|
||||
// 更新追踪列车到站状态
|
||||
StationPlan stationPlan = tripPlan.queryStationPlanByStation(station);
|
||||
if (parkTime < 0) {
|
||||
|
||||
int planParkTime = stationPlan.getParkTime();
|
||||
parkTime = stationPlan.getLeaveTime().toSecondOfDay() - systemTime.toSecondOfDay();
|
||||
if (this.checkIfFrontTurnBack(simulation, train, section, tripPlan, stationPlan)) {
|
||||
//是站台折返车
|
||||
//如果停车时间为0 ,则取后一个车次计划的首站发车时间
|
||||
TripPlan nextTripPlan = repository.queryServiceNextTripPlan(tripPlan.getServiceNumber(), tripPlan.getTripNumber());
|
||||
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);
|
||||
train.updateEstimatedLeaveInfo(section, leaveTime);
|
||||
this.atsStandService.updateStandParkTime(section, parkTime);
|
||||
|
@ -222,10 +222,6 @@ public class AtsRouteSettingService {
|
||||
// 处理站前折返的进路排列
|
||||
routePaths = repository.queryRoutePaths(trainSection, nextSection);
|
||||
} 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);
|
||||
if (!CollectionUtils.isEmpty(routePaths1)) {
|
||||
routePaths = routePaths1;
|
||||
@ -287,9 +283,7 @@ public class AtsRouteSettingService {
|
||||
if (route.isTurnBack() && firstChoiceRoutePath.getEnd().isNormalStandTrack()) {
|
||||
continue;
|
||||
}
|
||||
if (this.isAtsTrigger(simulation, train, route, false, trainList)) {
|
||||
triggerList.add(route);
|
||||
}
|
||||
triggerList.add(route);
|
||||
}
|
||||
}
|
||||
if (CollectionUtils.isEmpty(triggerList)) {
|
||||
@ -297,9 +291,12 @@ public class AtsRouteSettingService {
|
||||
} else if (triggerList.size() > 1) {
|
||||
if (this.hasSameEnd(triggerList)) {
|
||||
// 多延续保护进路,取延续保护是定位的那条
|
||||
// todo 暂时逻辑定为只触发定位保护进路,后需完善为根据接下来的运行目的选择延续保护
|
||||
for (Route route : triggerList) {
|
||||
if (this.isOverlapStraight(route)) {
|
||||
return route;
|
||||
if (this.isAtsTrigger(simulation, train, route, false, trainList)) {
|
||||
return route;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -279,8 +279,15 @@ public class AtsStationService {
|
||||
* @param station
|
||||
*/
|
||||
public void surrenderControl(Simulation simulation, SimulationMember member, Station station) {
|
||||
Station controlModeStation = station.getControlModeStation();
|
||||
controlModeStation.surrenderControl();
|
||||
Station deviceStation;
|
||||
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
|
||||
*/
|
||||
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()) {
|
||||
// 行调
|
||||
controlModeStation.occControl();
|
||||
stations.forEach(Station::occControl);
|
||||
} else if (member.isStationSupervisor()) {
|
||||
// 车站
|
||||
controlModeStation.localControl();
|
||||
stations.forEach(Station::localControl);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -853,7 +853,7 @@ public class RouteService {
|
||||
Collections.reverse(logicList);
|
||||
}
|
||||
for (Section logic : logicList) {
|
||||
if (!logic.isCtOccupied()) {
|
||||
if (!logic.isOccupied()) {
|
||||
logic.routeUnlocking(right);
|
||||
} else {
|
||||
break;
|
||||
@ -968,18 +968,18 @@ public class RouteService {
|
||||
}
|
||||
SectionPath sectionPath = overlap.selectPath();
|
||||
if (Objects.nonNull(sectionPath)) {
|
||||
boolean routeLock = true;
|
||||
for (Section section : sectionPath.getSectionList()) {
|
||||
if (!section.isRouteLock()) {
|
||||
routeLock = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (routeLock) { // 延续保护区段进路锁闭,立即解锁
|
||||
overlap.releaseImmediately();
|
||||
} else if (overlap.getSection().isRouteLock() &&
|
||||
|
||||
overlap.getSection().isOccupied()) { // 前方进路最后子进路占用,触发/解锁执行
|
||||
// boolean routeLock = true;
|
||||
// for (Section section : sectionPath.getSectionList()) {
|
||||
// if (!section.isRouteLock()) {
|
||||
// routeLock = false;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (routeLock) { // 延续保护区段进路锁闭,立即解锁
|
||||
// overlap.releaseImmediately();
|
||||
// } else
|
||||
if (overlap.getSection().isRouteLock() &&
|
||||
overlap.getSection().isOccupied()) { // 前方进路最后子进路占用,触发/解锁执行
|
||||
if (!overlap.isReleasing()) {
|
||||
log.debug(String.format("[%s]延续保护[%s],触发区段[%s(%s)]触发开始解锁",
|
||||
overlap.isRight() ? "右向" : "左向", overlap.getName(),
|
||||
@ -991,6 +991,17 @@ public class RouteService {
|
||||
} else if (!overlap.getSection().isRouteLock()) {
|
||||
// 最后子进路解锁,则延续保护解锁
|
||||
overlap.releaseImmediately();
|
||||
} else {
|
||||
boolean allUnlock = true;
|
||||
for (Section section : sectionPath.getSectionList()) {
|
||||
if (section.isOverlapLock()) {
|
||||
allUnlock = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allUnlock) {
|
||||
overlap.releaseImmediately();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -211,6 +211,10 @@ public class Simulation {
|
||||
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;
|
||||
|
||||
|
||||
}
|
||||
|
@ -148,6 +148,7 @@ public class InterlockBuilder2 {
|
||||
route.setDestinationButtonSignal(endButtonSignal);
|
||||
}
|
||||
}
|
||||
if (route.getStart() == null) continue;
|
||||
route.setTurnBack(mapRouteVO.isTurnBack());
|
||||
route.setAtp(mapRouteVO.isAtp());
|
||||
route.setGround(mapRouteVO.isGround());
|
||||
|
@ -23,9 +23,6 @@ public class MapDeviceBuilder {
|
||||
|
||||
/**
|
||||
* 校验并构建设备数据
|
||||
*
|
||||
* @param graphData
|
||||
* @param mapDataBuildResult
|
||||
*/
|
||||
static void checkAndBuildMapDeviceData(MapGraphDataNewVO graphData, SimulationBuilder.SimulationDeviceBuildResult mapDataBuildResult) {
|
||||
Map<String, MapElement> elementMap = mapDataBuildResult.getDeviceMap();
|
||||
@ -41,65 +38,7 @@ public class MapDeviceBuilder {
|
||||
elementMap.put(zc.getCode(), zc);
|
||||
});
|
||||
// 车站
|
||||
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());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
buildStation(graphData, elementMap, errMsgList);
|
||||
// 区段
|
||||
List<MapSectionNewVO> sectionList = graphData.getSectionList();
|
||||
Map<String, Section> desCodeSectionMap = new HashMap<>();
|
||||
@ -930,6 +869,72 @@ public class MapDeviceBuilder {
|
||||
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());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建接触网数据
|
||||
*/
|
||||
|
@ -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.VirtualRealityTrain;
|
||||
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.vo.client.SocketMessageVO;
|
||||
import club.joylink.rtss.vo.client.WebSocketMessageType;
|
||||
@ -38,9 +37,6 @@ public class Joylink3DMessageService {
|
||||
@Autowired
|
||||
private StompMessageService stompMessageService;
|
||||
|
||||
@Autowired
|
||||
private MemberManager memberManager;
|
||||
|
||||
@Autowired
|
||||
private GroupSimulationService groupSimulationService;
|
||||
|
||||
|
@ -370,10 +370,10 @@ public class Route extends MapNamedElement {
|
||||
* 排列失败
|
||||
*/
|
||||
public void settingFailed() {
|
||||
this.lock = false;
|
||||
if (Objects.equals(this.start.getLockedRoute(), this)) {
|
||||
this.start.setLockedRoute(null);
|
||||
}
|
||||
// this.lock = false;
|
||||
// if (Objects.equals(this.start.getLockedRoute(), this)) {
|
||||
// this.start.setLockedRoute(null);
|
||||
// }
|
||||
this.setting = false;
|
||||
if (Objects.nonNull(this.overlap)) {
|
||||
this.overlap.settingFailed();
|
||||
@ -447,8 +447,8 @@ public class Route extends MapNamedElement {
|
||||
Switch aSwitch = element.getASwitch();
|
||||
if (aSwitch.isFault() &&
|
||||
(Switch.SwitchFault.SPLIT.equals(aSwitch.getFault()) ||
|
||||
(element.isNormal() && Switch.SwitchFault.NORMAL_SPLIT.equals(aSwitch.getFault())) ||
|
||||
(!element.isNormal() && Switch.SwitchFault.REVERSE_SPLIT.equals(aSwitch.getFault())))) {
|
||||
(element.isNormal() && !aSwitch.isReversePosition() && Switch.SwitchFault.NORMAL_SPLIT.equals(aSwitch.getFault())) ||
|
||||
(!element.isNormal() && !aSwitch.isNormalPosition() && Switch.SwitchFault.REVERSE_SPLIT.equals(aSwitch.getFault())))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ public class RouteOverlap extends MapNamedElement {
|
||||
}
|
||||
|
||||
public void settingFailed() {
|
||||
this.lock = false;
|
||||
// this.lock = false;
|
||||
this.setting = false;
|
||||
this.settingStartTime = null;
|
||||
}
|
||||
|
@ -373,14 +373,6 @@ public class Station extends MapNamedElement {
|
||||
|
||||
}
|
||||
|
||||
public Station getControlModeStation() {
|
||||
if (Objects.nonNull(this.hasControlMode)) {
|
||||
return this;
|
||||
} else {
|
||||
return this.deviceStation;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否中控
|
||||
*/
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package club.joylink.rtss.simulation.cbtc.message.websocket;
|
||||
|
||||
import club.joylink.rtss.simulation.cbtc.event.*;
|
||||
import club.joylink.rtss.websocket.WebsocketConfig;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@ -48,6 +49,7 @@ public class SimulationSubscribeManager {
|
||||
|
||||
/**
|
||||
* 发布仿真连接/断连事件
|
||||
*
|
||||
* @param user
|
||||
* @param subscribeTopic
|
||||
* @param destination
|
||||
@ -58,12 +60,18 @@ public class SimulationSubscribeManager {
|
||||
String destination, boolean sub) {
|
||||
if (sub) {
|
||||
log.info(String.format("用户[%s]订阅仿真[%s]", user.getName(), destination));
|
||||
this.applicationContext.publishEvent(new SimulationSubscribeEvent(this, user.getUser().getId(), subscribeTopic.getId(destination)));
|
||||
} else {
|
||||
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) {
|
||||
case Main:
|
||||
case WeChatMini:{
|
||||
case WeChatMini: {
|
||||
if (sub) {
|
||||
this.applicationContext.publishEvent(new SimulationUserConnectEvent(user.getUser().getId(), subscribeTopic.getId(destination), this));
|
||||
} else {
|
||||
@ -71,7 +79,7 @@ public class SimulationSubscribeManager {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SandBox:{
|
||||
case SandBox: {
|
||||
if (sub) {
|
||||
this.applicationContext.publishEvent(new SandboxUserConnectEvent(user.getUser().getId(), subscribeTopic.getId(destination), this));
|
||||
} else {
|
||||
@ -79,7 +87,7 @@ public class SimulationSubscribeManager {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Drive:{
|
||||
case Drive: {
|
||||
if (sub) {
|
||||
this.applicationContext.publishEvent(new Drive3DUserConnectEvent(user.getUser().getId(), subscribeTopic.getId(destination), this));
|
||||
} else {
|
||||
@ -144,12 +152,13 @@ public class SimulationSubscribeManager {
|
||||
}
|
||||
subscribeInfos.removeAll(removeList);
|
||||
return set.stream()
|
||||
.filter(dest -> this.containsSubDestination(dest) ? false : true)
|
||||
.filter(dest -> !this.containsSubDestination(dest))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 断开连接,删除此连接的所有订阅,并查询此用户所有客户端都不再订阅的路径返回
|
||||
*
|
||||
* @param wsSessionId
|
||||
* @return 此用户所有客户端都没有订阅的路径
|
||||
*/
|
||||
@ -162,7 +171,7 @@ public class SimulationSubscribeManager {
|
||||
.map(subscribeInfo -> subscribeInfo.destination)
|
||||
.collect(Collectors.toSet())
|
||||
.stream()
|
||||
.filter(dest -> this.containsSubDestination(dest) ? false : true)
|
||||
.filter(dest -> !this.containsSubDestination(dest))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@ -177,9 +186,24 @@ public class SimulationSubscribeManager {
|
||||
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 {
|
||||
String wsSessionId;
|
||||
String subId;
|
||||
@Getter
|
||||
String destination;
|
||||
|
||||
public SubscribeInfo(String wsSessionId, String subId, String destination) {
|
||||
|
@ -189,6 +189,13 @@ public class ATPLogicLoop {
|
||||
|
||||
private void handleStandParkedTrain(Simulation simulation, VirtualRealityTrain train) {
|
||||
StandParkedTrainActivity activity = train.getStandParkedTrainActivity();
|
||||
int parkRemainTime = train.getParkRemainTime();
|
||||
if (parkRemainTime > 0) {
|
||||
parkRemainTime -= SimulationModule.ATP.getRateMs();
|
||||
train.setParkRemainTime(parkRemainTime);
|
||||
} else {
|
||||
train.setParkRemainTime(0);
|
||||
}
|
||||
switch (activity) {
|
||||
case PARK: // 停靠
|
||||
train.nextParkedTrainActivity();
|
||||
@ -204,11 +211,7 @@ public class ATPLogicLoop {
|
||||
}
|
||||
break;
|
||||
case BOARD: // 乘客乘降
|
||||
int parkRemainTime = train.getParkRemainTime();
|
||||
if (parkRemainTime >= 0) {
|
||||
parkRemainTime -= SimulationModule.ATP.getRateMs();
|
||||
train.setParkRemainTime(parkRemainTime);
|
||||
} else {
|
||||
if (parkRemainTime < 10000) { // 小于10秒,关门
|
||||
train.nextParkedTrainActivity();
|
||||
}
|
||||
break;
|
||||
|
@ -80,10 +80,10 @@ public class OnboardAtpApiServiceImpl implements OnboardAtpApiService {
|
||||
train.park(parkTime);
|
||||
log.debug(String.format("列车[%s]停站时间[%s s]",
|
||||
train.getGroupNumber(), parkTime));
|
||||
if (parkTime > 0) {
|
||||
// 开屏蔽门
|
||||
this.ATOService.syncOpenDoor(simulation, train);
|
||||
}
|
||||
// if (parkTime > 0) {
|
||||
// // 开屏蔽门
|
||||
// this.ATOService.syncOpenDoor(simulation, train);
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -112,7 +112,7 @@ public class OnboardAtpApiServiceImpl implements OnboardAtpApiService {
|
||||
train.updateNextStationPlan(nextStation, targetSection, parking);
|
||||
this.checkAndChangeDirection(simulation, train, targetSection);
|
||||
//根据时间控制速度
|
||||
runningTime -= 10; //减去开关门和延迟启动耗费的时间
|
||||
// runningTime -= 10; //减去开关门和延迟启动耗费的时间
|
||||
Float atoMaxSpeed = CalculateService.calculateAtoSpeedMax4RunTime(train, runningTime);
|
||||
if (atoMaxSpeed != null) {
|
||||
train.setAtoSpeedMax(atoMaxSpeed);
|
||||
|
@ -114,9 +114,31 @@ public class PassengerFlowSimulateService {
|
||||
// 发送初始化数据
|
||||
this.sendStandPassengerFlowData(simulation, standPassengerFlowMap);
|
||||
this.sendTrainPassengerFlowData(simulation, trainPassengerFlowMap);
|
||||
// 发送列车pis数据
|
||||
this.sendTrainInitPisData(simulation, trainPassengerFlowMap);
|
||||
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) {
|
||||
List<Map<String, Object>> trainPFNumList = new ArrayList<>();
|
||||
for (TrainPassengerFlow flow : trainPassengerFlowMap.values()) {
|
||||
@ -162,6 +184,8 @@ public class PassengerFlowSimulateService {
|
||||
}
|
||||
this.sendStandPassengerFlowData(simulation, passengerFlowSimulationData.getStandPassengerFlowMap());
|
||||
this.sendTrainPassengerFlowData(simulation, passengerFlowSimulationData.getTrainPassengerFlowMap());
|
||||
// 发生列车pis数据
|
||||
this.sendTrainInitPisData(simulation, passengerFlowSimulationData.getTrainPassengerFlowMap());
|
||||
}
|
||||
|
||||
private Map<String, TrainPassengerFlow> loadTrainPassengerFlow(Simulation simulation, PassengerFlowData passengerFlowData) {
|
||||
@ -289,6 +313,7 @@ public class PassengerFlowSimulateService {
|
||||
SimulationDataRepository repository = simulation.getRepository();
|
||||
List<TrainPassengerFlow> allTrainPassengerFlows = passengerFlowSimulationData.getAllTrainPassengerFlow();
|
||||
PassengerFlowData passengerFlowData = passengerFlowSimulationData.getPassengerFlowData();
|
||||
Set<String> users = simulation.getSimulationUserIds();
|
||||
for (TrainPassengerFlow trainPassengerFlow : allTrainPassengerFlows) {
|
||||
VirtualRealityTrain train = trainPassengerFlow.getTrain();
|
||||
TrainInfo trainInfo = repository.findSupervisedTrainByGroup(train.getGroupNumber());
|
||||
@ -328,14 +353,46 @@ public class PassengerFlowSimulateService {
|
||||
sendData.put("out", tripStationPassengerFlowData.getDown());
|
||||
trainPassengerFlow.startBoarding(station, tripStationPassengerFlowData);
|
||||
|
||||
Set<String> users = simulation.getSimulationUserIds();
|
||||
String json = JsonUtils.writeValueNullableFieldAsString(sendData);
|
||||
SocketMessageVO<String> message = SocketMessageFactory.build(
|
||||
WebSocketMessageType.TRAIN_PFI_BL,
|
||||
simulation.getGroup(), json);
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -164,6 +164,8 @@ public enum WebSocketMessageType {
|
||||
TRAIN_PFI_NUM,
|
||||
/** 列车客流乘降人数信息 */
|
||||
TRAIN_PFI_BL,
|
||||
/** 列车位置信息 */
|
||||
TRAIN_PIS,
|
||||
/** 车站客流当前人数信息 */
|
||||
STATION_PFI_NUM,
|
||||
// ------------客流消息end------------
|
||||
|
@ -131,6 +131,7 @@ public class SocketMessageFactory {
|
||||
case STAND_PFI:
|
||||
case TRAIN_PFI_NUM:
|
||||
case TRAIN_PFI_BL:
|
||||
case TRAIN_PIS:
|
||||
case PFV:
|
||||
case SJL3D_TrainStatus: {
|
||||
topicList.add(String.format(WebSocketSubscribeTopic.Sandbox3D, group));
|
||||
|
@ -1,7 +1,7 @@
|
||||
package club.joylink.rtss.vo.client.map.newmap;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import club.joylink.rtss.vo.client.Point;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
@ -155,7 +155,7 @@ public class MapStationNewVO {
|
||||
private boolean centralized;
|
||||
|
||||
/**
|
||||
* 是否连锁站
|
||||
* 是否联锁站
|
||||
*/
|
||||
private boolean ciStation;
|
||||
|
||||
|
@ -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
|
||||
<where>
|
||||
<if test="name != null and name != ''">
|
||||
and sys_user.`name` like '%#{name}%'
|
||||
and sys_user.`name` like concat('%', #{name}, '%')
|
||||
</if>
|
||||
<if test="nickname != null and nickname != ''">
|
||||
and sys_user.`nickname` like '%#{nickname}%'
|
||||
and sys_user.`nickname` like concat('%', #{nickname}, '%')
|
||||
</if>
|
||||
<if test="mobile != null and mobile != ''">
|
||||
and sys_user.`mobile` like '%#{mobile}%'
|
||||
and sys_user.`mobile` like concat('%', #{mobile}, '%')
|
||||
</if>
|
||||
<if test="rolesStr != null and rolesStr != ''">
|
||||
and sys_user.`roles` like '%${rolesStr}%'
|
||||
and sys_user.`roles` like concat('%', #{rolesStr}, '%')
|
||||
</if>
|
||||
<if test="companyId != null">
|
||||
and company.id = #{companyId}
|
||||
|
Loading…
Reference in New Issue
Block a user