diff --git a/src/main/java/club/joylink/rtss/controller/simulation/SimulationConversationController.java b/src/main/java/club/joylink/rtss/controller/simulation/SimulationConversationController.java index f816a88a7..04d590ae5 100644 --- a/src/main/java/club/joylink/rtss/controller/simulation/SimulationConversationController.java +++ b/src/main/java/club/joylink/rtss/controller/simulation/SimulationConversationController.java @@ -2,7 +2,7 @@ package club.joylink.rtss.controller.simulation; import club.joylink.rtss.controller.advice.AuthenticateInterceptor; import club.joylink.rtss.simulation.cbtc.conversation.CommunicationObject; -import club.joylink.rtss.simulation.cbtc.conversation.ConversationGroupManagerService; +import club.joylink.rtss.simulation.cbtc.conversation.ConversationGroupHandlerService; import club.joylink.rtss.simulation.cbtc.conversation.ConversationManagerService; import club.joylink.rtss.simulation.cbtc.conversation.ConversationText; import club.joylink.rtss.simulation.cbtc.data.vo.ConversationGroupVO; @@ -25,7 +25,7 @@ public class SimulationConversationController { private ConversationManagerService conversationManagerService; @Autowired - private ConversationGroupManagerService conversationGroupManagerService; + private ConversationGroupHandlerService conversationGroupHandlerService; /** *根据会话id获取仿真会话 @@ -113,6 +113,6 @@ public class SimulationConversationController { */ @GetMapping("/group/list") public List groupList(@PathVariable String group) { - return conversationGroupManagerService.getAllConversationsGroup(group); + return conversationGroupHandlerService.getAllConversationsGroup(group); } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/Simulation.java b/src/main/java/club/joylink/rtss/simulation/cbtc/Simulation.java index 8a721098b..adfe5cb4a 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/Simulation.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/Simulation.java @@ -46,6 +46,7 @@ import java.time.ZoneId; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Collectors; /** @@ -149,6 +150,11 @@ public class Simulation extends club.joylink.rtss.simulation.Simulation simulationConversationMap = new ConcurrentHashMap<>(); + /** + * 会话群组ID + */ + private AtomicLong conversationGroupId = new AtomicLong(0l); + /** * 用户组会话 * key-用户组ID @@ -320,8 +326,19 @@ public class Simulation extends club.joylink.rtss.simulation.Simulation map) { + public void initDefaultConversationGroupMap(Map map) { this.simulationConversationGroupMap.putAll(map); + Long groupId = map.keySet().stream().max(Comparator.comparing(Long::longValue)).orElse(0L); + this.conversationGroupId.set(groupId); + } + + public ConversationGroup getConversationGroupByName(String name) { + return this.simulationConversationGroupMap.values().stream().filter(group -> Objects.equals(group.getName(), name)) + .findAny().orElse(null); + } + + public Long getMaxConversationGroupId() { + return conversationGroupId.incrementAndGet(); } public ConversationGroup getConversationGroup(Long id) { diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/SimulationServiceImpl.java b/src/main/java/club/joylink/rtss/simulation/cbtc/SimulationServiceImpl.java index 9a506eeb4..ab41a0c86 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/SimulationServiceImpl.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/SimulationServiceImpl.java @@ -390,6 +390,6 @@ public class SimulationServiceImpl implements SimulationService { } Map groupMap = conversationGroupVOList.stream().map(g -> new ConversationGroup(simulation, g)) .collect(Collectors.toMap(ConversationGroup::getId, group -> group)); - simulation.addConversationGroupMap(groupMap); + simulation.initDefaultConversationGroupMap(groupMap); } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/Chat.java b/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/Chat.java index 6110020a1..948cedf7a 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/Chat.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/Chat.java @@ -45,6 +45,11 @@ public abstract class Chat { return false; } + public ConversationMember getConversionMember(SimulationMember member) { + return this.memberList.stream().filter(m -> Objects.equals(m.getMember().getId(), member.getId())) + .findFirst().orElse(null); + } + public boolean isCreator(SimulationMember member) { return Objects.equals(member, this.creator); } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationGroup.java b/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationGroup.java index 8c4e35265..4f8160ee8 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationGroup.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationGroup.java @@ -8,6 +8,7 @@ import lombok.Data; import lombok.Getter; import org.springframework.util.CollectionUtils; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @@ -42,14 +43,31 @@ public class ConversationGroup extends Chat { public ConversationGroup(Simulation simulation, ConversationGroupVO info) { this.id = info.getId(); this.name = info.getName(); + setTime(simulation.getCorrectSystemTime()); SimulationMember leader = null; if (info.getLeaderId() != null) { leader = simulation.getSimulationMemberById(info.getLeaderId()); setCreator(leader); } List memberList = null; - if (CollectionUtils.isEmpty(info.getMemberIds())) { - memberList = info.getMemberIds().stream().map(simulation::getSimulationMemberById).map(ConversationMember::new).collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(info.getMemberIds())) { + memberList = info.getMemberIds().stream().distinct().map(simulation::getSimulationMemberById) + .map(ConversationMember::new).collect(Collectors.toList()); + setMemberList(memberList); + } + } + + public ConversationGroup(Long id, String name, LocalDateTime time, SimulationMember leader, List simulationMembers){ + this.id = id; + this.name = name; + setTime(time); + setCreator(leader); + if (!CollectionUtils.isEmpty(simulationMembers)) { + List memberList = simulationMembers.stream().map(member -> { + ConversationMember conversationMember = new ConversationMember(member); + conversationMember.setTime(time); + return conversationMember; + }).collect(Collectors.toList()); setMemberList(memberList); } } @@ -74,34 +92,40 @@ public class ConversationGroup extends Chat { * @return 消息列表 */ public List getUnreadMessages(SimulationMember member) { + ConversationMember conversationMember = getConversionMember(member); // 没有消息,不是本群人员 - if (CollectionUtils.isEmpty(getMessageList()) && !isCreator(member) && !isConversationMember(member)) { + if (CollectionUtils.isEmpty(getMessageList()) && !isCreator(member) && conversationMember != null) { return List.of(); } return messageList.stream().filter(message -> { if (message.isAllRead()) { // 全部已读 return false; } + if (message.getTime().isBefore(conversationMember.getTime())) { // 在用户加入之前发的消息 + return false; + } return !message.getReaderSet().contains(member.getId()); // 在已读名单中 }).collect(Collectors.toList()); } /** - * 用户读消息 - * - * @param member 角色信息 + * 修改群组名称 + * @param name 名称 */ - public void readMessage(SimulationMember member){ - // 没有消息,不是本群人员 - List messageList = getUnreadMessages(member); - if (CollectionUtils.isEmpty(messageList)) { - return; + public void setName(String name) { + this.name = name; + } + + /** + * 增加群组成员 + * @param member 成员 + * @param time 时间 + */ + public void addSimulationMember(SimulationMember member, LocalDateTime time) { + if (!contains(member)) { + ConversationMember conversationMember = new ConversationMember(member); + conversationMember.setTime(time); + getMemberList().add(conversationMember); } - messageList.forEach(message -> { - message.read(member); - if (message.getReaderSet().size() >= getMemberList().size()) { // 全部用户已读 - message.finishRead(); - } - }); } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationGroupHandlerService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationGroupHandlerService.java new file mode 100644 index 000000000..40a11b91b --- /dev/null +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationGroupHandlerService.java @@ -0,0 +1,281 @@ +package club.joylink.rtss.simulation.cbtc.conversation; + +import club.joylink.rtss.services.voice.VoiceService; +import club.joylink.rtss.simulation.cbtc.GroupSimulationCache; +import club.joylink.rtss.simulation.cbtc.Simulation; +import club.joylink.rtss.simulation.cbtc.data.vo.ConversationGroupMessageVO; +import club.joylink.rtss.simulation.cbtc.data.vo.ConversationGroupVO; +import club.joylink.rtss.simulation.cbtc.exception.SimulationException; +import club.joylink.rtss.simulation.cbtc.exception.SimulationExceptionType; +import club.joylink.rtss.simulation.cbtc.member.SimulationMember; +import club.joylink.rtss.vo.client.voice.VoiceRecognitionResult; +import club.joylink.rtss.vo.client.voice.VoiceRecognitionVO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.*; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +@Slf4j +@Service +public class ConversationGroupHandlerService { + + @Autowired + private GroupSimulationCache groupSimulationCache; + + @Autowired + private VoiceService iVoiceService; + + @Autowired + private SimulationVoiceHandler simulationVoiceHandler; + + /** + * 获取所有群组信息 + * @param group + * @return + */ + public List getAllConversationsGroup(String group) { + Simulation simulation = groupSimulationCache.getSimulationByGroup(group); + List allGroup = simulation.queryAllConversationGroup(); + return ConversationGroupVO.convert2VOList(allGroup); + } + + /** + * 创建群组会话 + * + * @param simulation 仿真 + * @param member 用户 + * @param name 群组名称 + * @param memberIds 群组成员 + */ + public ConversationGroupVO createConversationGroup(Simulation simulation, SimulationMember member, String name, List memberIds) { + ConversationGroup conversationGroup = simulation.getConversationGroupByName(name); + if (conversationGroup != null) { + throw new SimulationException(SimulationExceptionType.Illegal_Argument, "【" + name + "】已存在"); + } + List simulationMembers = memberIds.stream().map(simulation::getSimulationMemberById).collect(Collectors.toList()); + Long groupId = simulation.getMaxConversationGroupId(); + conversationGroup = new ConversationGroup(groupId, name, simulation.getCorrectSystemTime(), member, simulationMembers); + simulation.addConversationGroup(conversationGroup); + // 通知用户消息 TODO + + return new ConversationGroupVO(conversationGroup); + } + + /** + * 修改会话群组名称 + * + * @param simulation 仿真 + * @param member 用户 + * @param groupId 群组主键 + * @param name 群组名称 + */ + public void updateConversationGroup(Simulation simulation, SimulationMember member, Long groupId, String name) { + ConversationGroup conversationGroup = checkGroupIdAndReturn(simulation, member, groupId); + // 查找名称是否已存在 + ConversationGroup nameConversationGroup = simulation.getConversationGroupByName(name); + if (nameConversationGroup != null && !Objects.equals(groupId, nameConversationGroup.getId())) { + throw new SimulationException(SimulationExceptionType.Illegal_Argument, "【" + name + "】已存在"); + } else if (nameConversationGroup != null && Objects.equals(groupId, nameConversationGroup.getId())) { + return; + } + conversationGroup.setName(name); + // 通知其他用户群名变更 TODO + + } + + /** + * 设置会话群群主 + * + * @param simulation 仿真 + * @param member 用户 + * @param groupId 群组主键 + * @param memberId 目标用户 + */ + public void setConversationGroupLeader(Simulation simulation, SimulationMember member, Long groupId, String memberId) { + ConversationGroup conversationGroup = checkGroupIdAndReturn(simulation, member, groupId); + SimulationMember simulationMember = simulation.getSimulationMemberById(memberId); + if (!conversationGroup.isConversationMember(simulationMember)) { + conversationGroup.addSimulationMember(simulationMember, simulation.getCorrectSystemTime()); + } + // 设置群组 + conversationGroup.setCreator(simulationMember); + // 发送通知消息 TODO + + } + + /** + * 邀请用户进群 + * @param simulation 仿真 + * @param member 用户 + * @param groupId 群组主键 + * @param memberIds 角色ID + */ + public void inviteMembersInConversationGroup(Simulation simulation, SimulationMember member, Long groupId, List memberIds) { + ConversationGroup conversationGroup = checkGroupIdAndReturn(simulation, null, groupId); + if (!conversationGroup.isConversationMember(member)) { + throw new SimulationException(SimulationExceptionType.Illegal_Argument, "非本组成员,不能邀请用户"); + } + List groupMemberIds = conversationGroup.getSimulationMemberIds(); + List newMemberIds = memberIds.stream().filter(mid -> !groupMemberIds.contains(mid)).collect(Collectors.toList()); + newMemberIds.forEach(memberId -> { + SimulationMember newMember = simulation.getSimulationMemberById(memberId); + conversationGroup.addSimulationMember(newMember, simulation.getCorrectSystemTime()); + }); + // 给新加入的用户发送消息 TODO + + } + + /** + * 退出群组 + * + * @param simulation 仿真 + * @param member 用户 + */ + public void exitConversationGroup(Simulation simulation, SimulationMember member, Long groupId) { + ConversationGroup conversationGroup = checkGroupIdAndReturn(simulation, null, groupId); + if (!conversationGroup.isConversationMember(member)) { + throw new SimulationException(SimulationExceptionType.Illegal_Argument, "非本组成员,不能邀请用户"); + } + if (conversationGroup.isCreator(member)) { + throw new SimulationException(SimulationExceptionType.Illegal_Argument, "请先变更群主"); + } + conversationGroup.exit(member); + // 发送退群消息 TODO + + } + + /** + * 语音文件聊天 + * + * @param simulation 仿真 + * @param member 用户 + * @param groupId 用户组 + * @param audioPath 文件路径 + * @param content 文件内容 + * @return 消息信息实体 + */ + public ConversationGroupMessageVO audioChat(Simulation simulation, SimulationMember member, Long groupId, String audioPath, String content) { + ConversationGroupMessage message = sendMessage(simulation, member, groupId, () -> { + VoiceRecognitionResult recognitionResult = new VoiceRecognitionResult(); + recognitionResult.setFilePath(audioPath); + recognitionResult.setResult(content); + return recognitionResult; + }); + return new ConversationGroupMessageVO(message); + } + + /** + * 文字聊天 + * + * @param simulation 仿真 + * @param member 用户 + * @param groupId 用户组 + * @param content 文字信息 + * @return 消息信息实体 + */ + public ConversationGroupMessageVO textChat(Simulation simulation, SimulationMember member, Long groupId, String content) { + ConversationGroupMessage message = sendMessage(simulation, member, groupId, () -> { + VoiceRecognitionResult recognitionResult = new VoiceRecognitionResult(); + recognitionResult.setResult(content); + return recognitionResult; + }); + return new ConversationGroupMessageVO(message); + } + + /** + * 发送Base64文件消息 + * @param simulation 仿真 + * @param member 成员 + * @param groupId 用户群组ID + * @param fileBase64Str base64文件内容 + * @return 消息信息实体 + */ + public ConversationGroupMessageVO audioBase64(Simulation simulation, SimulationMember member, Long groupId, String fileBase64Str) { + ConversationGroupMessage message = sendMessage(simulation, member, groupId, () -> { + VoiceRecognitionVO vo = VoiceRecognitionVO.load(fileBase64Str); + VoiceRecognitionResult recognitionResult = iVoiceService.voiceRecognition(vo); + return recognitionResult; + }); + return new ConversationGroupMessageVO(message); + } + + /** + * 群组用户读取消息 + * + * @param simulation 仿真 + * @param member 群组成员 + * @param groupId 群组ID + * @return 未读的消息列表 + */ + public List readConversationGroup(Simulation simulation, SimulationMember member, Long groupId) { + ConversationGroup conversationGroup = simulation.getConversationGroup(groupId); + // 没有消息,不是本群人员 + List messageList = conversationGroup.getUnreadMessages(member); + if (CollectionUtils.isEmpty(messageList)) { + return List.of(); + } + int memberSize = conversationGroup.getMemberList().size(); + messageList.forEach(message -> { + message.read(member); + if (message.getReaderSet().size() >= memberSize) { // 全部用户已读 + message.finishRead(); + } + }); + return ConversationGroupMessageVO.convert2VO(messageList); + } + + /** + * 对群组操作时基础判断 + * + * @param simulation 仿真 + * @param member 操作人员 + * @param groupId 群组ID + * @return 群组信息 + */ + private ConversationGroup checkGroupIdAndReturn(Simulation simulation, SimulationMember member, Long groupId) { + ConversationGroup conversationGroup = simulation.getConversationGroup(groupId); + if (conversationGroup == null) { + throw new SimulationException(SimulationExceptionType.Illegal_Argument, "群组不存在"); + } + if (member != null && !Objects.equals(member.getId(), conversationGroup.getCreator().getId())) { + throw new SimulationException(SimulationExceptionType.Illegal_Argument, "您无操作权限"); + } + return conversationGroup; + } + + /** + * 处理并发送消息方法 + * @param simulation 仿真 + * @param member 操作人 + * @param groupId 用户组 + * @param handleSupplier 处理消息方法 + * @return 用户组消息 + */ + private ConversationGroupMessage sendMessage(Simulation simulation, SimulationMember member, Long groupId + , Supplier handleSupplier) { + ConversationGroup conversationGroup = checkGroupIdAndReturn(simulation, null, groupId); + if (!conversationGroup.isConversationMember(member)) { + throw new SimulationException(SimulationExceptionType.Illegal_Argument, "非本组成员,不能邀请用户"); + } + + VoiceRecognitionResult recognitionResult = handleSupplier.get(); + String upperCaseResult = recognitionResult.getResult().toUpperCase(); + String handledContent = simulationVoiceHandler.handle(upperCaseResult); + + // 创建消息信息 + String messageId = conversationGroup.generateMessageId(); + ConversationGroupMessage message = new ConversationGroupMessage(messageId, member, + simulation.getCorrectSystemTime(), handledContent, recognitionResult.getFilePath()); + conversationGroup.addMessage(message); + + // 发送消息 + + + + return message; + } +} diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationGroupManagerService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationGroupManagerService.java deleted file mode 100644 index ffc42ad59..000000000 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationGroupManagerService.java +++ /dev/null @@ -1,30 +0,0 @@ -package club.joylink.rtss.simulation.cbtc.conversation; - -import club.joylink.rtss.simulation.cbtc.GroupSimulationCache; -import club.joylink.rtss.simulation.cbtc.Simulation; -import club.joylink.rtss.simulation.cbtc.data.vo.ConversationGroupVO; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.*; - -@Slf4j -@Service -public class ConversationGroupManagerService { - - @Autowired - private GroupSimulationCache groupSimulationCache; - - /** - * 获取所有群组信息 - * @param group - * @return - */ - public List getAllConversationsGroup(String group) { - Simulation simulation = groupSimulationCache.getSimulationByGroup(group); - List allGroup = simulation.queryAllConversationGroup(); - return ConversationGroupVO.convert2VOList(allGroup); - } - -} diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationGroupOperateHandler.java b/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationGroupOperateHandler.java index b3ac0642f..31c50e638 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationGroupOperateHandler.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationGroupOperateHandler.java @@ -1,9 +1,15 @@ package club.joylink.rtss.simulation.cbtc.conversation; import club.joylink.rtss.simulation.cbtc.ATS.operation.annotation.OperateHandler; +import club.joylink.rtss.simulation.cbtc.Simulation; +import club.joylink.rtss.simulation.cbtc.data.vo.ConversationGroupMessageVO; +import club.joylink.rtss.simulation.cbtc.data.vo.ConversationGroupVO; +import club.joylink.rtss.simulation.cbtc.member.SimulationMember; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import java.util.List; + /** * 群组会话操作 */ @@ -11,7 +17,77 @@ import org.springframework.beans.factory.annotation.Autowired; @Slf4j public class ConversationGroupOperateHandler { @Autowired - private ConversationGroupManagerService conversationGroupManagerService; + private ConversationGroupHandlerService conversationGroupManagerService; + /** + * 创建群组信息 + * @param simulation 仿真 + * @param member 创建人 + * @param name + * @param memberIds + */ + public ConversationGroupVO createConversationGroup(Simulation simulation, SimulationMember member, String name, List memberIds) { + return conversationGroupManagerService.createConversationGroup(simulation, member, name, memberIds); + } + /** + * 修改群组名称等基本信息 + */ + public void updateConversationGroup(Simulation simulation, SimulationMember member, Long groupId, String name) { + conversationGroupManagerService.updateConversationGroup(simulation, member, groupId, name); + } + + /** + * 设定群组群主 + * + * @param simulation 仿真 + * @param member 用户 + * @param groupId 群组ID + * @param memberId 用户ID + */ + public void setConversationGroupLeader(Simulation simulation, SimulationMember member, Long groupId, String memberId) { + conversationGroupManagerService.setConversationGroupLeader(simulation, member, groupId, memberId); + } + + /** + * 邀请角色进群组 + */ + public void inviteMembersInConversationGroup(Simulation simulation, SimulationMember member, Long groupId, List memberIds) { + conversationGroupManagerService.inviteMembersInConversationGroup(simulation, member, groupId, memberIds); + } + + /** + * 退出群组信息 + */ + public void exitConversationGroup(Simulation simulation, SimulationMember member, Long groupId) { + conversationGroupManagerService.exitConversationGroup(simulation, member, groupId); + } + + /** + * 发送语音信息 + */ + public ConversationGroupMessageVO audioChat(Simulation simulation, SimulationMember member, Long groupId, String audioPath, String content) { + return conversationGroupManagerService.audioChat(simulation, member, groupId, audioPath, content); + } + + /** + * 发送文字信息 + */ + public ConversationGroupMessageVO textChat(Simulation simulation, SimulationMember member, Long groupId, String content) { + return conversationGroupManagerService.textChat(simulation, member, groupId, content); + } + + /** + * 发送Base64音频文件 + */ + public ConversationGroupMessageVO audioBase64(Simulation simulation, SimulationMember member, Long groupId, String fileBase64Str) { + return conversationGroupManagerService.audioBase64(simulation, member, groupId, fileBase64Str); + } + + /** + * 阅读群组信息 + */ + public List readConversationGroup(Simulation simulation, SimulationMember member, Long groupId) { + return conversationGroupManagerService.readConversationGroup(simulation, member, groupId); + } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationMember.java b/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationMember.java index 5239e6fbf..f4205620a 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationMember.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/conversation/ConversationMember.java @@ -2,6 +2,9 @@ package club.joylink.rtss.simulation.cbtc.conversation; import club.joylink.rtss.simulation.cbtc.member.SimulationMember; import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDateTime; @Getter public class ConversationMember { @@ -10,6 +13,12 @@ public class ConversationMember { private boolean connect; + /** + * 加入时间 + */ + @Setter + private LocalDateTime time; + public ConversationMember(SimulationMember member) { this.member = member; this.connect = false;