Browse Source

feat: 多人音视频功能

master
xsx 2 years ago
parent
commit
b135f97ba2
  1. 5
      im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupDeviceDTO.java
  2. 29
      im-platform/src/main/java/com/bx/implatform/service/impl/WebrtcGroupServiceImpl.java
  3. 3
      im-platform/src/main/java/com/bx/implatform/session/WebrtcUserInfo.java
  4. 27
      im-ui/src/App.vue
  5. 45
      im-ui/src/api/enums.js
  6. 34
      im-ui/src/assets/iconfont/iconfont.css
  7. BIN
      im-ui/src/assets/iconfont/iconfont.ttf
  8. 134
      im-ui/src/components/chat/ChatBox.vue
  9. 28
      im-ui/src/components/common/HeadImage.vue
  10. 26
      im-ui/src/components/group/AddGroupMember.vue
  11. 2
      im-ui/src/components/rtc/RtcPrivateAcceptor.vue
  12. 1
      im-ui/src/main.js
  13. 30
      im-ui/src/view/Home.vue
  14. 22
      im-uniapp/pages/chat/chat-box.vue

5
im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupDeviceDTO.java

@ -21,6 +21,9 @@ public class WebrtcGroupDeviceDTO {
private Long groupId;
@ApiModelProperty(value = "是否开启摄像头")
private Boolean isCamera = false;
private Boolean isCamera;
@ApiModelProperty(value = "是否开启麦克风")
private Boolean isMicroPhone;
}

29
im-platform/src/main/java/com/bx/implatform/service/impl/WebrtcGroupServiceImpl.java

