diff --git a/im-platform/src/main/java/com/bx/implatform/enums/MessageType.java b/im-platform/src/main/java/com/bx/implatform/enums/MessageType.java index 59f229b..21537d4 100644 --- a/im-platform/src/main/java/com/bx/implatform/enums/MessageType.java +++ b/im-platform/src/main/java/com/bx/implatform/enums/MessageType.java @@ -2,6 +2,17 @@ package com.bx.implatform.enums; import lombok.AllArgsConstructor; + +/** + * 0-9: 真正的消息,需要存储到数据库 + * 10-19: 状态类消息: 撤回、已读、回执 + * 20-29: 提示类消息: 在会话中间显示的提示 + * 30-39: UI交互类消息: 显示加载状态等 + * 40-49: 操作交互类消息: 语音通话、视频通话消息等 + * 100-199: 单人语音通话rtc信令 + * 200-299: 多人语音通话rtc信令 + * + */ @AllArgsConstructor public enum MessageType { @@ -25,6 +36,7 @@ public enum MessageType { * 视频 */ VIDEO(4, "视频"), + /** * 撤回 */ @@ -46,11 +58,19 @@ public enum MessageType { * 文字提示 */ TIP_TEXT(21,"文字提示"), - /** * 消息加载标记 */ - LOADDING(30,"加载中"), + LOADING(30,"加载中"), + + /** + * 语音通话提示 + */ + ACT_RT_VOICE(40,"语音通话"), + /** + * 视频通话提示 + */ + ACT_RT_VIDEO(41,"视频通话"), RTC_CALL_VOICE(100, "语音呼叫"), RTC_CALL_VIDEO(101, "视频呼叫"), diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java index 1fb1795..5a8c45c 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java @@ -345,7 +345,6 @@ public class GroupMessageServiceImpl extends ServiceImpl wrapper = new QueryWrapper<>(); wrapper.lambda().eq(GroupMessage::getGroupId, groupId).gt(GroupMessage::getSendTime, member.getCreatedTime()) .ne(GroupMessage::getStatus, MessageStatus.RECALL.code()).orderByDesc(GroupMessage::getId).last("limit " + stIdx + "," + size); - List messages = this.list(wrapper); List messageInfos = messages.stream().map(m -> BeanUtils.copyProperties(m, GroupMessageVO.class)).collect(Collectors.toList()); @@ -369,7 +368,7 @@ public class GroupMessageServiceImpl extends ServiceImpl(); sendMessage.setSender(new IMUserInfo(session.getUserId(), session.getTerminal())); diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupServiceImpl.java index f3b4b59..feb13c8 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupServiceImpl.java @@ -50,6 +50,7 @@ public class GroupServiceImpl extends ServiceImpl implements private final IFriendService friendsService; private final IMClient imClient; private final RedisTemplate redisTemplate; + @Override public GroupVO createGroup(GroupVO vo) { UserSession session = SessionContext.getSession(); diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java index e97e0de..0e10922 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java @@ -9,7 +9,6 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.bx.imclient.IMClient; import com.bx.imcommon.contant.IMConstant; import com.bx.imcommon.enums.IMTerminalType; -import com.bx.imcommon.model.IMGroupMessage; import com.bx.imcommon.model.IMPrivateMessage; import com.bx.imcommon.model.IMUserInfo; import com.bx.implatform.dto.PrivateMessageDTO; @@ -26,7 +25,6 @@ import com.bx.implatform.session.SessionContext; import com.bx.implatform.session.UserSession; import com.bx.implatform.util.BeanUtils; import com.bx.implatform.util.SensitiveFilterUtil; -import com.bx.implatform.vo.GroupMessageVO; import com.bx.implatform.vo.PrivateMessageVO; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -245,7 +243,7 @@ public class PrivateMessageServiceImpl extends ServiceImpl(); sendMessage.setSender(new IMUserInfo(session.getUserId(), session.getTerminal())); diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/WebrtcPrivateServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/WebrtcPrivateServiceImpl.java index b05fc6c..ac9ca1a 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/WebrtcPrivateServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/WebrtcPrivateServiceImpl.java @@ -3,15 +3,18 @@ package com.bx.implatform.service.impl; import com.bx.imclient.IMClient; import com.bx.imcommon.model.IMPrivateMessage; import com.bx.imcommon.model.IMUserInfo; -import com.bx.implatform.config.ICEServer; -import com.bx.implatform.config.WebrtcConfig; import com.bx.implatform.contant.RedisKey; +import com.bx.implatform.entity.PrivateMessage; +import com.bx.implatform.enums.MessageStatus; import com.bx.implatform.enums.MessageType; +import com.bx.implatform.enums.WebrtcMode; import com.bx.implatform.exception.GlobalException; +import com.bx.implatform.service.IPrivateMessageService; import com.bx.implatform.service.IWebrtcPrivateService; import com.bx.implatform.session.SessionContext; import com.bx.implatform.session.UserSession; import com.bx.implatform.session.WebrtcPrivateSession; +import com.bx.implatform.util.BeanUtils; import com.bx.implatform.util.UserStateUtils; import com.bx.implatform.vo.PrivateMessageVO; import lombok.RequiredArgsConstructor; @@ -21,7 +24,7 @@ import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.RequestBody; import java.util.Collections; -import java.util.List; +import java.util.Date; import java.util.concurrent.TimeUnit; @Slf4j @@ -31,22 +34,28 @@ public class WebrtcPrivateServiceImpl implements IWebrtcPrivateService { private final IMClient imClient; private final RedisTemplate redisTemplate; - private final WebrtcConfig iceServerConfig; + private final IPrivateMessageService privateMessageService; private final UserStateUtils userStateUtils; @Override public void call(Long uid, String mode, String offer) { UserSession session = SessionContext.getSession(); + // 创建webrtc会话 + WebrtcPrivateSession webrtcSession = new WebrtcPrivateSession(); + webrtcSession.setCallerId(session.getUserId()); + webrtcSession.setCallerTerminal(session.getTerminal()); + webrtcSession.setAcceptorId(uid); + webrtcSession.setMode(mode); + // 校验 if (!imClient.isOnline(uid)) { + this.sendActMessage(webrtcSession,MessageStatus.UNSEND,"未接通"); throw new GlobalException("对方目前不在线"); } - if(userStateUtils.isBusy(uid)){ + if (userStateUtils.isBusy(uid)) { + this.sendActMessage(webrtcSession,MessageStatus.UNSEND,"未接通"); throw new GlobalException("对方正忙"); } - // 创建webrtc会话 - WebrtcPrivateSession webrtcSession = new WebrtcPrivateSession(); - webrtcSession.setCallerId(session.getUserId()); - webrtcSession.setCallerTerminal(session.getTerminal()); + // 保存rtc session String key = getWebRtcSessionKey(session.getUserId(), uid); redisTemplate.opsForValue().set(key, webrtcSession, 60, TimeUnit.SECONDS); // 设置用户忙线状态 @@ -54,7 +63,8 @@ public class WebrtcPrivateServiceImpl implements IWebrtcPrivateService { userStateUtils.setBusy(session.getUserId()); // 向对方所有终端发起呼叫 PrivateMessageVO messageInfo = new PrivateMessageVO(); - MessageType messageType = mode.equals("video") ? MessageType.RTC_CALL_VIDEO : MessageType.RTC_CALL_VOICE; + MessageType messageType = + mode.equals(WebrtcMode.VIDEO.getValue()) ? MessageType.RTC_CALL_VIDEO : MessageType.RTC_CALL_VOICE; messageInfo.setType(messageType.code()); messageInfo.setRecvId(uid); messageInfo.setSendId(session.getUserId()); @@ -78,6 +88,7 @@ public class WebrtcPrivateServiceImpl implements IWebrtcPrivateService { // 更新接受者信息 webrtcSession.setAcceptorId(session.getUserId()); webrtcSession.setAcceptorTerminal(session.getTerminal()); + webrtcSession.setChatTimeStamp(System.currentTimeMillis()); String key = getWebRtcSessionKey(session.getUserId(), uid); redisTemplate.opsForValue().set(key, webrtcSession, 60, TimeUnit.SECONDS); // 向发起人推送接受通话信令 @@ -123,11 +134,15 @@ public class WebrtcPrivateServiceImpl implements IWebrtcPrivateService { sendMessage.setRecvTerminals(Collections.singletonList(webrtcSession.getCallerTerminal())); sendMessage.setData(messageInfo); imClient.sendPrivateMessage(sendMessage); + // 生成通话消息 + sendActMessage(webrtcSession, MessageStatus.READED,"已拒绝"); } @Override public void cancel(Long uid) { UserSession session = SessionContext.getSession(); + // 查询webrtc会话 + WebrtcPrivateSession webrtcSession = getWebrtcSession(session.getUserId(), uid); // 删除会话信息 removeWebrtcSession(session.getUserId(), uid); // 设置用户空闲状态 @@ -147,6 +162,8 @@ public class WebrtcPrivateServiceImpl implements IWebrtcPrivateService { sendMessage.setData(messageInfo); // 通知对方取消会话 imClient.sendPrivateMessage(sendMessage); + // 生成通话消息 + sendActMessage(webrtcSession, MessageStatus.UNSEND,"已取消"); } @Override @@ -175,7 +192,8 @@ public class WebrtcPrivateServiceImpl implements IWebrtcPrivateService { sendMessage.setData(messageInfo); // 通知对方取消会话 imClient.sendPrivateMessage(sendMessage); - + // 生成消息 + sendActMessage(webrtcSession, MessageStatus.READED,"未接通"); } @Override @@ -204,6 +222,8 @@ public class WebrtcPrivateServiceImpl implements IWebrtcPrivateService { sendMessage.setData(messageInfo); // 通知对方取消会话 imClient.sendPrivateMessage(sendMessage); + // 生成通话消息 + sendActMessage(webrtcSession, MessageStatus.READED,"通话时长 " + chatTimeText(webrtcSession)); } @Override @@ -234,7 +254,7 @@ public class WebrtcPrivateServiceImpl implements IWebrtcPrivateService { UserSession session = SessionContext.getSession(); // 会话续命 String key = getWebRtcSessionKey(session.getUserId(), uid); - redisTemplate.expire(key,60,TimeUnit.SECONDS); + redisTemplate.expire(key, 60, TimeUnit.SECONDS); // 用户状态续命 userStateUtils.expire(session.getUserId()); } @@ -266,4 +286,42 @@ public class WebrtcPrivateServiceImpl implements IWebrtcPrivateService { return webrtcSession.getAcceptorTerminal(); } + private void sendActMessage(WebrtcPrivateSession rtcSession, MessageStatus status,String content) { + // 保存消息 + PrivateMessage msg = new PrivateMessage(); + msg.setSendId(rtcSession.getCallerId()); + msg.setRecvId(rtcSession.getAcceptorId()); + msg.setContent(content); + msg.setSendTime(new Date()); + msg.setStatus(status.code()); + MessageType type = rtcSession.getMode().equals(WebrtcMode.VIDEO.getValue()) ? MessageType.ACT_RT_VIDEO + : MessageType.ACT_RT_VOICE; + msg.setType(type.code()); + privateMessageService.save(msg); + // 推给发起人 + PrivateMessageVO messageInfo = BeanUtils.copyProperties(msg, PrivateMessageVO.class); + IMPrivateMessage sendMessage = new IMPrivateMessage<>(); + sendMessage.setSender(new IMUserInfo(rtcSession.getCallerId(), rtcSession.getCallerTerminal())); + sendMessage.setRecvId(rtcSession.getCallerId()); + sendMessage.setSendToSelf(false); + sendMessage.setSendResult(false); + sendMessage.setData(messageInfo); + imClient.sendPrivateMessage(sendMessage); + // 推给接听方 + sendMessage.setRecvId(rtcSession.getAcceptorId()); + imClient.sendPrivateMessage(sendMessage); + } + + private String chatTimeText(WebrtcPrivateSession rtcSession) { + long chatTime = (System.currentTimeMillis() - rtcSession.getChatTimeStamp())/1000; + int min = Math.abs((int)chatTime / 60); + int sec = Math.abs((int)chatTime % 60); + String strTime = min < 10 ? "0" : ""; + strTime += min; + strTime += ":"; + strTime += sec < 10 ? "0" : ""; + strTime += sec; + return strTime; + } + } diff --git a/im-platform/src/main/java/com/bx/implatform/session/WebrtcPrivateSession.java b/im-platform/src/main/java/com/bx/implatform/session/WebrtcPrivateSession.java index aefea51..3d74cd1 100644 --- a/im-platform/src/main/java/com/bx/implatform/session/WebrtcPrivateSession.java +++ b/im-platform/src/main/java/com/bx/implatform/session/WebrtcPrivateSession.java @@ -27,4 +27,13 @@ public class WebrtcPrivateSession { * 接受者终端类型 */ private Integer acceptorTerminal; + + /** + * 通话模式 + */ + private String mode; + /** + * 开始聊天时间戳 + */ + private Long chatTimeStamp; } diff --git a/im-ui/src/api/enums.js b/im-ui/src/api/enums.js index 0157962..0fcb7eb 100644 --- a/im-ui/src/api/enums.js +++ b/im-ui/src/api/enums.js @@ -4,14 +4,14 @@ const MESSAGE_TYPE = { FILE: 2, AUDIO: 3, VIDEO: 4, - RT_VOICE: 5, - RT_VIDEO: 6, RECALL: 10, READED: 11, RECEIPT: 12, TIP_TIME: 20, TIP_TEXT: 21, - LOADDING: 30, + LOADING: 30, + ACT_RT_VOICE: 40, + ACT_RT_VIDEO: 41, RTC_CALL_VOICE: 100, RTC_CALL_VIDEO: 101, RTC_ACCEPT: 102, diff --git a/im-ui/src/api/messageType.js b/im-ui/src/api/messageType.js new file mode 100644 index 0000000..4ab602c --- /dev/null +++ b/im-ui/src/api/messageType.js @@ -0,0 +1,40 @@ + +// 是否普通消息 +let isNormal = function(type){ + return type>=0 && type < 10; +} + +// 是否状态消息 +let isStatus = function(type){ + return type>=10 && type < 20; +} + +// 是否提示消息 +let isTip = function(type){ + return type>=20 && type < 30; +} + +// 操作交互类消息 +let isAction = function(type){ + return type>=40 && type < 50; +} + +// 单人通话信令 +let isRtcPrivate = function(type){ + return type>=100 && type < 300; +} + +// 多人通话信令 +let isRtcGroup = function(type){ + return type>=200 && type < 400; +} + + +export { + isNormal, + isStatus, + isTip, + isAction, + isRtcPrivate, + isRtcGroup +} \ No newline at end of file diff --git a/im-ui/src/api/rtcPrivateApi.js b/im-ui/src/api/rtcPrivateApi.js new file mode 100644 index 0000000..687ee65 --- /dev/null +++ b/im-ui/src/api/rtcPrivateApi.js @@ -0,0 +1,66 @@ +import http from './httpRequest.js' + +class RtcPrivateApi { +} + +RtcPrivateApi.prototype.call = function(uid, mode, offer) { + return http({ + url: `/webrtc/private/call?uid=${uid}&mode=${mode}`, + method: 'post', + data: JSON.stringify(offer) + }) +} + +RtcPrivateApi.prototype.accept = function(uid, answer) { + return http({ + url: `/webrtc/private/accept?uid=${uid}`, + method: 'post', + data: JSON.stringify(answer) + }) +} + + +RtcPrivateApi.prototype.handup = function(uid) { + return http({ + url: `/webrtc/private/handup?uid=${uid}`, + method: 'post' + }) +} + +RtcPrivateApi.prototype.cancel = function(uid) { + return http({ + url: `/webrtc/private/cancel?uid=${uid}`, + method: 'post' + }) +} + +RtcPrivateApi.prototype.reject = function(uid) { + return http({ + url: `/webrtc/private/reject?uid=${uid}`, + method: 'post' + }) +} + +RtcPrivateApi.prototype.failed = function(uid, reason) { + return http({ + url: `/webrtc/private/failed?uid=${uid}&reason=${reason}`, + method: 'post' + }) +} + +RtcPrivateApi.prototype.sendCandidate = function(uid, candidate) { + return http({ + url: `/webrtc/private/candidate?uid=${uid}`, + method: 'post', + data: JSON.stringify(candidate) + }); +} + +RtcPrivateApi.prototype.heartbeat = function(uid) { + return http({ + url: `/webrtc/private/heartbeat?uid=${uid}`, + method: 'post' + }) +} + +export default RtcPrivateApi; \ No newline at end of file diff --git a/im-ui/src/components/chat/ChatBox.vue b/im-ui/src/components/chat/ChatBox.vue index c58529d..9919f97 100644 --- a/im-ui/src/components/chat/ChatBox.vue +++ b/im-ui/src/components/chat/ChatBox.vue @@ -157,9 +157,9 @@ this.$refs.atBox.close(); }, onCall(type) { - if (type == this.$enums.MESSAGE_TYPE.RT_VOICE) { + if (type == this.$enums.MESSAGE_TYPE.ACT_RT_VOICE) { this.showPrivateVideo('voice'); - } else if (type == this.$enums.MESSAGE_TYPE.RT_VIDEO) { + } else if (type == this.$enums.MESSAGE_TYPE.ACT_RT_VIDEO) { this.showPrivateVideo('video'); } }, diff --git a/im-ui/src/components/chat/ChatItem.vue b/im-ui/src/components/chat/ChatItem.vue index 8fe65fe..b1c3fc6 100644 --- a/im-ui/src/components/chat/ChatItem.vue +++ b/im-ui/src/components/chat/ChatItem.vue @@ -12,7 +12,7 @@
{{atText}}
-
{{chat.sendNickName+': '}}
+
{{chat.sendNickName+': '}}
@@ -76,6 +76,18 @@ } }, computed: { + isShowSendName() { + if (!this.chat.sendNickName) { + return false; + } + let size = this.chat.messages.length; + if (size == 0) { + return false; + } + // 只有群聊的普通消息需要显示名称 + let lastMsg = this.chat.messages[size - 1]; + return this.$msgType.isNormal(lastMsg.type) + }, showTime() { return this.$date.toTimeText(this.chat.lastSendTime, true) }, @@ -108,11 +120,11 @@ &:hover { background-color: #F8FAFF; } - + &.active { background-color: #F4F9FF; } - + .chat-left { position: relative; display: flex; @@ -147,6 +159,7 @@ display: flex; line-height: 25px; height: 25px; + .chat-name-text { flex: 1; font-size: 15px; @@ -154,9 +167,9 @@ white-space: nowrap; overflow: hidden; } - - - .chat-time-text{ + + + .chat-time-text { font-size: 13px; text-align: right; color: #888888; @@ -169,23 +182,24 @@ .chat-content { display: flex; line-height: 22px; - + .chat-at-text { color: #c70b0b; font-size: 12px; } - - .chat-send-name{ + + .chat-send-name { font-size: 13px; } - + .chat-content-text { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - font-size: 13px; + font-size: 13px; + img { width: 20px !important; height: 20px !important; diff --git a/im-ui/src/components/chat/ChatMessageItem.vue b/im-ui/src/components/chat/ChatMessageItem.vue index 9a466a7..7852365 100644 --- a/im-ui/src/components/chat/ChatMessageItem.vue +++ b/im-ui/src/components/chat/ChatMessageItem.vue @@ -1,14 +1,13 @@ @@ -72,15 +72,15 @@ }, methods: { init() { - this.$eventBus.$on('openPrivateVideo', (rctInfo)=>{ + this.$eventBus.$on('openPrivateVideo', (rctInfo) => { // 进入单人视频通话 this.$refs.rtcPrivateVideo.open(rctInfo); }); - this.$eventBus.$on('openGroupVideo', (rctInfo)=>{ + this.$eventBus.$on('openGroupVideo', (rctInfo) => { // 进入多人视频通话 this.$refs.rtcGroupVideo.open(rctInfo); }); - + this.$store.dispatch("load").then(() => { // ws初始化 this.$wsApi.connect(process.env.VUE_APP_WS_URL, sessionStorage.getItem("accessToken")); @@ -136,7 +136,7 @@ }, handlePrivateMessage(msg) { // 消息加载标志 - if (msg.type == this.$enums.MESSAGE_TYPE.LOADDING) { + if (msg.type == this.$enums.MESSAGE_TYPE.LOADING) { this.$store.commit("loadingPrivateMsg", JSON.parse(msg.content)) return; } @@ -158,7 +158,7 @@ // 标记这条消息是不是自己发的 msg.selfSend = msg.sendId == this.$store.state.userStore.userInfo.id; // 单人webrtc 信令 - if (msg.type >= 100 && msg.type <= 199) { + if (this.$msgType.isRtcPrivate(msg.type)) { this.$refs.rtcPrivateVideo.onRTCMessage(msg) return; } @@ -169,7 +169,7 @@ }) }, insertPrivateMessage(friend, msg) { - + let chatInfo = { type: 'PRIVATE', targetId: friend.id, @@ -181,14 +181,14 @@ // 插入消息 this.$store.commit("insertMessage", msg); // 播放提示音 - if (!msg.selfSend && msg.type < 10 - && msg.status != this.$enums.MESSAGE_STATUS.READED) { + if (!msg.selfSend && this.$msgType.isNormal(msg.type) && + msg.status != this.$enums.MESSAGE_STATUS.READED) { this.playAudioTip(); } }, handleGroupMessage(msg) { // 消息加载标志 - if (msg.type == this.$enums.MESSAGE_TYPE.LOADDING) { + if (msg.type == this.$enums.MESSAGE_TYPE.LOADING) { this.$store.commit("loadingGroupMsg", JSON.parse(msg.content)) return; } @@ -217,8 +217,8 @@ // 标记这条消息是不是自己发的 msg.selfSend = msg.sendId == this.$store.state.userStore.userInfo.id; // 群视频信令 - if (msg.type >= 200 && msg.type <= 299) { - this.$nextTick(()=>{ + if (this.$msgType.isRtcGroup(msg.type)) { + this.$nextTick(() => { this.$refs.rtcGroupVideo.onRTCMessage(msg); }) return; @@ -229,7 +229,7 @@ }) }, insertGroupMessage(group, msg) { - + let chatInfo = { type: 'GROUP', targetId: group.id, @@ -241,8 +241,8 @@ // 插入消息 this.$store.commit("insertMessage", msg); // 播放提示音 - if (!msg.selfSend && msg.type < 10 - && msg.status != this.$enums.MESSAGE_STATUS.READED) { + if (!msg.selfSend && msg.type <= this.$enums.MESSAGE_TYPE.VIDEO && + msg.status != this.$enums.MESSAGE_STATUS.READED) { this.playAudioTip(); } }, @@ -346,15 +346,16 @@ background-color: #19082f !important; padding: 0 !important; text-align: center; + .link { text-decoration: none; - + &.router-link-active .icon { color: #ba785a; } } - - .icon { + + .icon { font-size: 26px !important; color: #ddd; } @@ -387,7 +388,7 @@ .icon { font-size: 28px; } - + &:hover { color: white; } diff --git a/im-uniapp/App.vue b/im-uniapp/App.vue index 41f6933..7bd7d24 100644 --- a/im-uniapp/App.vue +++ b/im-uniapp/App.vue @@ -81,7 +81,7 @@ }, handlePrivateMessage(msg) { // 消息加载标志 - if (msg.type == enums.MESSAGE_TYPE.LOADDING) { + if (msg.type == enums.MESSAGE_TYPE.LOADING) { store.commit("loadingPrivateMsg", JSON.parse(msg.content)) return; } @@ -109,12 +109,13 @@ }, insertPrivateMessage(friend, msg) { // 单人视频信令 - if (msg.type >= 100 && msg.type <= 199) { + if (this.$msgType.isRtcPrivate(msg.type)) { // #ifdef MP-WEIXIN // 小程序不支持音视频 return; // #endif // 被呼叫,弹出视频页面 + let delayTime = 100; if(msg.type == enums.MESSAGE_TYPE.RTC_CALL_VOICE || msg.type == enums.MESSAGE_TYPE.RTC_CALL_VIDEO){ let mode = msg.type == enums.MESSAGE_TYPE.RTC_CALL_VIDEO? "video":"voice"; @@ -125,11 +126,12 @@ uni.navigateTo({ url: `/pages/chat/chat-private-video?mode=${mode}&friend=${friendInfo}&isHost=false` }) + delayTime = 500; } } setTimeout(() => { uni.$emit('WS_RTC_PRIVATE',msg); - },500) + },delayTime) return; } let chatInfo = { @@ -143,12 +145,12 @@ // 插入消息 store.commit("insertMessage", msg); // 播放提示音 - !msg.selfSend && this.playAudioTip(); + this.playAudioTip(); }, handleGroupMessage(msg) { // 消息加载标志 - if (msg.type == enums.MESSAGE_TYPE.LOADDING) { + if (msg.type == enums.MESSAGE_TYPE.LOADING) { store.commit("loadingGroupMsg",JSON.parse(msg.content)) return; } @@ -184,7 +186,7 @@ }, insertGroupMessage(group, msg) { // 群视频信令 - if (msg.type >= 200 && msg.type <= 299) { + if (this.$msgType.isRtcGroup(msg.type)) { // #ifdef MP-WEIXIN // 小程序不支持音视频 return; @@ -223,7 +225,7 @@ // 插入消息 store.commit("insertMessage", msg); // 播放提示音 - !msg.selfSend && this.playAudioTip(); + this.playAudioTip(); }, loadFriendInfo(id) { return new Promise((resolve, reject) => { diff --git a/im-uniapp/common/enums.js b/im-uniapp/common/enums.js index e74b893..6dddc3b 100644 --- a/im-uniapp/common/enums.js +++ b/im-uniapp/common/enums.js @@ -5,14 +5,14 @@ const MESSAGE_TYPE = { FILE:2, AUDIO:3, VIDEO:4, - RT_VOICE:5, - RT_VIDEO:6, RECALL:10, READED:11, RECEIPT:12, TIP_TIME:20, TIP_TEXT:21, - LOADDING:30, + LOADING:30, + ACT_RT_VOICE:40, + ACT_RT_VIDEO:41, RTC_CALL_VOICE: 100, RTC_CALL_VIDEO: 101, RTC_ACCEPT: 102, diff --git a/im-uniapp/common/messageType.js b/im-uniapp/common/messageType.js new file mode 100644 index 0000000..4ab602c --- /dev/null +++ b/im-uniapp/common/messageType.js @@ -0,0 +1,40 @@ + +// 是否普通消息 +let isNormal = function(type){ + return type>=0 && type < 10; +} + +// 是否状态消息 +let isStatus = function(type){ + return type>=10 && type < 20; +} + +// 是否提示消息 +let isTip = function(type){ + return type>=20 && type < 30; +} + +// 操作交互类消息 +let isAction = function(type){ + return type>=40 && type < 50; +} + +// 单人通话信令 +let isRtcPrivate = function(type){ + return type>=100 && type < 300; +} + +// 多人通话信令 +let isRtcGroup = function(type){ + return type>=200 && type < 400; +} + + +export { + isNormal, + isStatus, + isTip, + isAction, + isRtcPrivate, + isRtcGroup +} \ No newline at end of file diff --git a/im-uniapp/components/chat-message-item/chat-message-item.vue b/im-uniapp/components/chat-message-item/chat-message-item.vue index 7fc701e..6520813 100644 --- a/im-uniapp/components/chat-message-item/chat-message-item.vue +++ b/im-uniapp/components/chat-message-item/chat-message-item.vue @@ -7,7 +7,7 @@ {{$date.toTimeText(msgInfo.sendTime)}} - @@ -52,13 +52,13 @@ - - - + + {{msgInfo.content}} - + 已读 - + - + @@ -133,6 +133,7 @@ keyboardHeight: 322, atUserIds: [], recordText: "", + needScrollToBottom: false, // 需要滚动到底部 showMinIdx: 0 // 下标小于showMinIdx的消息不显示,否则可能很卡 } }, @@ -174,9 +175,9 @@ }) }, onRtCall(msgInfo) { - if (msgInfo.type == this.$enums.MESSAGE_TYPE.RT_VOICE) { + if (msgInfo.type == this.$enums.MESSAGE_TYPE.ACT_RT_VOICE) { this.onPriviteVoice(); - } else if (msgInfo.type == this.$enums.MESSAGE_TYPE.RT_VIDEO) { + } else if (msgInfo.type == this.$enums.MESSAGE_TYPE.ACT_RT_VIDEO) { this.onPriviteVideo(); } }, @@ -692,7 +693,14 @@ messageSize: function(newSize, oldSize) { // 接收到消息时滚动到底部 if (newSize > oldSize) { - this.scrollToBottom(); + console.log("messageSize",newSize,oldSize) + let pages = getCurrentPages(); + let curPage = pages[pages.length-1].route; + if(curPage == "pages/chat/chat-box"){ + this.scrollToBottom(); + }else { + this.needScrollToBottom = true; + } } }, unreadCount: { @@ -723,11 +731,16 @@ this.$store.commit("activeChat", options.chatIdx); // 复位回执消息 this.isReceipt = false; - // 页面滚到底部 - this.scrollToBottom(); }, onUnload() { this.$store.commit("activeChat", -1); + }, + onShow(){ + if(this.needScrollToBottom){ + // 页面滚到底部 + this.scrollToBottom(); + this.needScrollToBottom = false; + } } } diff --git a/im-uniapp/pages/chat/chat-private-video.vue b/im-uniapp/pages/chat/chat-private-video.vue index afb405b..b72d22c 100644 --- a/im-uniapp/pages/chat/chat-private-video.vue +++ b/im-uniapp/pages/chat/chat-private-video.vue @@ -20,16 +20,6 @@ onMessage(e) { this.onWebviewMessage(e.detail.data[0]); }, - onInsertMessage(msgInfo){ - let chat = { - type: 'PRIVATE', - targetId: this.friend.id, - showName: this.friend.nickName, - headImage: this.friend.headImage, - }; - this.$store.commit("openChat",chat); - this.$store.commit("insertMessage", msgInfo); - }, onWebviewMessage(event) { console.log("来自webview的消息:" + JSON.stringify(event)) switch (event.key) { @@ -39,9 +29,6 @@ case "WV_CLOSE": uni.navigateBack(); break; - case "INSERT_MESSAGE": - this.onInsertMessage(event.data); - break; } }, sendMessageToWebView(key, message) { diff --git a/im-uniapp/store/chatStore.js b/im-uniapp/store/chatStore.js index 5356df3..3641d21 100644 --- a/im-uniapp/store/chatStore.js +++ b/im-uniapp/store/chatStore.js @@ -171,9 +171,9 @@ export default { chat.lastContent = "[语音]"; } else if (msgInfo.type == MESSAGE_TYPE.TEXT || msgInfo.type == MESSAGE_TYPE.RECALL) { chat.lastContent = msgInfo.content; - } else if (msgInfo.type == MESSAGE_TYPE.RT_VOICE) { + } else if (msgInfo.type == MESSAGE_TYPE.ACT_RT_VOICE) { chat.lastContent = "[语音通话]"; - } else if (msgInfo.type == MESSAGE_TYPE.RT_VIDEO) { + } else if (msgInfo.type == MESSAGE_TYPE.ACT_RT_VIDEO) { chat.lastContent = "[视频通话]"; } chat.lastSendTime = msgInfo.sendTime; @@ -275,14 +275,14 @@ export default { } this.commit("saveToStorage"); }, - loadingPrivateMsg(state, loadding) { - state.loadingPrivateMsg = loadding; + loadingPrivateMsg(state, loading) { + state.loadingPrivateMsg = loading; if (!this.getters.isLoading()) { this.commit("refreshChats") } }, - loadingGroupMsg(state, loadding) { - state.loadingGroupMsg = loadding; + loadingGroupMsg(state, loading) { + state.loadingGroupMsg = loading; if (!this.getters.isLoading()) { this.commit("refreshChats") }