Merge remote-tracking branch 'origin/test' into test-training2

This commit is contained in:
tiger_zhou 2022-09-20 16:53:21 +08:00
commit 542c7da98e
38 changed files with 913 additions and 39 deletions

View File

@ -67,6 +67,9 @@ public enum ProjectDeviceType {
SANDBOX, SANDBOX,
/** 派班工作站 */ /** 派班工作站 */
SCHEDULING, SCHEDULING,
PIS_STAND,
PIS_TRAIN,
/* -----------client device end---------- */ /* -----------client device end---------- */
; ;

View File

@ -23,10 +23,18 @@ public class AudioResourcesController {
* 创建 * 创建
*/ */
@PostMapping() @PostMapping()
public void create(@RequestBody @Validated AudioResourcesVO vo) { public void create(@RequestBody @Validated(value = AudioResourcesVO.Create.class) AudioResourcesVO vo) {
audioResourcesService.create(vo); audioResourcesService.create(vo);
} }
/**
* 生成资源
*/
@PostMapping("/generate")
public void generate(@RequestBody @Validated(value = AudioResourcesVO.Generate.class) AudioResourcesVO vo) {
audioResourcesService.generate(vo);
}
/** /**
* 查询所有 * 查询所有
*/ */

View File

@ -34,6 +34,11 @@ public class IscsSystemResourcesController {
iscsSystemResourcesService.batchCreate(vos); iscsSystemResourcesService.batchCreate(vos);
} }
@PostMapping("/generate/{mapId}/{type}")
public void generate(@PathVariable long mapId, @PathVariable int type) {
iscsSystemResourcesService.generate(mapId, type);
}
/** /**
* 获取所有 * 获取所有
*/ */

View File

@ -4,13 +4,8 @@ import club.joylink.rtss.services.ISysUserService;
import club.joylink.rtss.vo.AccountVO; import club.joylink.rtss.vo.AccountVO;
import club.joylink.rtss.vo.UserQueryVO; import club.joylink.rtss.vo.UserQueryVO;
import club.joylink.rtss.vo.client.PageVO; import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.user.MobileInfoVO; import club.joylink.rtss.vo.client.user.*;
import club.joylink.rtss.vo.client.user.UpdateEmailVO;
import club.joylink.rtss.vo.client.user.UpdateMobileVO;
import club.joylink.rtss.vo.client.user.UpdatePasswordVO;
import club.joylink.rtss.vo.user.AccountCreateVO; import club.joylink.rtss.vo.user.AccountCreateVO;
import club.joylink.rtss.vo.client.user.AccountRegisterQueryVO;
import club.joylink.rtss.vo.client.user.AccountRegisterStatisticsVO;
import club.joylink.rtss.vo.user.UserRegisterCheck; import club.joylink.rtss.vo.user.UserRegisterCheck;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -146,4 +141,20 @@ public class UserInfoController {
queryVO.setSource(source); queryVO.setSource(source);
return this.iSysUserService.queryPagedUser(queryVO); return this.iSysUserService.queryPagedUser(queryVO);
} }
/**
* 超管重置用户密码
*/
@PutMapping("/{id}/reset/pwd")
public void resetPwd(@PathVariable long id) {
iSysUserService.resetPwd(id);
}
/**
* 找回密码
*/
@PutMapping("/retrieve/pwd")
public void retrievePwd(@RequestBody @Validated RetrievePwdVO vo) {
iSysUserService.retrievePwd(vo);
}
} }

View File

@ -10,7 +10,6 @@ import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.org.CompanyVO; import club.joylink.rtss.vo.client.org.CompanyVO;
import club.joylink.rtss.vo.client.user.*; import club.joylink.rtss.vo.client.user.*;
import club.joylink.rtss.vo.user.AccountCreateVO; import club.joylink.rtss.vo.user.AccountCreateVO;
import club.joylink.rtss.vo.client.user.AccountRegisterStatisticsVO;
import club.joylink.rtss.vo.wx.WmUserSession; import club.joylink.rtss.vo.wx.WmUserSession;
import lombok.NonNull; import lombok.NonNull;
@ -325,4 +324,8 @@ public interface ISysUserService {
boolean isThirdParentAccountExist(String parentAccount); boolean isThirdParentAccountExist(String parentAccount);
List<SysAccount> findEntitiesBySource(String source); List<SysAccount> findEntitiesBySource(String source);
void resetPwd(long id);
void retrievePwd(RetrievePwdVO vo);
} }

View File