@ -59,6 +59,9 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService {
@Override
public void setup(WebrtcGroupSetupDTO dto) {
UserSession userSession = SessionContext.getSession();
if(!imClient.isOnline(userSession.getUserId())){
throw new GlobalException("您已断开连接,请重新登陆");
}
if (dto.getUserInfos().size() > webrtcConfig.getMaxChannel()) {
throw new GlobalException("最多支持" + webrtcConfig.getMaxChannel() + "人进行通话");
}
@ -78,8 +81,8 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService {
List<Long> busyUserIds = new LinkedList<>();
for (WebrtcUserInfo userInfo : dto.getUserInfos()) {
if (!imClient.isOnline(userInfo.getId())) {
//userInfos.add(userInfo);
offlineUserIds.add(userInfo.getId());
userInfos.add(userInfo);
//offlineUserIds.add(userInfo.getId());
} else if (userStateUtils.isBusy(userInfo.getId())) {
busyUserIds.add(userInfo.getId());
} else {
@ -99,7 +102,7 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService {
if (!offlineUserIds.isEmpty()) {
WebrtcGroupFailedVO vo = new WebrtcGroupFailedVO();
vo.setUserIds(offlineUserIds);
vo.setReason("用户不在线");
vo.setReason("用户当前不在线");
sendRtcMessage2(MessageType.RTC_GROUP_FAILED, dto.getGroupId(), userInfo, JSON.toJSONString(vo));
}
if (!busyUserIds.isEmpty()) {
@ -209,20 +212,24 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService {
if (Objects.isNull(member) || member.getQuit()) {
throw new GlobalException("您不在群里中");
}
// 防止重复进入
if (isInchat(webrtcSession, userSession.getUserId())) {
throw new GlobalException("已在通话");
IMUserInfo mine = findInChatUser(webrtcSession, userSession.getUserId());
if(!Objects.isNull(mine) && mine.getTerminal() != userSession.getTerminal()){
throw new GlobalException("已在其他设备加入通话");
}
WebrtcUserInfo userInfo = new WebrtcUserInfo();
userInfo.setId(userSession.getUserId());
userInfo.setNickName(member.getAliasName());
userInfo.setHeadImage(member.getHeadImage());
// 默认是开启麦克风,关闭摄像头
userInfo.setIsCamera(false);
userInfo.setIsMicroPhone(true);
// 将当前用户加入通话用户列表中
if (!isExist(webrtcSession, userSession.getUserId())) {
webrtcSession.getUserInfos().add(userInfo);
}
if (!isInchat(webrtcSession, userSession.getUserId())) {
webrtcSession.getInChatUsers().add(new IMUserInfo(userSession.getUserId(), userSession.getTerminal()));
}
saveWebrtcSession(groupId, webrtcSession);
// 进入忙线状态
userStateUtils.setBusy(userSession.getUserId());
@ -237,7 +244,7 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService {
public void invite(WebrtcGroupInviteDTO dto) {
UserSession userSession = SessionContext.getSession();
WebrtcGroupSession webrtcSession = getWebrtcSession(dto.getGroupId());
if (dto.getUserInfos().size() + dto.getUserInfos().size() > webrtcConfig.getMaxChannel()) {
if (webrtcSession.getUserInfos().size() + dto.getUserInfos().size() > webrtcConfig.getMaxChannel()) {
throw new GlobalException("最多支持" + webrtcConfig.getMaxChannel() + "人进行通话");
}
if (!groupMemberService.isInGroup(dto.getGroupId(), getRecvIds(dto.getUserInfos()))) {
@ -259,7 +266,9 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService {
continue;
}
if (!imClient.isOnline(userInfo.getId())) {
offlineUserIds.add(userInfo.getId());
// offlineUserIds.add(userInfo.getId());
userStateUtils.setBusy(userInfo.getId());
newUserInfos.add(userInfo);
} else if (userStateUtils.isBusy(userInfo.getId())) {
busyUserIds.add(userInfo.getId());
} else {
@ -275,7 +284,7 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService {
if (!offlineUserIds.isEmpty()) {
WebrtcGroupFailedVO vo = new WebrtcGroupFailedVO();
vo.setUserIds(offlineUserIds);
vo.setReason("用户不在线");
vo.setReason("用户当前不在线");
IMUserInfo reciver = new IMUserInfo(userSession.getUserId(), userSession.getTerminal());
sendRtcMessage2(MessageType.RTC_GROUP_FAILED, dto.getGroupId(), reciver, JSON.toJSONString(vo));
}
@ -417,6 +426,7 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService {
}
// 更新设备状态
userInfo.setIsCamera(dto.getIsCamera());
userInfo.setIsMicroPhone(dto.getIsMicroPhone());
saveWebrtcSession(dto.getGroupId(), webrtcSession);
// 广播信令
List<Long> recvIds = getRecvIds(webrtcSession.getUserInfos());
@ -446,7 +456,6 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService {
host.setId(hostId);
host.setNickName(member.getAliasName());
host.setHeadImage(member.getHeadImage());
host.setIsCamera(false);
}
vo.setHost(host);
}

3
im-platform/src/main/java/com/bx/implatform/session/WebrtcUserInfo.java

@ -23,4 +23,7 @@ public class WebrtcUserInfo {
@ApiModelProperty(value = "是否开启摄像头")
private Boolean isCamera;
@ApiModelProperty(value = "是否开启麦克风")
private Boolean isMicroPhone;
}

27
im-ui/src/App.vue

@ -85,4 +85,31 @@
.el-button {
padding: 8px 15px !important;
}
.el-checkbox {
display: flex;
align-items: center;
//
.el-checkbox__inner {
width: 20px;
height: 20px;
//
&::after {
height: 12px;
left: 7px;
}
}
//
.el-checkbox__input.is-checked+.el-checkbox__label {
color: #333333;
}
.el-checkbox__label {
line-height: 20px;
padding-left: 8px;
}
}
</style>

45
im-ui/src/api/enums.js

@ -1,18 +1,17 @@
const MESSAGE_TYPE = {
TEXT: 0,
IMAGE:1,
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,
IMAGE: 1,
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,
RTC_CALL_VOICE: 100,
RTC_CALL_VIDEO: 101,
RTC_ACCEPT: 102,
@ -20,7 +19,19 @@ const MESSAGE_TYPE = {
RTC_CANCEL: 104,
RTC_FAILED: 105,
RTC_HANDUP: 106,
RTC_CANDIDATE: 107
RTC_CANDIDATE: 107,
RTC_GROUP_SETUP: 200,
RTC_GROUP_ACCEPT: 201,
RTC_GROUP_REJECT: 202,
RTC_GROUP_FAILED: 203,
RTC_GROUP_CANCEL: 204,
RTC_GROUP_QUIT: 205,
RTC_GROUP_INVITE: 206,
RTC_GROUP_JOIN: 207,
RTC_GROUP_OFFER: 208,
RTC_GROUP_ANSWER: 209,
RTC_GROUP_CANDIDATE: 210,
RTC_GROUP_DEVICE: 211
}
const RTC_STATE = {
@ -28,7 +39,7 @@ const RTC_STATE = {
WAIT_CALL: 1, // 呼叫后等待
WAIT_ACCEPT: 2, // 被呼叫后等待
ACCEPTED: 3, // 已接受聊天,等待建立连接
CHATING:4 // 聊天中
CHATING: 4 // 聊天中
}
const TERMINAL_TYPE = {
@ -39,8 +50,8 @@ const TERMINAL_TYPE = {
const MESSAGE_STATUS = {
UNSEND: 0,
SENDED: 1,
RECALL:2,
READED:3
RECALL: 2,
READED: 3
}

34
im-ui/src/assets/iconfont/iconfont.css

@ -1,6 +1,6 @@
@font-face {
font-family: "iconfont"; /* Project id 3791506 */
src: url('iconfont.ttf?t=1714220334746') format('truetype');
src: url('iconfont.ttf?t=1718373714629') format('truetype');
}
.iconfont {
@ -11,6 +11,38 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-invite-rtc:before {
content: "\e65f";
}
.icon-quit:before {
content: "\e606";
}
.icon-camera-off:before {
content: "\e6b5";
}
.icon-speaker-off:before {
content: "\ea3c";
}
.icon-microphone-on:before {
content: "\e63b";
}
.icon-speaker-on:before {
content: "\e6a4";
}
.icon-camera-on:before {
content: "\e627";
}
.icon-microphone-off:before {
content: "\efe5";
}
.icon-chat:before {
content: "\e600";
}

BIN
im-ui/src/assets/iconfont/iconfont.ttf

Binary file not shown.

134
im-ui/src/components/chat/ChatBox.vue

@ -13,11 +13,11 @@
<div class="im-chat-box">
<ul>
<li v-for="(msgInfo, idx) in chat.messages" :key="idx">
<chat-message-item v-if="idx >= showMinIdx"
@call="onCall(msgInfo.type)"
:mine="msgInfo.sendId == mine.id"
:headImage="headImage(msgInfo)" :showName="showName(msgInfo)" :msgInfo="msgInfo"
:groupMembers="groupMembers" @delete="deleteMessage" @recall="recallMessage">
<chat-message-item v-if="idx >= showMinIdx" @call="onCall(msgInfo.type)"
:mine="msgInfo.sendId == mine.id" :headImage="headImage(msgInfo)"
:showName="showName(msgInfo)" :msgInfo="msgInfo"
:groupMembers="groupMembers" @delete="deleteMessage"
@recall="recallMessage">
</chat-message-item>
</li>
</ul>
@ -36,8 +36,8 @@
</file-upload>
</div>
<div title="发送文件">
<file-upload :action="'/file/upload'" :maxSize="10 * 1024 * 1024" @before="onFileBefore"
@success="onFileSuccess" @fail="onFileFail">
<file-upload :action="'/file/upload'" :maxSize="10 * 1024 * 1024"
@before="onFileBefore" @success="onFileSuccess" @fail="onFileFail">
<i class="el-icon-wallet"></i>
</file-upload>
</div>
@ -49,6 +49,9 @@
<div title="语音通话" v-show="chat.type == 'PRIVATE'" class="el-icon-phone-outline"
@click="showPrivateVideo('voice')">
</div>
<div title="语音通话" v-show="chat.type == 'GROUP'" class="el-icon-phone-outline"
@click="onGroupVideo()">
</div>
<div title="视频通话" v-show="chat.type == 'PRIVATE'" class="el-icon-video-camera"
@click="showPrivateVideo('video')">
</div>
@ -57,9 +60,10 @@
<div class="send-content-area">
<div contenteditable="true" v-show="!sendImageUrl" ref="editBox" class="send-text-area"
:disabled="lockMessage" @paste.prevent="onEditorPaste"
@compositionstart="onEditorCompositionStart" @compositionend="onEditorCompositionEnd"
@input="onEditorInput" :placeholder="placeholder" @blur="onEditBoxBlur()"
@keydown.down="onKeyDown" @keydown.up="onKeyUp" @keydown.enter.prevent="onKeyEnter">x
@compositionstart="onEditorCompositionStart"
@compositionend="onEditorCompositionEnd" @input="onEditorInput"
:placeholder="placeholder" @blur="onEditBoxBlur()" @keydown.down="onKeyDown"
@keydown.up="onKeyUp" @keydown.enter.prevent="onKeyEnter">x
</div>
<div v-show="sendImageUrl" class="send-image-area">
@ -85,22 +89,27 @@
<chat-at-box ref="atBox" :ownerId="group.ownerId" :members="groupMembers" :search-text="atSearchText"
@select="onAtSelect"></chat-at-box>
<chat-voice :visible="showVoice" @close="closeVoiceBox" @send="onSendVoice"></chat-voice>
<chat-history :visible="showHistory" :chat="chat" :friend="friend" :group="group" :groupMembers="groupMembers"
@close="closeHistoryBox"></chat-history>
<group-member-selector ref="rtcSel" :groupId="group.id" @complete="onInviteOk"></group-member-selector>
<rtc-group-join ref="rtcJoin" :groupId="group.id"></rtc-group-join>
<chat-history :visible="showHistory" :chat="chat" :friend="friend" :group="group"
:groupMembers="groupMembers" @close="closeHistoryBox"></chat-history>
</el-container>
</div>
</template>
<script>
import ChatGroupSide from "./ChatGroupSide.vue";
import ChatMessageItem from "./ChatMessageItem.vue";
import FileUpload from "../common/FileUpload.vue";
import Emotion from "../common/Emotion.vue";
import ChatVoice from "./ChatVoice.vue";
import ChatHistory from "./ChatHistory.vue";
import ChatAtBox from "./ChatAtBox.vue"
export default {
import ChatGroupSide from "./ChatGroupSide.vue";
import ChatMessageItem from "./ChatMessageItem.vue";
import FileUpload from "../common/FileUpload.vue";
import Emotion from "../common/Emotion.vue";
import ChatVoice from "./ChatVoice.vue";
import ChatHistory from "./ChatHistory.vue";
import ChatAtBox from "./ChatAtBox.vue"
import GroupMemberSelector from "../group/GroupMemberSelector.vue"
import RtcGroupJoin from "../rtc/RtcGroupJoin.vue"
export default {
name: "chatPrivate",
components: {
ChatMessageItem,
@ -109,7 +118,9 @@ export default {
Emotion,
ChatVoice,
ChatHistory,
ChatAtBox
ChatAtBox,
GroupMemberSelector,
RtcGroupJoin
},
props: {
chat: {
@ -137,18 +148,18 @@ export default {
}
},
methods: {
moveChatToTop(){
moveChatToTop() {
let chatIdx = this.$store.getters.findChatIdx(this.chat);
this.$store.commit("moveTop",chatIdx);
this.$store.commit("moveTop", chatIdx);
},
closeRefBox() {
this.$refs.emoBox.close();
this.$refs.atBox.close();
},
onCall(type){
if(type == this.$enums.MESSAGE_TYPE.RT_VOICE){
onCall(type) {
if (type == this.$enums.MESSAGE_TYPE.RT_VOICE) {
this.showPrivateVideo('voice');
}else if(type == this.$enums.MESSAGE_TYPE.RT_VIDEO){
} else if (type == this.$enums.MESSAGE_TYPE.RT_VIDEO) {
this.showPrivateVideo('video');
}
},
@ -256,13 +267,13 @@ export default {
return sendText;
},
html2Escape(strHtml) {
return strHtml.replace(/[<>&"]/g, function (c) {
return strHtml.replace(/[<>&"]/g, function(c) {
return {
'<': '&lt;',
'>': '&gt;',
'&': '&amp;',
'"': '&quot;'
}[c];
} [c];
});
},
createAtUserIds() {
@ -276,7 +287,7 @@ export default {
},
onEditorPaste(e) {
let txt = e.clipboardData.getData('Text')
if (typeof (txt) == 'string') {
if (typeof(txt) == 'string') {
let range = window.getSelection().getRangeAt(0)
let textNode = document.createTextNode(txt);
range.insertNode(textNode)
@ -457,7 +468,48 @@ export default {
offer: "",
state: this.$enums.RTC_STATE.WAIT_CALL
}
this.$store.commit("setRtcInfo",rtcInfo);
this.$store.commit("setRtcInfo", rtcInfo);
},
onGroupVideo() {
this.$http({
url: "/webrtc/group/info?groupId=" + this.group.id,
method: 'GET'
}).then((rtcInfo) => {
if (rtcInfo.isChating) {
//
this.$refs.rtcJoin.open(rtcInfo);
} else {
//
let ids = [this.mine.id];
let maxChannel = this.$store.state.configStore.webrtc.maxChannel;
this.$refs.rtcSel.open(maxChannel, ids, ids);
}
})
},
onInviteOk(members) {
if(members.length < 2){
return;
}
let userInfos = [];
members.forEach(m => {
userInfos.push({
id: m.userId,
nickName: m.aliasName,
headImage: m.headImage,
isCamera: false,
isMicroPhone: true
})
})
let rtcInfo = {
isHost: true,
groupId: this.group.id,
inviterId: this.mine.id,
userInfos: userInfos
}
// home.vue
this.$eventBus.$emit("openGroupVideo", rtcInfo);
},
showHistoryBox() {
this.showHistory = true;
@ -615,7 +667,7 @@ export default {
this.$http({
url: url,
method: 'put'
}).then(() => { })
}).then(() => {})
},
loadReaded(fId) {
this.$http({
@ -688,13 +740,13 @@ export default {
div.scrollTop = div.scrollHeight;
});
},
refreshPlaceHolder(){
refreshPlaceHolder() {
console.log("placeholder")
if(this.isReceipt){
if (this.isReceipt) {
this.placeholder = "【回执消息】"
}else if(this.$refs.editBox && this.$refs.editBox.innerHTML){
} else if (this.$refs.editBox && this.$refs.editBox.innerHTML) {
this.placeholder = ""
}else{
} else {
this.placeholder = "聊点什么吧~";
}
@ -769,11 +821,11 @@ export default {
let div = document.getElementById("chatScrollBox");
div.addEventListener('scroll', this.onScroll)
}
}
}
</script>
<style lang="scss">
.chat-box {
.chat-box {
position: relative;
width: 100%;
background: #f8f8f8;
@ -786,6 +838,7 @@ export default {
font-size: 20px;
font-weight: 600;
border-bottom: 1px #ddd solid;
.btn-side {
position: absolute;
right: 20px;
@ -799,6 +852,7 @@ export default {
.im-chat-main {
padding: 0;
background-color: #f8f8f8;
.im-chat-box {
>ul {
padding: 0 20px;
@ -825,6 +879,7 @@ export default {
border-top: #ccc solid 1px;
padding: 2px;
background-color: #E8F2FF;
>div {
font-size: 22px;
cursor: pointer;
@ -934,4 +989,5 @@ export default {
border: #dddddd solid 1px;
animation: rtl-drawer-in .3s 1ms;
}
}</style>
}
</style>

28
im-ui/src/components/common/HeadImage.vue

@ -28,6 +28,16 @@
type: Number,
default: 50
},
width: {
type: Number
},
height: {
type: Number
},
radius:{
type: String,
default: "10%"
},
url: {
type: String
},
@ -54,12 +64,18 @@
}
},
computed:{
avatarImageStyle(){
return `width:${this.size}px; height:${this.size}px;`
avatarImageStyle() {
let w = this.width ? this.width : this.size;
let h = this.height ? this.height : this.size;
return `width:${w}px; height:${h}px;
border-radius: ${this.radius};`
},
avatarTextStyle(){
return `width: ${this.size}px;height:${this.size}px;
color:${this.textColor};font-size:${this.size*0.6}px;`
avatarTextStyle() {
let w = this.width ? this.width : this.size;
let h = this.height ? this.height : this.size;
return `width: ${w}px;height:${h}px;
color:${this.textColor};font-size:${w*0.6}px;
border-radius: ${this.radius};`
},
textColor(){
let hash = 0;
@ -79,7 +95,7 @@
.avatar-image {
position: relative;
overflow: hidden;
border-radius: 10%;
display: block;
}
.avatar-text{

26
im-ui/src/components/group/AddGroupMember.vue

@ -136,32 +136,6 @@
border-radius: 5px;
overflow: hidden;
.el-checkbox {
display: flex;
align-items: center;
//
.el-checkbox__inner {
width: 20px;
height: 20px;
//
&::after {
height: 12px;
left: 7px;
}
}
//
.el-checkbox__input.is-checked+.el-checkbox__label {
color: #333333;
}
.el-checkbox__label {
line-height: 20px;
padding-left: 8px;
}
}
.agm-friend-checkbox {
margin-right: 20px;

2
im-ui/src/components/rtc/RtcPrivateAcceptor.vue

@ -15,7 +15,7 @@
import HeadImage from '../common/HeadImage.vue';
export default {
name: "videoAcceptor",
name: "rtcPrivateAcceptor",
components: {
HeadImage
},

1
im-ui/src/main.js

@ -21,6 +21,7 @@ Vue.prototype.$http = httpRequest // http请求方法
Vue.prototype.$emo = emotion; // emo表情
Vue.prototype.$elm = element; // 元素操作
Vue.prototype.$enums = enums; // 枚举
Vue.prototype.$eventBus = new Vue(); // 全局事件
Vue.config.productionTip = false;
new Vue({

30
im-ui/src/view/Home.vue

@ -42,6 +42,7 @@
@close="$store.commit('closeFullImageBox')"></full-image>
<rtc-private-video ref="rtcPrivateVideo"></rtc-private-video>
<rtc-private-acceptor ref="rtcPrivateAcceptor"></rtc-private-acceptor>
<rtc-group-video ref="rtcGroupVideo" ></rtc-group-video>
</el-container>
</template>
@ -52,6 +53,7 @@
import FullImage from '../components/common/FullImage.vue';
import RtcPrivateVideo from '../components/rtc/RtcPrivateVideo.vue';
import RtcPrivateAcceptor from '../components/rtc/RtcPrivateAcceptor.vue';
import RtcGroupVideo from '../components/rtc/RtcGroupVideo.vue';
export default {
components: {
@ -60,7 +62,8 @@
UserInfo,
FullImage,
RtcPrivateVideo,
RtcPrivateAcceptor
RtcPrivateAcceptor,
RtcGroupVideo
},
data() {
return {
@ -70,6 +73,12 @@
},
methods: {
init() {
this.$eventBus.$on('openGroupVideo', (rctInfo)=>{
//
console.log(this.$refs.rtcGroupVideo)
this.$refs.rtcGroupVideo.open(rctInfo);
});
this.$store.dispatch("load").then(() => {
// ws
this.$wsApi.connect(process.env.VUE_APP_WS_URL, sessionStorage.getItem("accessToken"));
@ -153,9 +162,8 @@
})
},
insertPrivateMessage(friend, msg) {
// webrtc
if (msg.type >= this.$enums.MESSAGE_TYPE.RTC_CALL_VOICE &&
msg.type <= this.$enums.MESSAGE_TYPE.RTC_CANDIDATE) {
// webrtc
if (msg.type >= 100 && msg.type <= 199) {
let rtcInfo = this.$store.state.userStore.rtcInfo;
//
if (msg.type == this.$enums.MESSAGE_TYPE.RTC_CALL_VOICE ||
@ -180,7 +188,8 @@
//
this.$store.commit("insertMessage", msg);
//
if (!msg.selfSend && msg.status != this.$enums.MESSAGE_STATUS.READED) {
if (!msg.selfSend && msg.type < 10
&& msg.status != this.$enums.MESSAGE_STATUS.READED) {
this.playAudioTip();
}
},
@ -214,12 +223,20 @@
}
//
msg.selfSend = msg.sendId == this.$store.state.userStore.userInfo.id;
//
if (msg.type >= 200 && msg.type <= 299) {
this.$nextTick(()=>{
this.$refs.rtcGroupVideo.onRTCMessage(msg);
})
return;
}
this.loadGroupInfo(msg.groupId).then((group) => {
//
this.insertGroupMessage(group, msg);
})
},
insertGroupMessage(group, msg) {
let chatInfo = {
type: 'GROUP',
targetId: group.id,
@ -231,7 +248,8 @@
//
this.$store.commit("insertMessage", msg);
//
if (!msg.selfSend && msg.status != this.$enums.MESSAGE_STATUS.READED) {
if (!msg.selfSend && msg.type < 10
&& msg.status != this.$enums.MESSAGE_STATUS.READED) {
this.playAudioTip();
}
},

22
im-uniapp/pages/chat/chat-box.vue

@ -81,11 +81,11 @@
</view>
<!-- #ifndef MP-WEIXIN -->
<!-- 音视频不支持小程序 -->
<view v-if="chat.type == 'PRIVATE'" class="chat-tools-item" @click="onVideoCall()">
<view v-if="chat.type == 'PRIVATE'" class="chat-tools-item" @click="onPriviteVideo()">
<view class="tool-icon iconfont icon-video"></view>
<view class="tool-name">视频通话</view>
</view>
<view v-if="chat.type == 'PRIVATE'" class="chat-tools-item" @click="onVoiceCall()">
<view v-if="chat.type == 'PRIVATE'" class="chat-tools-item" @click="onPriviteVoice()">
<view class="tool-icon iconfont icon-call"></view>
<view class="tool-name">语音通话</view>
</view>
@ -110,7 +110,7 @@
<!-- 群语音通话时选择成员 -->
<group-member-selector ref="selBox" :members="groupMembers"
:maxSize="$store.state.configStore.webrtc.maxChannel"
@complete="onSelectMember"></group-member-selector>
@complete="onInviteOk"></group-member-selector>
<group-rtc-join ref="rtcJoin" :groupId="group.id"></group-rtc-join>
</view>
</template>
@ -175,18 +175,18 @@
},
onRtCall(msgInfo) {
if (msgInfo.type == this.$enums.MESSAGE_TYPE.RT_VOICE) {
this.onVoiceCall();
this.onPriviteVoice();
} else if (msgInfo.type == this.$enums.MESSAGE_TYPE.RT_VIDEO) {
this.onVideoCall();
this.onPriviteVideo();
}
},
onVideoCall() {
onPriviteVideo() {
const friendInfo = encodeURIComponent(JSON.stringify(this.friend));
uni.navigateTo({
url: `/pages/chat/chat-private-video?mode=video&friend=${friendInfo}&isHost=true`
})
},
onVoiceCall() {
onPriviteVoice() {
const friendInfo = encodeURIComponent(JSON.stringify(this.friend));
uni.navigateTo({
url: `/pages/chat/chat-private-video?mode=voice&friend=${friendInfo}&isHost=true`
@ -208,7 +208,10 @@
}
})
},
onSelectMember(ids) {
onInviteOk(ids) {
if(ids.length < 2){
return;
}
let users = [];
ids.forEach(id => {
let m = this.groupMembers.find(m => m.userId == id);
@ -217,7 +220,8 @@
id: m.userId,
nickName: m.aliasName,
headImage: m.headImage,
isCamera: false
isCamera: false,
isMicroPhone: true
})
})
const groupId = this.group.id;

Loading…
Cancel
Save