@ -738,7 +738,7 @@ public class SysUserService implements ISysUserService {
@Override @Override
public String sendMobileValidCode(MobileInfoVO mobileInfoVO) { public String sendMobileValidCode(MobileInfoVO mobileInfoVO) {
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertTrue(mobileInfoVO.validate()); BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertTrue(mobileInfoVO.validate(), "发送验证码请求未通过");
String code = RandomGenerator.getByLen(4); String code = RandomGenerator.getByLen(4);
long ts = System.currentTimeMillis(); long ts = System.currentTimeMillis();
List<String> params = new ArrayList<>(); List<String> params = new ArrayList<>();
@ -757,18 +757,44 @@ public class SysUserService implements ISysUserService {
public void updatePassword(Long id, UpdatePasswordVO updatePasswordVO) { public void updatePassword(Long id, UpdatePasswordVO updatePasswordVO) {
Objects.requireNonNull(id, "用户id不能为空"); Objects.requireNonNull(id, "用户id不能为空");
SysAccount account = this.sysAccountDAO.selectByPrimaryKey(id); SysAccount account = this.sysAccountDAO.selectByPrimaryKey(id);
updatePwdByMobileVdCode(updatePasswordVO, account);
}
private void updatePwdByMobileVdCode(UpdatePasswordVO updatePasswordVO, SysAccount account) {
if (Objects.nonNull(account)) { if (Objects.nonNull(account)) {
VdCode vdCode = (VdCode) this.iCacheService.get(account.getNationcode() + account.getMobile()); VdCode vdCode = (VdCode) this.iCacheService.get(account.getNationcode() + account.getMobile());
BusinessExceptionAssertEnum.INCORRECT_VERIFICATION_CODE.assertNotNull(vdCode); BusinessExceptionAssertEnum.INCORRECT_VERIFICATION_CODE.assertNotNull(vdCode);
// 验证验证码 // 验证验证码
vdCode.isValidCode(updatePasswordVO.getVfCode()); vdCode.isValidCode(updatePasswordVO.getVfCode());
// 验证码通过,修改密码 // 验证码通过,修改密码
account.setPassword(updatePasswordVO.getPassword()); updatePassword4Entity(account, updatePasswordVO.getPassword());
account.setUpdateTime(LocalDateTime.now());
this.sysAccountDAO.updateByPrimaryKey(account);
} }
} }
/**
* 通过邮箱验证码更新密码
* @param account 要更新密码的账号
* @param userVfCode 用户填写的验证码
* @param newPwd 新密码
*/
private void updatePwdByEmailVdCode(SysAccount account, String userVfCode, String newPwd) {
if (Objects.nonNull(account)) {
VdCode vdCode = (VdCode) this.iCacheService.get(account.getEmail());
BusinessExceptionAssertEnum.INCORRECT_VERIFICATION_CODE.assertNotNull(vdCode);
// 验证验证码
vdCode.isValidCode(userVfCode);
// 验证码通过,修改密码
updatePassword4Entity(account, newPwd);
}
}
private void updatePassword4Entity(SysAccount account, String newPwd) {
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertHasText(newPwd, "新密码不能为空");
account.setPassword(newPwd);
account.setUpdateTime(LocalDateTime.now());
this.sysAccountDAO.updateByPrimaryKey(account);
}
@Override @Override
public void updateUserPassword(Long id, String password) { public void updateUserPassword(Long id, String password) {
Objects.requireNonNull(id, "用户id不能为空"); Objects.requireNonNull(id, "用户id不能为空");
@ -991,6 +1017,55 @@ public class SysUserService implements ISysUserService {
return sysAccountDAO.selectByExample(example); return sysAccountDAO.selectByExample(example);
} }
@Override
public void resetPwd(long id) {
String pwd = EncryptUtil.md5("123456");
SysAccount account = getEntity(id);
updatePassword4Entity(account, pwd);
}
@Override
public void retrievePwd(RetrievePwdVO vo) {
if (StringUtils.hasText(vo.getMobile())) {
SysAccount account = getEntityByMobile(vo.getMobile());
UpdatePasswordVO updatePasswordVO = new UpdatePasswordVO(vo.getVfCode(), vo.getNewPwd());
updatePwdByMobileVdCode(updatePasswordVO, account);
} else if (StringUtils.hasText(vo.getEmail())) {
SysAccount account = getEntityByEmail(vo.getEmail());
updatePwdByEmailVdCode(account, vo.getVfCode(), vo.getNewPwd());
} else {
throw BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.exception("手机号和邮箱不能都为空");
}
}
private SysAccount getEntityByMobile(String mobile) {
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertHasText(mobile);
SysAccountExample example = new SysAccountExample();
example.createCriteria().andMobileEqualTo(mobile);
List<SysAccount> accounts = sysAccountDAO.selectByExample(example);
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertCollectionNotEmpty(accounts,
String.format("[手机号:%s]的账号不存在", mobile));
if (accounts.size() != 1) {
log.error("[手机号:%s]的账号有多个");
throw BusinessExceptionAssertEnum.DATA_ERROR.exception();
}
return accounts.get(0);
}
private SysAccount getEntityByEmail(String email) {
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertHasText(email);
SysAccountExample example = new SysAccountExample();
example.createCriteria().andEmailEqualTo(email);
List<SysAccount> accounts = sysAccountDAO.selectByExample(example);
BusinessExceptionAssertEnum.DATA_NOT_EXIST.assertCollectionNotEmpty(accounts,
String.format("[邮箱:%s]的账号不存在", email));
if (accounts.size() != 1) {
log.error(String.format("[邮箱:%s]的账号有多个", email));
throw BusinessExceptionAssertEnum.DATA_ERROR.exception();
}
return accounts.get(0);
}
private boolean isSameEmailExist(String email) { private boolean isSameEmailExist(String email) {
SysAccountExample example = new SysAccountExample(); SysAccountExample example = new SysAccountExample();
example.createCriteria() example.createCriteria()

View File

@ -20,4 +20,6 @@ public interface AudioResourcesService {
PageVO<AudioResourcesVO> pagedQuery(AudioResourcesQueryVO queryVO); PageVO<AudioResourcesVO> pagedQuery(AudioResourcesQueryVO queryVO);
AudioResourcesVO getById(long id); AudioResourcesVO getById(long id);
void generate(AudioResourcesVO vo);
} }

View File

@ -3,12 +3,14 @@ package club.joylink.rtss.services.audio;
import club.joylink.rtss.dao.AudioResourcesDAO; import club.joylink.rtss.dao.AudioResourcesDAO;
import club.joylink.rtss.entity.AudioResources; import club.joylink.rtss.entity.AudioResources;
import club.joylink.rtss.entity.AudioResourcesExample; import club.joylink.rtss.entity.AudioResourcesExample;
import club.joylink.rtss.services.voice.IVoiceService;
import club.joylink.rtss.vo.client.PageVO; import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.audio.AudioResourcesQueryVO; import club.joylink.rtss.vo.client.audio.AudioResourcesQueryVO;
import club.joylink.rtss.vo.client.audio.AudioResourcesVO; import club.joylink.rtss.vo.client.audio.AudioResourcesVO;
import com.github.pagehelper.Page; import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
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 org.springframework.util.StringUtils;
@ -21,6 +23,9 @@ import java.util.List;
public class AudioResourcesServiceImpl implements AudioResourcesService { public class AudioResourcesServiceImpl implements AudioResourcesService {
@Autowired @Autowired
private AudioResourcesDAO audioResourcesDAO; private AudioResourcesDAO audioResourcesDAO;
@Autowired
@Qualifier("baiDuVoiceService")
private IVoiceService iVoiceService;
@Override @Override
public void create(AudioResourcesVO vo) { public void create(AudioResourcesVO vo) {
@ -82,6 +87,13 @@ public class AudioResourcesServiceImpl implements AudioResourcesService {
return new AudioResourcesVO(getEntity(id)); return new AudioResourcesVO(getEntity(id));
} }
@Override
public void generate(AudioResourcesVO vo) {
String filePath = iVoiceService.synthesis(vo.getDesc());
vo.setUrl(filePath);
create(vo);
}
private AudioResources getEntity(long id) { private AudioResources getEntity(long id) {
return audioResourcesDAO.selectByPrimaryKey(id); return audioResourcesDAO.selectByPrimaryKey(id);
} }

View File

@ -468,6 +468,8 @@ public class AuthenticateService implements IAuthenticateService {
case CCTV: case CCTV:
case SANDBOX: case SANDBOX:
case ILW: case ILW:
case PIS_STAND:
case PIS_TRAIN:
case VR_IBP: { case VR_IBP: {
RelationLoginConfigVO config = deviceVO.buildRelationLoginConfig(); RelationLoginConfigVO config = deviceVO.buildRelationLoginConfig();
if (Objects.nonNull(config) && Objects.nonNull(config.getDeviceCode())) { if (Objects.nonNull(config) && Objects.nonNull(config.getDeviceCode())) {

View File

@ -22,4 +22,10 @@ public interface IscsSystemResourcesService {
List<IscsSystemResourcesVO> criteriaQuery(IscsSystemResourcesQueryVO queryVO); List<IscsSystemResourcesVO> criteriaQuery(IscsSystemResourcesQueryVO queryVO);
void batchCreate(List<IscsSystemResourcesVO> vos); void batchCreate(List<IscsSystemResourcesVO> vos);
/**
* 生成Iscs资源
* @param type 要生成的资源的类型详见方法体内的注释
*/
void generate(long mapId, int type);
} }

View File

@ -4,11 +4,14 @@ import club.joylink.rtss.dao.IscsSystemResourcesDAO;
import club.joylink.rtss.entity.IscsSystemResources; import club.joylink.rtss.entity.IscsSystemResources;
import club.joylink.rtss.entity.IscsSystemResourcesExample; import club.joylink.rtss.entity.IscsSystemResourcesExample;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum; import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.services.IMapService;
import club.joylink.rtss.services.audio.AudioResourcesService; import club.joylink.rtss.services.audio.AudioResourcesService;
import club.joylink.rtss.vo.client.PageVO; import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.audio.AudioResourcesVO; import club.joylink.rtss.vo.client.audio.AudioResourcesVO;
import club.joylink.rtss.vo.client.iscs.systemRes.IscsSystemResourcesQueryVO; import club.joylink.rtss.vo.client.iscs.systemRes.IscsSystemResourcesQueryVO;
import club.joylink.rtss.vo.client.iscs.systemRes.IscsSystemResourcesVO; import club.joylink.rtss.vo.client.iscs.systemRes.IscsSystemResourcesVO;
import club.joylink.rtss.vo.map.MapVO;
import club.joylink.rtss.vo.map.graph.MapStationNewVO;
import com.github.pagehelper.Page; import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -22,9 +25,10 @@ import java.util.List;
public class IscsSystemResourcesServiceImpl implements IscsSystemResourcesService { public class IscsSystemResourcesServiceImpl implements IscsSystemResourcesService {
@Autowired @Autowired
private IscsSystemResourcesDAO iscsSystemResourcesDAO; private IscsSystemResourcesDAO iscsSystemResourcesDAO;
@Autowired @Autowired
private AudioResourcesService audioResourcesService; private AudioResourcesService audioResourcesService;
@Autowired
private IMapService iMapService;
@Override @Override
public void create(IscsSystemResourcesVO vo) { public void create(IscsSystemResourcesVO vo) {
@ -106,6 +110,13 @@ public class IscsSystemResourcesServiceImpl implements IscsSystemResourcesServic
} }
} }
@Override
public void generate(long mapId, int type) {
MapVO mapDetail = iMapService.getMapDetail(mapId);
List<MapStationNewVO> stationList = mapDetail.getGraphDataNew().getStationList();
}
private IscsSystemResources findEntityById(long id) { private IscsSystemResources findEntityById(long id) {
return iscsSystemResourcesDAO.selectByPrimaryKey(id); return iscsSystemResourcesDAO.selectByPrimaryKey(id);
} }

View File

@ -5,7 +5,7 @@ import club.joylink.rtss.services.audio.AudioResourcesService;
import club.joylink.rtss.services.voice.IVoiceService; import club.joylink.rtss.services.voice.IVoiceService;
import club.joylink.rtss.simulation.cbtc.Simulation; import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository; import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
import club.joylink.rtss.simulation.cbtc.data.map.Audio; import club.joylink.rtss.simulation.cbtc.data.iscs.Audio;
import club.joylink.rtss.simulation.cbtc.data.map.MapElement; import club.joylink.rtss.simulation.cbtc.data.map.MapElement;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityAudio; import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityAudio;
import club.joylink.rtss.simulation.cbtc.member.SimulationMember; import club.joylink.rtss.simulation.cbtc.member.SimulationMember;
@ -18,6 +18,9 @@ import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
/**
* ISCS交互服务
*/
@Component @Component
public class IscsInteractiveService { public class IscsInteractiveService {
@Autowired @Autowired
@ -27,7 +30,7 @@ public class IscsInteractiveService {
@Qualifier("baiDuVoiceService") @Qualifier("baiDuVoiceService")
private IVoiceService iVoiceService; private IVoiceService iVoiceService;
public void play(Simulation simulation, PlayParamVO param, SimulationMember member) { public void paPlay(Simulation simulation, PlayParamVO param, SimulationMember member) {
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(member != null && (member.isDispatcher() || member.isStationSupervisor()), BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED.assertTrue(member != null && (member.isDispatcher() || member.isStationSupervisor()),
"仅行调和行值可操作"); "仅行调和行值可操作");
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotNull(param.getResourceId(), "资源id不能为null"); BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotNull(param.getResourceId(), "资源id不能为null");
@ -47,6 +50,26 @@ public class IscsInteractiveService {
} }
} }
/**
* 信号系统自动通过PA系统播放
*/
public void paPlayBySystem(Simulation simulation, List<String> iscsDeviceCodes,
AudioResourcesVO audioResourcesVO, String state) {
SimulationDataRepository repository = simulation.getRepository();
for (String code : iscsDeviceCodes) {
MapElement element = repository.getByCode(code);
if (element instanceof Audio) {
Audio audio = (Audio) element;
audio.updateResource(audioResourcesVO);
audio.updateState(state);
audio.updateRemain(Audio.DEFAULT_REMAIN);
VirtualRealityAudio vrAudio = audio.getVrAudio();
vrAudio.updateUrl(audioResourcesVO.getUrl());
vrAudio.control(VirtualRealityAudio.Command.PLAY);
}
}
}
public void paStopPlaying(Simulation simulation, List<String> iscsDeviceCodes) { public void paStopPlaying(Simulation simulation, List<String> iscsDeviceCodes) {
SimulationDataRepository repository = simulation.getRepository(); SimulationDataRepository repository = simulation.getRepository();
for (String code : iscsDeviceCodes) { for (String code : iscsDeviceCodes) {

View File

@ -14,6 +14,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*; import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@ -190,6 +191,10 @@ public abstract class Simulation<U extends SimulationUser, M extends SimulationM
return this.systemTime; return this.systemTime;
} }
public long getSystemTimeStamp() {
return getSystemTime().toInstant(ZoneOffset.UTC).toEpochMilli();
}
/** /**
* 仿真初始化 * 仿真初始化
*/ */

View File

@ -281,12 +281,10 @@ public class ATSMessageCollectAndDispatcher {
/** /**
* 同步仿真系统时间给客户端 * 同步仿真系统时间给客户端
*
* @param simulation
*/ */
public void syncTime(Simulation simulation) { public void syncTime(Simulation simulation) {
Set<String> sessions = simulation.getSimulationUserIds(); Set<String> sessions = simulation.getSimulationUserIds();
SocketMessageVO<Integer> timeSyncMessage = SocketMessageFactory.buildSimulationTimeSyncMessage(simulation); SocketMessageVO<Long> timeSyncMessage = SocketMessageFactory.buildSimulationTimeSyncMessage(simulation);
stompMessageService.sendToUser(sessions, timeSyncMessage); stompMessageService.sendToUser(sessions, timeSyncMessage);
} }

View File

@ -23,7 +23,7 @@ public class IscsOperateHandler {
*/ */
@OperateHandlerMapping(type = Operation.Type.ISCS_PA_Play) @OperateHandlerMapping(type = Operation.Type.ISCS_PA_Play)
public void paPlay(Simulation simulation, PlayParamVO playParamVO, SimulationMember member) { public void paPlay(Simulation simulation, PlayParamVO playParamVO, SimulationMember member) {
iscsInteractiveService.play(simulation, playParamVO, member); iscsInteractiveService.paPlay(simulation, playParamVO, member);
} }
/** /**
@ -46,7 +46,7 @@ public class IscsOperateHandler {
* PIS系统停止播放 * PIS系统停止播放
*/ */
@OperateHandlerMapping(type = Operation.Type.ISCS_PIS_Stop_Playing) @OperateHandlerMapping(type = Operation.Type.ISCS_PIS_Stop_Playing)
public void pisPlay(Simulation simulation, List<String> iscsDeviceCodes) { public void pisStopPlaying(Simulation simulation, List<String> iscsDeviceCodes) {
iscsInteractiveService.pisStopPlaying(simulation, iscsDeviceCodes); iscsInteractiveService.pisStopPlaying(simulation, iscsDeviceCodes);
} }
} }

View File

@ -3,13 +3,17 @@ package club.joylink.rtss.simulation.cbtc.ISCS;
import club.joylink.rtss.simulation.cbtc.Simulation; import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants; import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants;
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository; import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
import club.joylink.rtss.simulation.cbtc.data.map.Audio; import club.joylink.rtss.simulation.cbtc.data.iscs.Audio;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component
public class IscsLogicLoop { public class IscsLogicLoop {
private void run(Simulation simulation) { public static final String JOB_NAME = "ISCS_LOGIC_LOOP";
public static final int RATE = 1000;
public void run(Simulation simulation) {
SimulationDataRepository repository = simulation.getRepository(); SimulationDataRepository repository = simulation.getRepository();
// 广播播放结束逻辑
for (Audio audio : repository.getAudioList()) { for (Audio audio : repository.getAudioList()) {
if (audio.isInPa() && !audio.isNotUsed()) { if (audio.isInPa() && !audio.isNotUsed()) {
int remain = audio.getRemainDuration(); int remain = audio.getRemainDuration();
@ -24,6 +28,6 @@ public class IscsLogicLoop {
} }
public void addJob(Simulation simulation) { public void addJob(Simulation simulation) {
simulation.addJob(Simulation.JobName.iscsLogicLoop, () -> run(simulation), SimulationConstants.ATS_LOOP_RATE); simulation.addJob(JOB_NAME, () -> run(simulation), RATE);
} }
} }

View File

@ -4,7 +4,7 @@ import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants; import club.joylink.rtss.simulation.cbtc.constant.SimulationConstants;
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository; import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
import club.joylink.rtss.simulation.cbtc.data.SimulationIscsDataRepository; import club.joylink.rtss.simulation.cbtc.data.SimulationIscsDataRepository;
import club.joylink.rtss.simulation.cbtc.data.map.Audio; import club.joylink.rtss.simulation.cbtc.data.iscs.Audio;
import club.joylink.rtss.simulation.cbtc.data.vo.iscs.IscsAudioStatusVO; import club.joylink.rtss.simulation.cbtc.data.vo.iscs.IscsAudioStatusVO;
import club.joylink.rtss.simulation.cbtc.data.vo.iscs.IscsStatusVO; import club.joylink.rtss.simulation.cbtc.data.vo.iscs.IscsStatusVO;
import club.joylink.rtss.simulation.rt.iscs.IscsStatusPublisher; import club.joylink.rtss.simulation.rt.iscs.IscsStatusPublisher;

View File

@ -141,12 +141,14 @@ public class ProjectJointSimulationServiceImpl implements ProjectJointSimulation
case PSC: case PSC:
return ((Heb1PscConfig) config).getConfig().getPsdCode(); return ((Heb1PscConfig) config).getConfig().getPsdCode();
} }
break;
} }
case XTY:{ case XTY:{
switch (config.getDeviceType()) { switch (config.getDeviceType()) {
case PSD: case PSD:
return ((XtyPsdConfig) config).getConfig().getPsdCode(); return ((XtyPsdConfig) config).getConfig().getPsdCode();
} }
break;
} }
case RICHOR_JOINT: { case RICHOR_JOINT: {
switch (config.getDeviceType()) { switch (config.getDeviceType()) {
@ -155,6 +157,7 @@ public class ProjectJointSimulationServiceImpl implements ProjectJointSimulation
case PSL: case PSL:
return ((ZjdPslConfig) config).getConfigVO().getPslCode(); return ((ZjdPslConfig) config).getConfigVO().getPslCode();
} }
break;
} }
case SR_SANDBOX: { case SR_SANDBOX: {
switch (config.getDeviceType()) { switch (config.getDeviceType()) {
@ -167,6 +170,7 @@ public class ProjectJointSimulationServiceImpl implements ProjectJointSimulation
case TRAIN: case TRAIN:
return ((SrTrainConfig) config).getConfigVO().getVrCode(); return ((SrTrainConfig) config).getConfigVO().getVrCode();
} }
break;
} }
case RICHOR_HHCJ: { case RICHOR_HHCJ: {
switch (config.getDeviceType()) { switch (config.getDeviceType()) {
@ -175,6 +179,7 @@ public class ProjectJointSimulationServiceImpl implements ProjectJointSimulation
case PSD: case PSD:
return ((HhcjPsdConfig) config).getConfigVO().getPsdCode(); return ((HhcjPsdConfig) config).getConfigVO().getPsdCode();
} }
break;
} }
} }
return null; return null;

View File

@ -39,6 +39,7 @@ import org.springframework.util.CollectionUtils;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
@ -497,6 +498,13 @@ public class Simulation extends club.joylink.rtss.simulation.Simulation<Simulati
return this.getSystemTime().plusHours(SimulationConstants.RUN_DIAGRAM_TRANS_TIME); return this.getSystemTime().plusHours(SimulationConstants.RUN_DIAGRAM_TRANS_TIME);
} }
/**
* 获取仿真正确时间在系统默认时区的时间戳
*/
public long getCorrectSystemTimeStamp() {
return getCorrectSystemTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
}
// /** // /**
// * 仿真异常信息 // * 仿真异常信息
// * // *

View File

@ -34,8 +34,10 @@ import club.joylink.rtss.simulation.cbtc.fault.FaultGenerator;
import club.joylink.rtss.simulation.cbtc.member.MemberManager; import club.joylink.rtss.simulation.cbtc.member.MemberManager;
import club.joylink.rtss.simulation.cbtc.onboard.ATP.ATPLogicLoop; import club.joylink.rtss.simulation.cbtc.onboard.ATP.ATPLogicLoop;
import club.joylink.rtss.simulation.cbtc.onboard.TrainTargetUpdateService; import club.joylink.rtss.simulation.cbtc.onboard.TrainTargetUpdateService;
import club.joylink.rtss.simulation.cbtc.pis.PisLogicLoop;
import club.joylink.rtss.simulation.cbtc.robot.SimulationRobotService; import club.joylink.rtss.simulation.cbtc.robot.SimulationRobotService;
import club.joylink.rtss.simulation.rt.iscs.IscsStatusPublisher; import club.joylink.rtss.simulation.rt.iscs.IscsStatusPublisher;
import club.joylink.rtss.simulation.rt.pis.PisStatusPublisher;
import club.joylink.rtss.vo.client.iscs.device.IscsDeviceVO; import club.joylink.rtss.vo.client.iscs.device.IscsDeviceVO;
import club.joylink.rtss.vo.client.iscs.systemRes.IscsSystemResourcesQueryVO; import club.joylink.rtss.vo.client.iscs.systemRes.IscsSystemResourcesQueryVO;
import club.joylink.rtss.vo.client.iscs.systemRes.IscsSystemResourcesVO; import club.joylink.rtss.vo.client.iscs.systemRes.IscsSystemResourcesVO;
@ -139,6 +141,9 @@ public class SimulationLifeCycleServiceImpl implements SimulationLifeCycleServic
@Autowired @Autowired
private GroupSimulationService groupSimulationService; private GroupSimulationService groupSimulationService;
@Autowired
private PisLogicLoop pisLogicLoop;
@Override @Override
public Simulation create(SimulationBuildParams params, String group) { public Simulation create(SimulationBuildParams params, String group) {
// 构建仿真 // 构建仿真
@ -163,8 +168,6 @@ public class SimulationLifeCycleServiceImpl implements SimulationLifeCycleServic
} }
// 缓存 // 缓存
simulationManager.save(simulation); simulationManager.save(simulation);
// TODO: 2021/9/10 暂时放在这里
simulation.addMessagePublisher(new IscsStatusPublisher(simulation));
// 初始化设备状态 // 初始化设备状态
deviceStatusService.init(simulation); deviceStatusService.init(simulation);
depotService.loadDepotTrain(simulation); depotService.loadDepotTrain(simulation);
@ -173,12 +176,19 @@ public class SimulationLifeCycleServiceImpl implements SimulationLifeCycleServic
// 初始化语音指令 // 初始化语音指令
List<VoiceCommandBO> voiceCommandBOList = iVoiceCommandService.getAll(); List<VoiceCommandBO> voiceCommandBOList = iVoiceCommandService.getAll();
simulation.setVoiceCommandBOList(voiceCommandBOList); simulation.setVoiceCommandBOList(voiceCommandBOList);
// 添加消息发送器
addMessagePublisher(simulation);
// 添加任务 // 添加任务
addJobs(simulation); addJobs(simulation);
applicationContext.publishEvent(new SimulationCreateSuccessEvent(this, simulation)); applicationContext.publishEvent(new SimulationCreateSuccessEvent(this, simulation));
return simulation; return simulation;
} }
private void addMessagePublisher(Simulation simulation) {
simulation.addMessagePublisher(new IscsStatusPublisher(simulation));
simulation.addMessagePublisher(new PisStatusPublisher(simulation));
}
private void addJobs(Simulation simulation) { private void addJobs(Simulation simulation) {
if(simulation.getBuildParams().getProdType() == MapPrdTypeEnum.YJDDZH){ if(simulation.getBuildParams().getProdType() == MapPrdTypeEnum.YJDDZH){
//非武汉大屏车辆定位 //非武汉大屏车辆定位
@ -201,6 +211,7 @@ public class SimulationLifeCycleServiceImpl implements SimulationLifeCycleServic
iVirtualRealityPslService.addJobs(simulation); iVirtualRealityPslService.addJobs(simulation);
iscsMessageCollectAndDispatcher.addJob(simulation); iscsMessageCollectAndDispatcher.addJob(simulation);
iscsLogicLoop.addJob(simulation); iscsLogicLoop.addJob(simulation);
pisLogicLoop.addJobs(simulation);
} }
atpLogicLoop.addJobs(simulation); atpLogicLoop.addJobs(simulation);
atsLogicLoop.addJobs(simulation); atsLogicLoop.addJobs(simulation);

View File

@ -3,11 +3,11 @@ package club.joylink.rtss.simulation.cbtc.build;
import club.joylink.rtss.entity.Ibp; import club.joylink.rtss.entity.Ibp;
import club.joylink.rtss.simulation.cbtc.CI.data.StationDirection; import club.joylink.rtss.simulation.cbtc.CI.data.StationDirection;
import club.joylink.rtss.simulation.cbtc.CTC.data.*; import club.joylink.rtss.simulation.cbtc.CTC.data.*;
import club.joylink.rtss.simulation.cbtc.Simulation; import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.data.CalculateService; import club.joylink.rtss.simulation.cbtc.data.CalculateService;
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository; import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
import club.joylink.rtss.simulation.cbtc.data.SimulationIscsDataRepository; import club.joylink.rtss.simulation.cbtc.data.SimulationIscsDataRepository;
import club.joylink.rtss.simulation.cbtc.data.iscs.Audio;
import club.joylink.rtss.simulation.cbtc.data.map.*; import club.joylink.rtss.simulation.cbtc.data.map.*;
import club.joylink.rtss.simulation.cbtc.data.plan.TerminalDeparturePlan; import club.joylink.rtss.simulation.cbtc.data.plan.TerminalDeparturePlan;
import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan; import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;

View File

@ -5,6 +5,7 @@ import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.cbtc.ATS.data.AtsAlarm; import club.joylink.rtss.simulation.cbtc.ATS.data.AtsAlarm;
import club.joylink.rtss.simulation.cbtc.Simulation; import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.communication.vo.TrainHmiDisplay; import club.joylink.rtss.simulation.cbtc.communication.vo.TrainHmiDisplay;
import club.joylink.rtss.simulation.cbtc.data.iscs.Audio;
import club.joylink.rtss.simulation.cbtc.data.map.*; import club.joylink.rtss.simulation.cbtc.data.map.*;
import club.joylink.rtss.simulation.cbtc.data.plan.RealRun; import club.joylink.rtss.simulation.cbtc.data.plan.RealRun;
import club.joylink.rtss.simulation.cbtc.data.plan.SchedulingTrainPlan; import club.joylink.rtss.simulation.cbtc.data.plan.SchedulingTrainPlan;
@ -852,6 +853,7 @@ public class SimulationDataRepository {
/** /**
* 此方法只能用于计划车次号唯一的线路比如西门子风格的运行计划 * 此方法只能用于计划车次号唯一的线路比如西门子风格的运行计划
*
* @param tripNumber * @param tripNumber
* @return * @return
*/ */
@ -1242,6 +1244,18 @@ public class SimulationDataRepository {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
public Stream<Audio> getAudioStream() {
return deviceMap.values().stream()
.filter(device -> device instanceof Audio)
.map(device -> (Audio) device);
}
public List<Audio> getAudioList(Station station) {
return getAudioStream()
.filter(audio -> Objects.equals(audio.getStation(), station))
.collect(Collectors.toList());
}
public List<Audio> getAudioList(IscsSystem system, IscsDeviceVO.Position position) { public List<Audio> getAudioList(IscsSystem system, IscsDeviceVO.Position position) {
Stream<Audio> stream = deviceMap.values().stream() Stream<Audio> stream = deviceMap.values().stream()
.filter(device -> device instanceof Audio) .filter(device -> device instanceof Audio)

View File

@ -2,9 +2,14 @@ package club.joylink.rtss.simulation.cbtc.data;
import club.joylink.rtss.constants.IscsSystem; import club.joylink.rtss.constants.IscsSystem;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum; import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.cbtc.data.info.OnboardPis;
import club.joylink.rtss.simulation.cbtc.data.info.StandPis;
import club.joylink.rtss.simulation.cbtc.data.status.OnboardPisStatus;
import club.joylink.rtss.simulation.cbtc.data.status.StandPisStatus;
import club.joylink.rtss.simulation.cbtc.data.vo.iscs.IscsStatusVO; import club.joylink.rtss.simulation.cbtc.data.vo.iscs.IscsStatusVO;
import club.joylink.rtss.vo.client.audio.AudioResourcesVO; import club.joylink.rtss.vo.client.audio.AudioResourcesVO;
import club.joylink.rtss.vo.client.iscs.systemRes.IscsSystemResourcesVO; import club.joylink.rtss.vo.client.iscs.systemRes.IscsSystemResourcesVO;
import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -13,12 +18,32 @@ import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@Getter
@NoArgsConstructor @NoArgsConstructor
public class SimulationIscsDataRepository { public class SimulationIscsDataRepository {
private final Map<String, IscsStatusVO> statusVOMap = new HashMap<>(); private final Map<String, IscsStatusVO> statusVOMap = new HashMap<>();
private final List<IscsSystemResourcesVO> systemResources = new ArrayList<>(); private final List<IscsSystemResourcesVO> systemResources = new ArrayList<>();
/**
* k - name
*/
private final Map<String, AudioResourcesVO> audioResourcesVOMap = new HashMap<>();
/**
* k - groupNumber
*/
private final Map<String, OnboardPis> onBoardPisMap = new HashMap<>();
/**
* k - standCode
*/
private final Map<String, StandPis> standPisMap = new HashMap<>();
private final Map<String, OnboardPisStatus> onboardPisStatusMap = new HashMap<>();
private final Map<String, StandPisStatus> standPisStatusMap = new HashMap<>();
public IscsStatusVO findStatus(String iscsCode) { public IscsStatusVO findStatus(String iscsCode) {
return statusVOMap.get(iscsCode); return statusVOMap.get(iscsCode);
} }
@ -67,14 +92,27 @@ public class SimulationIscsDataRepository {
throw BusinessExceptionAssertEnum.DATA_NOT_EXIST.exception(String.format("id为[%s]的资源不存在", resourceId)); throw BusinessExceptionAssertEnum.DATA_NOT_EXIST.exception(String.format("id为[%s]的资源不存在", resourceId));
} }
public AudioResourcesVO findAudioResource(String name) {
return audioResourcesVOMap.get(name);
}
public void addSystemResources(List<IscsSystemResourcesVO> resourcesVOS) { public void addSystemResources(List<IscsSystemResourcesVO> resourcesVOS) {
if (!CollectionUtils.isEmpty(resourcesVOS)) { if (!CollectionUtils.isEmpty(resourcesVOS)) {
systemResources.addAll(resourcesVOS); systemResources.addAll(resourcesVOS);
resourcesVOS.stream()
.filter(iscsSystemResourcesVO -> !IscsSystemResourcesVO.Type.REAL_TIME.equals(iscsSystemResourcesVO.getType()))
.flatMap(iscsSystemResourcesVO -> iscsSystemResourcesVO.getResources().stream())
.filter(Objects::nonNull)
.forEach(audioResourcesVO -> audioResourcesVOMap.put(audioResourcesVO.getName(), audioResourcesVO));
} }
} }
public void reset() { public void reset() {
this.statusVOMap.clear(); this.statusVOMap.clear();
this.systemResources.removeIf(vo -> IscsSystemResourcesVO.Type.REAL_TIME.equals(vo.getType())); this.systemResources.removeIf(vo -> IscsSystemResourcesVO.Type.REAL_TIME.equals(vo.getType()));
this.onBoardPisMap.clear();
this.onboardPisStatusMap.clear();
this.standPisMap.clear();
this.standPisStatusMap.clear();
} }
} }

View File

@ -0,0 +1,46 @@
package club.joylink.rtss.simulation.cbtc.data.info;
import club.joylink.rtss.simulation.cbtc.data.map.Station;
import lombok.Getter;
/**
* 车载Pis
*/
@Getter
public class OnboardPis {
private String groupNumber;
/**
* 下一抵达车站
*/
private Station nextStation;
/**
* 终点站
*/
private Station endStation;
public OnboardPis(String groupNumber, Station nextStation, Station endStation) {
this.groupNumber = groupNumber;
this.nextStation = nextStation;
this.endStation = endStation;
}
public String getNextStationName() {
return nextStation == null ? "" : nextStation.getName();
}
public String getEndStationName() {
return endStation == null ? "" : endStation.getName();
}
public void update(Station nextStation, Station endStation) {
this.nextStation = nextStation;
this.endStation = endStation;
}
public void clear() {
nextStation = null;
endStation = null;
}
}

View File

@ -0,0 +1,106 @@
package club.joylink.rtss.simulation.cbtc.data.info;
import club.joylink.rtss.simulation.cbtc.data.map.Stand;
import club.joylink.rtss.simulation.cbtc.data.map.Station;
import club.joylink.rtss.simulation.cbtc.data.vo.TrainInfo;
import lombok.Getter;
import lombok.Setter;
/**
* 站台Pis
*/
@Getter
public class StandPis {
private Stand stand;
/**
* 本站
*/
private Station station;
private TrainInfo firstTrain;
/**
* 第一辆车预计进站时间/m
* 剩余时间为1时表示 即将进站
* 剩余时间为0时表示 列车进站
*/
private Integer firstTrainRemain;
/**
* 第一辆车的终点站
*/
private Station firstEndStation;
private TrainInfo secondTrain;
/**
* 第二辆车预计进站时间/m
*/
private Integer secondTrainRemain;
/**
* 第二辆车的终点站
*/
private Station secondEndStation;
/**
* 最后一个即将进站的列车播报了即将进站语音的列车
*/
@Setter
private TrainInfo lastComingTrain;
public StandPis(Stand stand, Station station) {
this.stand = stand;
this.station = station;
}
public String getFirstEndStationName() {
return firstEndStation == null ? "" : firstEndStation.getName();
}
public String getSecondEndStationName() {
return secondEndStation == null ? "" : secondEndStation.getName();
}
public void clear() {
firstTrainRemain = null;
firstEndStation = null;
secondTrainRemain = null;
secondEndStation = null;
}
/**
* 替换将参数中的剩余时间与当前记录的两辆列车的信息做比较留下时间更短的两个
*/
public void replace(TrainInfo train, Integer remain, Station endStation) {
if (firstTrainRemain == null) {
firstTrain = train;
firstTrainRemain = remain;
firstEndStation = endStation;
} else if (secondTrainRemain == null) {
secondTrain = train;
secondTrainRemain = remain;
secondEndStation = endStation;
} else {
if (remain < firstTrainRemain) {
secondTrain = firstTrain;
secondTrainRemain = firstTrainRemain;
secondEndStation = firstEndStation;
firstTrain = train;
firstTrainRemain = remain;
firstEndStation = endStation;
} else if (remain < secondTrainRemain) {
secondTrain = train;
secondTrainRemain = remain;
secondEndStation = endStation;
}
}
}
/**
* 第一趟列车即将进站
*/
public boolean firstTrainIsComing() {
return firstTrainRemain == 1;
}
}

View File

@ -1,6 +1,8 @@
package club.joylink.rtss.simulation.cbtc.data.map; package club.joylink.rtss.simulation.cbtc.data.iscs;
import club.joylink.rtss.constants.IscsSystem; import club.joylink.rtss.constants.IscsSystem;
import club.joylink.rtss.simulation.cbtc.data.map.MapElement;
import club.joylink.rtss.simulation.cbtc.data.map.Station;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityAudio; import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityAudio;
import club.joylink.rtss.vo.client.audio.AudioResourcesVO; import club.joylink.rtss.vo.client.audio.AudioResourcesVO;
import club.joylink.rtss.vo.client.iscs.device.IscsDeviceVO; import club.joylink.rtss.vo.client.iscs.device.IscsDeviceVO;
@ -13,7 +15,7 @@ import java.util.Objects;
* 广播 * 广播
*/ */
@Getter @Getter
public class Audio extends MapElement{ public class Audio extends MapElement {
private IscsSystem system; private IscsSystem system;
private Station station; private Station station;
@ -50,6 +52,10 @@ public class Audio extends MapElement{
} }
} }
public String getUrl() {
return vrAudio.getUrl();
}
public void updateResource(AudioResourcesVO resource) { public void updateResource(AudioResourcesVO resource) {
this.resource = resource; this.resource = resource;
} }

View File

@ -1,10 +1,12 @@
package club.joylink.rtss.simulation.cbtc.data.plan; package club.joylink.rtss.simulation.cbtc.data.plan;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.cbtc.data.map.Section; import club.joylink.rtss.simulation.cbtc.data.map.Section;
import club.joylink.rtss.simulation.cbtc.data.map.Stand; import club.joylink.rtss.simulation.cbtc.data.map.Stand;
import club.joylink.rtss.simulation.cbtc.data.map.Station; import club.joylink.rtss.simulation.cbtc.data.map.Station;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.NonNull;
import lombok.Setter; import lombok.Setter;
import java.time.LocalTime; import java.time.LocalTime;
@ -494,4 +496,10 @@ public class TripPlan {
} }
return plan1.getStartTime().compareTo(plan2.getStartTime()); return plan1.getStartTime().compareTo(plan2.getStartTime());
} }
public List<StationPlan> getSubList(@NonNull StationPlan stationPlan) {
int startIndex = planList.indexOf(stationPlan);
BusinessExceptionAssertEnum.ARGUMENT_ILLEGAL.assertTrue(startIndex != -1);
return planList.subList(startIndex, planList.size());
}
} }

View File

@ -0,0 +1,57 @@
package club.joylink.rtss.simulation.cbtc.data.status;
import club.joylink.rtss.simulation.Watchable;
import club.joylink.rtss.simulation.cbtc.data.info.OnboardPis;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.Objects;
/**
* 车载pis状态
*/
@Getter
@Setter
@NoArgsConstructor
public class OnboardPisStatus extends Watchable {
/**
* 列车编号
*/
private String groupNumber;
/**
* 下一站的站名
*/
private String nextStationName;
/**
* 终点站的站名
*/
private String endStationName;
public OnboardPisStatus(OnboardPis pis) {
this.groupNumber = pis.getGroupNumber();
this.nextStationName = pis.getNextStationName();
this.endStationName = pis.getNextStationName();
}
public OnboardPisStatus compareAndChange(OnboardPis pis) {
boolean change = false;
OnboardPisStatus changeStatus = new OnboardPisStatus();
changeStatus.setGroupNumber(groupNumber);
if (Objects.equals(nextStationName, pis.getNextStationName())) {
nextStationName = pis.getNextStationName();
change = true;
changeStatus.setNextStationName(nextStationName);
}
if (!Objects.equals(endStationName, pis.getEndStationName())) {
endStationName = pis.getEndStationName();
change = true;
changeStatus.setEndStationName(endStationName);
}
return change ? changeStatus : null;
}
}

View File

@ -0,0 +1,99 @@
package club.joylink.rtss.simulation.cbtc.data.status;
import club.joylink.rtss.simulation.Watchable;
import club.joylink.rtss.simulation.cbtc.data.info.StandPis;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.Objects;
/**
* 站台pis状态
*/
@Getter
@Setter
@NoArgsConstructor
public class StandPisStatus extends Watchable {
/**
* 该Pis信息所属的站台的code
*/
private String standCode;
/**
* 当前车站的名称
*/
@JsonInclude
private String stationName;
/**
* 第一辆车预计进站时间/m
*/
@JsonInclude
private Integer firstTrainRemain;
/**
* 第一辆车的终点站的名称
*/
private String firstEndStationName;
/**
* 第二辆车预计进站时间/m
*/
@JsonInclude
private Integer secondTrainRemain;
/**
* 第二辆车的终点站的名称
*/
private String secondEndStationName;
public StandPisStatus(StandPis pis) {
this.standCode = pis.getStand().getCode();
this.stationName = pis.getStation().getName();
this.firstTrainRemain = pis.getFirstTrainRemain();
this.firstEndStationName = pis.getFirstEndStationName();
this.secondTrainRemain = pis.getSecondTrainRemain();
this.secondEndStationName = pis.getSecondEndStationName();
}
public StandPisStatus compareAndChange(StandPis pis) {
boolean change = false;
StandPisStatus changeStatus = new StandPisStatus();
changeStatus.setStandCode(standCode);
if (!Objects.equals(stationName, pis.getStation().getName())) {
stationName = pis.getStation().getName();
change = true;
changeStatus.setStationName(stationName);
}
if (!Objects.equals(firstTrainRemain, pis.getFirstTrainRemain())) {
firstTrainRemain = pis.getFirstTrainRemain();
change = true;
changeStatus.setFirstTrainRemain(firstTrainRemain);
}
if (!Objects.equals(firstEndStationName, pis.getFirstEndStationName())) {
firstEndStationName = pis.getFirstEndStationName();
change = true;
changeStatus.setFirstEndStationName(firstEndStationName);
}
if (!Objects.equals(secondTrainRemain, pis.getSecondTrainRemain())) {
secondTrainRemain = pis.getSecondTrainRemain();
change = true;
changeStatus.setSecondTrainRemain(secondTrainRemain);
}
if (!Objects.equals(secondEndStationName, pis.getSecondEndStationName())) {
secondEndStationName = pis.getSecondEndStationName();
change = true;
changeStatus.setSecondEndStationName(secondEndStationName);
}
if (change) {
changeStatus.setFirstTrainRemain(firstTrainRemain);
changeStatus.setSecondTrainRemain(secondTrainRemain);
return changeStatus;
}
return null;
}
}

View File

@ -31,7 +31,7 @@ public class SimulationVO {
private Simulation.FunctionalType type; private Simulation.FunctionalType type;
private int systemTime; private long systemTime;
/** 数据是否存在错误 */ /** 数据是否存在错误 */
private boolean dataError; private boolean dataError;
@ -71,7 +71,6 @@ public class SimulationVO {
creator.setId(user.getId()); creator.setId(user.getId());
creator.setName(user.getName()); creator.setName(user.getName());
creator.setNickname(user.getNickname()); creator.setNickname(user.getNickname());
int systemTime = simulation.getCorrectSystemTime().toLocalTime().toSecondOfDay();
return SimulationVO.builder() return SimulationVO.builder()
.group(simulation.getId()) .group(simulation.getId())
.map(mapVO) .map(mapVO)
@ -81,7 +80,7 @@ public class SimulationVO {
.prodType(Objects.nonNull(simulation.getBuildParams().getProdType()) ? simulation.getBuildParams().getProdType().getCode() : null) .prodType(Objects.nonNull(simulation.getBuildParams().getProdType()) ? simulation.getBuildParams().getProdType().getCode() : null)
.dataError(simulation.isMapDataError() || simulation.isPlanDataError()) .dataError(simulation.isMapDataError() || simulation.isPlanDataError())
.errorMsgList(simulation.getDataErrMsgList()) .errorMsgList(simulation.getDataErrMsgList())
.systemTime(systemTime) .systemTime(simulation.getCorrectSystemTimeStamp())
.planRunning(simulation.isPlanRunning()) .planRunning(simulation.isPlanRunning())
.scriptId(Objects.isNull(simulation.getScript()) ? null : simulation.getScript().getId()) .scriptId(Objects.isNull(simulation.getScript()) ? null : simulation.getScript().getId())
.pause(simulation.isPause()) .pause(simulation.isPause())

View File

@ -1,7 +1,7 @@
package club.joylink.rtss.simulation.cbtc.data.vo.iscs; package club.joylink.rtss.simulation.cbtc.data.vo.iscs;
import club.joylink.rtss.constants.IscsSystem; import club.joylink.rtss.constants.IscsSystem;
import club.joylink.rtss.simulation.cbtc.data.map.Audio; import club.joylink.rtss.simulation.cbtc.data.iscs.Audio;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter; import lombok.Getter;
@ -14,6 +14,8 @@ public class IscsAudioStatusVO extends IscsStatusVO{
private String state; private String state;
private String url;
@JsonIgnore @JsonIgnore
public boolean isPaSystem() { public boolean isPaSystem() {
return IscsSystem.PA.equals(system); return IscsSystem.PA.equals(system);
@ -28,6 +30,7 @@ public class IscsAudioStatusVO extends IscsStatusVO{
super(audio.getCode(), DeviceType.AUDIO, audio.getStation().getCode()); super(audio.getCode(), DeviceType.AUDIO, audio.getStation().getCode());
this.system = audio.getSystem(); this.system = audio.getSystem();
this.state = audio.getState(); this.state = audio.getState();
this.url = audio.getUrl();
} }
public boolean compareAndChange(Audio audio) { public boolean compareAndChange(Audio audio) {
@ -36,6 +39,10 @@ public class IscsAudioStatusVO extends IscsStatusVO{
this.state = audio.getState(); this.state = audio.getState();
change = true; change = true;
} }
if (!Objects.equals(this.url, audio.getUrl())) {
this.url = audio.getUrl();
change = true;
}
return change; return change;
} }
} }

View File

@ -0,0 +1,200 @@
package club.joylink.rtss.simulation.cbtc.pis;
import club.joylink.rtss.services.iscs.interactive.IscsInteractiveService;
import club.joylink.rtss.simulation.cbtc.Simulation;
import club.joylink.rtss.simulation.cbtc.data.SimulationDataRepository;
import club.joylink.rtss.simulation.cbtc.data.SimulationIscsDataRepository;
import club.joylink.rtss.simulation.cbtc.data.info.OnboardPis;
import club.joylink.rtss.simulation.cbtc.data.info.StandPis;
import club.joylink.rtss.simulation.cbtc.data.iscs.Audio;
import club.joylink.rtss.simulation.cbtc.data.map.MapElement;
import club.joylink.rtss.simulation.cbtc.data.map.Section;
import club.joylink.rtss.simulation.cbtc.data.map.Stand;
import club.joylink.rtss.simulation.cbtc.data.map.Station;
import club.joylink.rtss.simulation.cbtc.data.plan.StationPlan;
import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;
import club.joylink.rtss.simulation.cbtc.data.status.OnboardPisStatus;
import club.joylink.rtss.simulation.cbtc.data.status.StandPisStatus;
import club.joylink.rtss.simulation.cbtc.data.vo.TrainInfo;
import club.joylink.rtss.vo.client.audio.AudioResourcesVO;
import club.joylink.rtss.vo.client.iscs.device.IscsDeviceVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* Pis系统逻辑循环
*/
@Component
public class PisLogicLoop {
public static final String LOGIC_JOB_NAME = "PIS_LOGIC";
public static final int RATE = 1000;
public static final String MESSAGE_JOB_NAME = "PIS_MESSAGE";
@Autowired
private IscsInteractiveService iscsInteractiveService;
public void run(Simulation simulation) {
SimulationDataRepository repository = simulation.getRepository();
SimulationIscsDataRepository iscsRepository = simulation.getIscsRepository();
Map<String, OnboardPis> onBoardPisMap = iscsRepository.getOnBoardPisMap();
onBoardPisMap.values().forEach(OnboardPis::clear); //清除过期数据
Map<String, StandPis> standPisMap = iscsRepository.getStandPisMap();
standPisMap.values().forEach(StandPis::clear); //清除过期数据
List<TrainInfo> superviseTrainList = repository.getSuperviseTrainList();
for (TrainInfo trainInfo : superviseTrainList) {
// 车载PIS信息更新逻辑
//下一站
Station nextStation = null;
String nextStandTrackCode = trainInfo.getEstimatedArriveStandTrack();
if (StringUtils.hasText(nextStandTrackCode)) {
Section standTrack = repository.getByCode(nextStandTrackCode, Section.class);
List<Stand> standList = standTrack.getStandList();
if (!CollectionUtils.isEmpty(standList)) {
nextStation = standList.get(0).getStation();
}
}
//终点站
Station endStation = null;
if (StringUtils.hasText(trainInfo.getEndStation())) {
endStation = repository.getByCode(trainInfo.getEndStation(), Station.class);
}
OnboardPis onboardPis = onBoardPisMap.get(trainInfo.getGroupNumber());
if (onboardPis != null) {
onboardPis.update(nextStation, endStation);
} else {
onboardPis = new OnboardPis(trainInfo.getGroupNumber(), nextStation, endStation);
onBoardPisMap.put(onboardPis.getGroupNumber(), onboardPis);
}
//站台PIS信息更新
TripPlan tripPlan = repository.queryTripPlan(trainInfo.getTripNumber());
if (tripPlan == null)
continue;
List<StationPlan> planList = tripPlan.getPlanList();
int index;
StandPis standPis = null;
if (trainInfo.isParking()) { //当列车停站时剩余时间计算方式与通常不同必须为0所以独立出来
StationPlan stationPlan = tripPlan.queryStationPlan(trainInfo.getActualArriveStandTrack());
if (stationPlan != null) {
List<Stand> standList = stationPlan.getSection().getStandList();
if (!CollectionUtils.isEmpty(standList)) {
Stand stand = standList.get(0);
if (!stand.isSmall()) {
standPis = standPisMap.computeIfAbsent(stand.getCode(), k -> new StandPis(stand, stationPlan.getStation()));
standPis.replace(trainInfo, 0, endStation);
}
index = planList.indexOf(stationPlan) + 1;
} else {
index = tripPlan.getPlanIndex(trainInfo.getEstimatedArriveStandTrack());
}
} else {
index = tripPlan.getPlanIndex(trainInfo.getEstimatedArriveStandTrack());
}
} else {
index = tripPlan.getPlanIndex(trainInfo.getEstimatedArriveStandTrack());
if (index != -1) {
StationPlan stationPlan = tripPlan.getPlanList().get(index);
if (stationPlan.getSection().getCode().equals(trainInfo.getPhysicalSection())) {
List<Stand> standList = stationPlan.getSection().getStandList();
if (!CollectionUtils.isEmpty(standList)) {
Stand stand = standList.get(0);
if (!stand.isSmall()) {
standPis = standPisMap.computeIfAbsent(stand.getCode(), k -> new StandPis(stand, stationPlan.getStation()));
standPis.replace(trainInfo, 1, endStation);
index++;
}
}
}
}
}
if (index != -1) {
for (StationPlan plan : planList.subList(index, planList.size())) { //遍历未完成的计划
long seconds = Duration.between(simulation.getSystemTime().toLocalTime(), plan.getArriveTime()).toSeconds();
int remain = (int) (Math.ceil(seconds / 60f)); //剩余秒数转分钟后向上取整
remain = Math.max(2, remain); //因为remain==0表示列车已经进站所以列车没停站时remain不可以==0
List<Stand> standList = plan.getSection().getStandList();
if (!CollectionUtils.isEmpty(standList)) {
Stand stand = standList.get(0);
if (!stand.isSmall()) {
standPis = standPisMap.computeIfAbsent(stand.getCode(), k -> new StandPis(stand, plan.getStation()));
standPis.replace(trainInfo, remain, endStation);
}
}
}
}
// 即将到站语音播报
if (standPis != null) {
if (standPis.firstTrainIsComing()
&& !Objects.equals(trainInfo, standPis.getLastComingTrain())
&& Objects.equals(trainInfo, standPis.getFirstTrain())) { //列车即将进站且没有播报过
String resourceName = String.format("开往%s方向的列车即将进站", standPis.getFirstEndStationName());
AudioResourcesVO audioResource = iscsRepository.findAudioResource(resourceName);
if (audioResource != null) {
boolean up = repository.getConfig().isUp(standPis.getStand().isRight()); //判断站台上下行
IscsDeviceVO.Position audioPosition = up ? IscsDeviceVO.Position.UP_STAND : IscsDeviceVO.Position.DOWN_STAND;
List<String> audioCodes = repository.getAudioList(standPis.getStation()).stream()
.filter(audio -> Objects.equals(audio.getPosition(), audioPosition))
.map(MapElement::getCode)
.collect(Collectors.toList());
if (!CollectionUtils.isEmpty(audioCodes)) {
iscsInteractiveService.paPlayBySystem(simulation, audioCodes, audioResource, Audio.State.STATION_NORMAL);
standPis.setLastComingTrain(trainInfo);
}
}
}
}
}
}
public void updateStatusAndSend(Simulation simulation) {
SimulationIscsDataRepository iscsRepository = simulation.getIscsRepository();
Map<String, OnboardPis> onBoardPisMap = iscsRepository.getOnBoardPisMap();
Map<String, OnboardPisStatus> onboardPisStatusMap = iscsRepository.getOnboardPisStatusMap();
for (OnboardPis value : onBoardPisMap.values()) {
OnboardPisStatus status = onboardPisStatusMap.get(value.getGroupNumber());
OnboardPisStatus changed;
if (status == null) {
status = new OnboardPisStatus(value);
onboardPisStatusMap.put(status.getGroupNumber(), status);
changed = status;
} else {
changed = status.compareAndChange(value);
}
if (changed != null) {
changed.fireWatcher(null, null);
}
}
Map<String, StandPis> standPisMap = iscsRepository.getStandPisMap();
Map<String, StandPisStatus> standPisStatusMap = iscsRepository.getStandPisStatusMap();
for (StandPis value : standPisMap.values()) {
StandPisStatus status = standPisStatusMap.get(value.getStand().getCode());
StandPisStatus changed;
if (status == null) {
status = new StandPisStatus(value);
standPisStatusMap.put(status.getStandCode(), status);
changed = status;
} else {
changed = status.compareAndChange(value);
}
if (changed != null) {
changed.fireWatcher(null, null);
}
}
}
public void addJobs(Simulation simulation) {
simulation.addJobIfAbsent(LOGIC_JOB_NAME, () -> run(simulation), RATE);
simulation.addFixedRateJob(MESSAGE_JOB_NAME, () -> updateStatusAndSend(simulation), RATE);
}
}

View File

@ -0,0 +1,70 @@
package club.joylink.rtss.simulation.rt.pis;
import club.joylink.rtss.simulation.Simulation;
import club.joylink.rtss.simulation.SimulationTriggerMessagePublisher;
import club.joylink.rtss.simulation.Watchable;
import club.joylink.rtss.simulation.cbtc.data.status.OnboardPisStatus;
import club.joylink.rtss.simulation.cbtc.data.status.StandPisStatus;
import java.util.*;
/**
* Pis状态发布
*/
public class PisStatusPublisher extends SimulationTriggerMessagePublisher {
public static final String NAME = "PisMP";
public static final String STAND_PIS_PATH = "standPis";
public static final String STAND_PIS_PATTERN = String.format("%s/%s/%s", Simulation.MESSAGE_SUB_PREFIX, STAND_PIS_PATH, "{standCode}");
public static final String ONBOARD_PIS_PATH = "onboardPis";
public static final String ONBOARD_PIS_PATTERN = String.format("%s/%s/%s", Simulation.MESSAGE_SUB_PREFIX, ONBOARD_PIS_PATH, "{groupNumber}");
private club.joylink.rtss.simulation.cbtc.Simulation simulation;
public PisStatusPublisher(club.joylink.rtss.simulation.cbtc.Simulation simulation) {
super(NAME, List.of(STAND_PIS_PATTERN, ONBOARD_PIS_PATTERN));
this.simulation = simulation;
}
@Override
public Object buildMessageOfSubscribe(String destination) {
List<String> list = this.getDestinationParamsMap().get(destination);
Object result = null;
if (destination.contains(STAND_PIS_PATH)) {
String standCode = list.get(1);
result = simulation.getIscsRepository().getStandPisStatusMap().get(standCode);
} else if (destination.contains(ONBOARD_PIS_PATH)) {
String groupNumber = list.get(1);
result = simulation.getIscsRepository().getOnboardPisStatusMap().get(groupNumber);
}
return result;
}
@Override
public List<String> getNeedBuildDestination(Watchable watchable) {
List<String> list = new ArrayList<>();
for (Map.Entry<String, List<String>> entry : this.getDestinationParamsMap().entrySet()) {
String destination = entry.getKey();
List<String> param = entry.getValue();
if (watchable instanceof OnboardPisStatus) {
if (param.get(1).equals(((OnboardPisStatus) watchable).getGroupNumber())) {
list.add(destination);
}
} else if (watchable instanceof StandPisStatus) {
if (param.get(1).equals(((StandPisStatus) watchable).getStandCode())) {
list.add(destination);
}
}
}
return list;
}
@Override
public Object buildMessage(Watchable watchable) {
Map<String, Object> map = new HashMap<>();
if (watchable instanceof OnboardPisStatus) {
map.put("onboardPis", Collections.singletonList(watchable));
} else if (watchable instanceof StandPisStatus) {
map.put("standPis", Collections.singletonList(watchable));
}
return map;
}
}

View File

@ -9,6 +9,7 @@ import lombok.Setter;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.groups.Default;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -19,6 +20,9 @@ import java.util.stream.Collectors;
@NoArgsConstructor @NoArgsConstructor
@Setter @Setter
public class AudioResourcesVO { public class AudioResourcesVO {
public interface Create extends Default {}
public interface Generate extends Default{}
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
private Long id; private Long id;
@ -29,14 +33,15 @@ public class AudioResourcesVO {
private String name; private String name;
/** /**
* 描述 * 描述生成时为语音内容
*/ */
@NotBlank(message = "描述不能为空", groups = Generate.class)
private String desc; private String desc;
/** /**
* 资源地址 * 资源地址
*/ */
@NotBlank(message = "地址不能为空") @NotBlank(message = "地址不能为空", groups = {Create.class})
private String url; private String url;
private LocalDateTime createTime; private LocalDateTime createTime;

View File

@ -286,8 +286,8 @@ public class SocketMessageFactory {
ConversationSocketMessageVO.buildExitMessage(conversation, member)); ConversationSocketMessageVO.buildExitMessage(conversation, member));
} }
public static SocketMessageVO<Integer> buildSimulationTimeSyncMessage(Simulation simulation) { public static SocketMessageVO<Long> buildSimulationTimeSyncMessage(Simulation simulation) {
int systemTime = simulation.getCorrectSystemTime().toLocalTime().toSecondOfDay(); long systemTime = simulation.getCorrectSystemTimeStamp();
return build(WebSocketMessageType.Simulation_Time_Sync, simulation.getId(), systemTime); return build(WebSocketMessageType.Simulation_Time_Sync, simulation.getId(), systemTime);
} }

View File

@ -0,0 +1,25 @@
package club.joylink.rtss.vo.client.user;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
/**
* 找回密码
*/
@Getter
@Setter
@NoArgsConstructor
public class RetrievePwdVO {
private String mobile;
private String email;
@NotBlank(message = "验证码不能为空")
private String vfCode;
@NotBlank(message = "密码不能为空")
private String newPwd;
}

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.vo.client.user; package club.joylink.rtss.vo.client.user;
import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
@ -9,6 +10,7 @@ import javax.validation.constraints.NotBlank;
@Getter @Getter
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor
public class UpdatePasswordVO { public class UpdatePasswordVO {
/** /**
* 短信验证码 * 短信验证码

View File

@ -24,8 +24,8 @@ spring:
mail: mail:
host: smtp.exmail.qq.com host: smtp.exmail.qq.com
port: 465 port: 465
username: ServiceEmail@joylink.club username: serviceemai@joylink.club
password: wFHcZQFuigKPvpSr password: Jiulian0503
properties: properties:
mail: mail:
smtp: smtp: