vue项目中集成腾讯TIM即时通讯
近端时间有需求完成一个即时通讯的需求,选择了腾讯的TIM及时通讯服务
TIM即时通讯。文档地址:https://cloud.tencent.com/document/product/269/36887
常规TIM集成文档:https://cloud.tencent.com/document/product/269/37412
最佳实践文档:https://cloud.tencent.com/document/product/269/43002
// IM Web SDK npm install tim-js-sdk --save // 发送图片、文件等消息需要的 COS SDK npm install cos-js-sdk-v5 --save
初始化(这是初始化一个 单个的而非群组的tim实例)
import TIM from 'tim-js-sdk'; // 发送图片、文件等消息需要的 COS SDK import COS from "cos-js-sdk-v5"; let options = { SDKAppID: 0 // 接入时需要将0替换为您的即时通信 IM 应用的 SDKAppID }; // 创建 SDK 实例,TIM.create() 方法对于同一个 SDKAppID 只会返回同一份实例 let tim = TIM.create(options); // SDK 实例通常用 tim 表示 // 设置 SDK 日志输出级别,详细分级请参见 setLogLevel 接口的说明 tim.setLogLevel(0); // 普通级别,日志量较多,接入时建议使用 // tim.setLogLevel(1); // release 级别,SDK 输出关键信息,生产环境时建议使用 // 注册 COS SDK 插件 tim.registerPlugin({'cos-js-sdk': COS});
这里可以绑定一些事件(例如):事件列表文档:https://cloud.tencent.com/document/product/269/37416
bindEvents(){//绑定tim的监听事件
var self=this;
self.tim.on(TIM.EVENT.SDK_READY, function(event) {
// 收到离线消息和会话列表同步完毕通知,接入侧可以调用 sendMessage 等需要鉴权的接口
// event.name - TIM.EVENT.SDK_READY
console.log(111)
});
tim.on(TIM.EVENT.KICKED_OUT, function (event) {// mutipleAccount(同一设备,同一帐号,多页面登录被踢)
console.log(event.data.type);
});
}
本地生成签名
userid和秘钥可以由后端接口返回,签名也可以由后端返回,但是本地生成签名时可以利用demo中提供的genTestUserSig.js来获取,用于本地调试用,线上需要后台接口返回(这些操作应该在登录之前)
genTestUserSig.js
/*eslint-disable*/ /* * Module: GenerateTestUserSig * * Function: 用于生成测试用的 UserSig,UserSig 是腾讯云为其云服务设计的一种安全保护签名。 * 其计算方法是对 SDKAppID、UserID 和 EXPIRETIME 进行加密,加密算法为 HMAC-SHA256。 * * Attention: 请不要将如下代码发布到您的线上正式版本的 App 中,原因如下: * * 本文件中的代码虽然能够正确计算出 UserSig,但仅适合快速调通 SDK 的基本功能,不适合线上产品, * 这是因为客户端代码中的 SECRETKEY 很容易被反编译逆向破解,尤其是 Web 端的代码被破解的难度几乎为零。 * 一旦您的密钥泄露,攻击者就可以计算出正确的 UserSig 来盗用您的腾讯云流量。 * * 正确的做法是将 UserSig 的计算代码和加密密钥放在您的业务服务器上,然后由 App 按需向您的服务器获取实时算出的 UserSig。 * 由于破解服务器的成本要高于破解客户端 App,所以服务器计算的方案能够更好地保护您的加密密钥。 * * Reference:https://cloud.tencent.com/document/product/647/17275#Server */ function genTestUserSig(userID,sdkAppId, Secretkey) { /** * 腾讯云 SDKAppId,需要替换为您自己账号下的 SDKAppId。 * * 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/rav ) 创建应用,即可看到 SDKAppId, * 它是腾讯云用于区分客户的唯一标识。 */ var SDKAPPID = sdkAppId? Number(sdkAppId) : 必须为数字; /** * 签名过期时间,建议不要设置的过短 * <p> * 时间单位:秒 * 默认时间:7 x 24 x 60 x 60 = 604800 = 7 天 */ var EXPIRETIME = 604800; /** * 计算签名用的加密密钥,获取步骤如下: * * step1. 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/rav ),如果还没有应用就创建一个, * step2. 单击“应用配置”进入基础配置页面,并进一步找到“帐号体系集成”部分。 * step3. 点击“查看密钥”按钮,就可以看到计算 UserSig 使用的加密的密钥了,请将其拷贝并复制到如下的变量中 * * 注意:该方案仅适用于调试Demo,正式上线前请将 UserSig 计算代码和密钥迁移到您的后台服务器上,以避免加密密钥泄露导致的流量盗用。 * 文档:https://cloud.tencent.com/document/product/647/17275#Server */ var SECRETKEY = Secretkey ? Secretkey : "xxxxxxx"; var generator = new window.LibGenerateTestUserSig(SDKAPPID, SECRETKEY, EXPIRETIME); var userSig = generator.genTestUserSig(userID); return { SDKAppID: SDKAPPID, userSig: userSig }; } export default { genTestUserSig //获取签名 }
登录
let promise = tim.login({userID: 'your userID', userSig: 'your userSig'});
promise.then(function(imResponse) {
console.log(imResponse.data); // 登录成功
}).catch(function(imError) {
console.warn('login error:', imError); // 登录失败的相关信息
});
登出
let promise = tim.logout(); promise.then(function(imResponse) { console.log(imResponse.data); // 登出成功 }).catch(function(imError) { console.warn('logout error:', imError); });
发送消息(这里是给摸一个人发送消息,但是一般项是在某个群组发送消息,这里举个例子)
sendTextMessage(){//tim发送消息
var self=this;
if(!self.messageContent){
tools.msgErr("请输入将要发送的消息");
return;
}
const message = self.tim.createTextMessage({
to: "user1",
conversationType: TIM.TYPES.CONV_C2C,
payload: { text: self.messageContent }
})
self.tim.sendMessage(message)
.then((imResponse)=>{
// 发送成功
console.log(imResponse);
})
.catch((imError)=>{
// 发送失败
console.warn('sendMessage error:', imError);
})
}
加入群组(需要在腾讯控制台创建群组,然后就有了群组id)
加入群组需要在登录成功回调再加入
// 加入群组 self.tim.joinGroup({ groupID:"群组id"}).then(function(imResponse) { console.log("===================加入群组成功============") switch (imResponse.data.status) { case TIM.TYPES.JOIN_STATUS_WAIT_APPROVAL: // 等待管理员同意 break case TIM.TYPES.JOIN_STATUS_SUCCESS: // 加群成功 console.log(imResponse.data.group) // 加入的群组资料 break case TIM.TYPES.JOIN_STATUS_ALREADY_IN_GROUP: // 已经在群中 break default: break } }).catch(function(imError){ console.log("===================加入群组失败============") console.warn('joinGroup error:', imError) // 申请加群失败的相关信息 });
项目实战:仅供参考(出问题需要自己微调)
// TIM相关 async timInit(){//初始化tim var self=this; // 初始化tim // self.roomDetail.imAppId self.tim =await timModule.initTIM(self.selfAppID);//获取到初始化后的tim实例 // 绑定监听事件: self.bindEvents(); // 生成签名 // var userSig=await self.$store.dispatch("getTencentImUserSig",self.getLoginAfterData.id); var userSig=genTestUserSig.genTestUserSig(self.getLoginAfterData.id?self.getLoginAfterData.id:self.selfUserId,self.selfAppID,self.selfSecretkey) console.log(userSig) // 登录 // var allowLogin=await self.$store.dispatch("timloginBefore",self.getLoginAfterData.id); // if(allowLogin){//如果允许用户登录页 则执行登录 self.tim.login({userID:self.getLoginAfterData.id?self.getLoginAfterData.id:self.selfUserId,userSig:userSig.userSig}).then(imResponse=>{//登录 console.log("===登录成功===") // console.log(imResponse.data); // 登录成功 }).catch(imError=>{ // console.warn('login error:', imError); // 登录失败的相关信息 }) // } }, joinGroup(){//加入群组 需要在登录成功后才能加入群组 var self=this; // 加入群组 // self.roomDetail.imGroupId console.log("==准备加入群组===") self.tim.joinGroup({ groupID:self.groupID}).then(function(imResponse) { if(imResponse.data.status==self.TIM.TYPES.JOIN_STATUS_SUCCESS){ console.log("===加入群组成功===") // self.tim.setMessageRead({conversationID:self.conversationID}) } }).catch(function(imError){ console.log("===加入群组失败===") console.warn('joinGroup error:', imError) // 申请加群失败的相关信息 }); }, getAppIdAndSecretKey(){//获取appid和秘钥 var self=this; return new Promise(reslove=>{ self.$store .dispatch("getToken") .then((token) => { return self.$store.dispatch( "getTencentSecret", self.$store.getters.getToken ) }) .then((appIdAndSecretKey) => { reslove(appIdAndSecretKey) }) }) }, getTencentImUserSig(userId){ this.$store.dispatch("getTencentImUserSig",userId); }, bindEvents(){//绑定tim的监听事件 var self=this; self.tim.on(self.TIM.EVENT.SDK_READY, this.sdkReady);//sdkReady self.tim.on(self.TIM.EVENT.KICKED_OUT,this.kickedOut);//有可能同名用户被踢出 self.tim.on(self.TIM.EVENT.ERROR,this.timError);//TIM内部出错 self.tim.on(self.TIM.EVENT.CONVERSATION_LIST_UPDATED,this.conversation_list_updated);//会话列表更新 self.tim.on(self.TIM.EVENT.GROUP_LIST_UPDATED,this.group_list_updated);//群组列表更新 self.tim.on(self.TIM.EVENT.MESSAGE_RECEIVED, this.message_received);//收到新消息 }, // 以下是tim的监听的回调函数 sdkReady({ name }){//sdkReady // 收到离线消息和会话列表同步完毕通知,接入侧可以调用 sendMessage 等需要鉴权的接口 // event.name - TIM.EVENT.SDK_READY console.log("===SDKready===") this.timSDKisReady= name === this.TIM.EVENT.SDK_READY ? true : false; this.tim .getMyProfile() .then(({ data }) => { this.$store.commit('updateCurrentUserProfile', data) }) .catch(error => { tools.msgErr(error.message) }) this.joinGroup();//加入群组 }, kickedOut(event){//被踢出 console.log("===被剔出===") // console.log(event.data.type); tools.msgErr("您已被踢出群组",3000); }, timError({data}){//tim错误回调 console.log("===SDK内部出错===") if (data.message !== 'Network Error') { tools.msgErr(data.message) } }, conversation_list_updated(event){//会话列表更新 var self=this; console.log("===会话列表更新===") if(!self.conversationID){//如果还没拿到会话ID var arr=event.data.filter(item=>item.type=="GROUP"); if(arr.length>0){ self.conversationID=arr[0].conversationID; } }else{ if(!self.haveCurrentConversation){//如果还未获取到会话资料 则获取一下 self.tim.getConversationProfile(self.conversationID).then(({ data }) => { console.log("===获取会话资料成功===") // 3.1 更新当前会话 self.$store.commit("setCurrentConversation",data.conversation); self.haveCurrentConversation=true;//标记获取了会话资料 // 3.2 获取消息列表 self.getMessageList(); }); } } }, group_list_updated(event){//群组列表更新 console.log("===群组列表更新===") // console.log(event.data) }, message_received({data:messageList}){//收到信息消息 // 收到推送的单聊、群聊、群提示、群系统通知的新消息,可通过遍历 event.data 获取消息列表数据并渲染到页面 // event.name - TIM.EVENT.MESSAGE_RECEIVED // event.data - 存储 Message 对象的数组 - [Message] console.log("===消息列表更新===") // console.log(messageList) this.pushCurrentMessageList(messageList);//向消息列表添加消息 }, sendTextMessage(){//tim发送消息 var self=this; if(!self.timSDKisReady){//timSDKisReady未准备成功 tools.msgErr("通信环境未准备完备,请稍后再试或者刷新网页",3000); return; } if(!(self.messageContent.trim())){ self.messageContent="";//重置文本消息框 tools.msgErr("请输入将要发送的消息"); return; } const message = self.tim.createTextMessage({ to: self.groupID,//群组id conversationType: self.TIM.TYPES.CONV_GROUP, payload: { text: self.messageContent } }) self.pushCurrentMessageList(message);//向消息列表添加消息 this.$bus.$emit('scroll-messageList-bottom');//消息框滚动到底部 self.tim.sendMessage(message) .then((imResponse)=>{ // 发送成功 console.log("=====消息发送成功=====") // console.log(imResponse); self.messageContent="";//重置文本消息框 }) .catch((imError)=>{ // 发送失败 console.log("=====消息发送失败=====") tools.msgErr(imError.message); }) }, getMessageList(){//获取消息列表信息 var self=this; self.tim.getMessageList({ conversationID:self.conversationID, nextReqMessageID:self.nextReqMessageID, count: 15 }).then(imReponse => { // 更新messageID,续拉时要用到 self.nextReqMessageID = imReponse.data.nextReqMessageID; self.isCompleted = imReponse.data.isCompleted; // 更新当前消息列表,从头部插入 self.currentMessageList = [...imReponse.data.messageList,...self.currentMessageList]; console.log("$$$$消息列表$$$$$"); console.log(self.currentMessageList) }) }, pushCurrentMessageList(data){//向消息列表添加数据 var self=this; // 还没当前会话,则跳过 if (!self.currentConversation.conversationID) { return } if (Array.isArray(data)) { // 筛选出当前会话的消息 const result = data.filter(item => item.conversationID === self.currentConversation.conversationID) self.currentMessageList = [...self.currentMessageList, ...result] } else if (data.conversationID === self.currentConversation.conversationID) { self.currentMessageList = [...self.currentMessageList, data] } console.log(">>>>>>>>向消息列表添加成功>>>>>>>") console.log(self.currentMessageList) }, // 直接滚到底部 scrollMessageListToButtom() { this.$nextTick(() => { let messageListNode = this.$refs['message-list'] if (!messageListNode) { return } messageListNode.scrollTop = messageListNode.scrollHeight; this.preScrollHeight = messageListNode.scrollHeight; }) }, }, destroyed() { // tim退出群组 this.tim.quitGroup(this.groupID).then((imResponse)=>{ console.log("退出群组成功") }).catch((imError)=>{ console.warn('quitGroup error:', imError); // 退出群组失败的相关信息 }) // 退出tim登陆 this.tim.logout(); // 取消绑定tim的各种事件 this.tim.off(this.TIM.EVENT.SDK_READY, this.sdkReady);//sdkReady this.tim.off(this.TIM.EVENT.KICKED_OUT,this.kickedOut);//有可能同名用户被踢出 this.tim.off(this.TIM.EVENT.ERROR,this.timError);//TIM内部出错 this.tim.off(this.TIM.EVENT.CONVERSATION_LIST_UPDATED,this.conversation_list_updated);//会话列表更新 this.tim.off(this.TIM.EVENT.GROUP_LIST_UPDATED,this.group_list_updated);//群组列表更新 this.tim.off(this.TIM.EVENT.MESSAGE_RECEIVED, this.message_received);//收到新消息 // 销毁socket实例 this.socket = null; }
TIM设置禁言/解禁:
支持禁言的群类型:

群类型:
GRP_AVCHATROOM: "AVChatRoom" //音视频聊天 GRP_CHATROOM: "ChatRoom"//聊天室 GRP_PRIVATE: "Private"//私有群 GRP_PUBLIC: "Public"//公开群
群成员类型:
GRP_MBR_ROLE_ADMIN: "Admin"//管理员 GRP_MBR_ROLE_MEMBER: "Member"//群成员 GRP_MBR_ROLE_OWNER: "Owner"//群主
确定群主类型是否有禁言功能,并且确认当前用户是否有禁言权限:此步骤必须在SDKReady就绪后才能调用
// 获取群组资料 self.tim.getGroupProfile({ groupID: self.groupID, groupCustomFieldFilter: [] }).then(function(imResponse) { var supportOffTalkGroupTypeArr=[self.TIM.TYPES.GRP_PUBLIC,self.TIM.TYPES.GRP_CHATROOM,self.TIM.TYPES.GRP_AVCHATROOM]; //当前群类型是否支持禁言功能 self.curGroupSupportOffTalk=supportOffTalkGroupTypeArr.includes(imResponse.data.group.type); //若该群支持禁言功能 if(self.curGroupSupportOffTalk){ self.tim.getGroupMemberProfile({ groupID: self.groupID, userIDList: [self.getLoginAfterData.id?self.getLoginAfterData.id:self.selfUserId], // 请注意:即使只拉取一个群成员的资料,也需要用数组类型,例如:userIDList: ['user1'] memberCustomFieldFilter: [], // 筛选群成员自定义字段:group_member_custom }).then(function(imResponse) { console.log(imResponse.data.memberList); // 群成员列表 // 非Member类型 都有禁言权限(app管理员、群主、管理员) if(imResponse.data.memberList.length>0&&imResponse.data.memberList[0].role!=self.TIM.TYPES.GRP_MBR_ROLE_MEMBER){ console.log("当前用户有禁言权限") self.curUserSupportOffTalk=true; } }).catch(function(imError) { console.warn('getGroupMemberProfile error:', imError); }); } }).catch(function(imError) { console.warn('getGroupProfile error:', imError); // 获取群详细资料失败的相关信息 });
禁言操作:
let promise = tim.setGroupMemberMuteTime({ groupID: 'group1', userID: 'user1', muteTime: 1000,//秒 });
在限制下拉组件显示时可以采用将元素高度、宽度设置为0的方式实现,如果直接v-if,
el-dropdown组件下没有el-dropdown-menu会报错,虽然不影响功能,但是有报错很烦人。
需要用样式穿透的方式去设置比如:、
<el-dropdown-menu slot="dropdown" :class="{width0:!bannedShow}"> <!-- <el-dropdown-item command="revoke" v-if="isMine">撤回</el-dropdown-item> --> <el-dropdown-item command="bannerTalk" v-if="bannedShow" >禁言</el-dropdown-item> </el-dropdown-menu>
css:
.width0/deep/ .popper__arrow:after{ border-bottom-width: 0; border-top-width: 0; } .width0/deep/ .popper__arrow{ border-width:0; } .width0{ border-width: 0; }
进一步实战:
<template>
<div class="IM">
<msg :msg="msgText" v-if="msgStatus" @changeMsgShow="changeMsgShow"></msg>
<div class="discuss_box">
<div class="message_list" ref="message-list">
<div class="no_more cursor" v-if="pageNo < dataChatContent.pages" @click="loadMoreList">点击加载更多</div>
<div class="no_more" v-else>没有更多了</div>
<message-item v-for="message in currentMessageList" :key="message.ID" :message="message"/>
</div>
<!-- -->
<div class="inner_bottom_box">
<!-- <div class="input_wrap">
<svg-icon style="font-size:20px;" icon-class="register"></svg-icon>
<div class="fakeInput">参与讨论</div>
</div> -->
<div class="bottomWrap">
<div style="padding: .2rem">
<textarea v-model="messageContent" @blur="temporaryRepair()" ></textarea>
</div>
<div class="drawer_bottom_box">
<div class="submit_button" @click="sendTextMessage()">发送</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapGetters, mapActions, mapState } from "vuex"
import timModule from "./js/initTIM.js";
import genTestUserSig from "./js/GenerateTestUserSig.js";//用来本地生成tim的签名
import MessageItem from './message/message-item.vue';
import msg from '../msg.vue'
import { promises } from 'fs';
export default {
components: {
MessageItem,
msg
},
data() {
return {
msgText: '',
msgStatus: false,
appId: null,
appKey: null,
userId: '',
userName: this.$store.getters.UserInfo,
dataIm: {},
dataImUserSig: '',
dataChatContent: {},
dataImUserSaveInfo: {}, //用户保存后的返回信息
pageSize: 30,
pageNo: 1,
total: 0,
messageContent: '',//发送的消息内容
timSDKisReady: false,//tim是否准备好
conversationID: '', //会话ID
nextReqMessageID:"",//获取下一个消息列表的ID 目前默认一页15条
isCompleted:false,//消息分页 是否到最后一页
currentMessageList: [],//当前消息列表
haveCurrentConversation: false,//判断是否获取了当前会话 自己设置的flag
}
},
props: ['liveData', 'imType'],
created() {
this.userName = `${this.getUserInfo.realName}_${this.getUserInfo.sn}` || this.randomString(16)
// this.userName = `${this.getUserInfo.realName}` || this.randomString(16)
this.init()
// this.sendTextMessage()
// console.log(this.getUserInfo)
},
mounted() {
this.$bus.$on('scroll-messageList-bottom', this.scrollMessageListToButtom);//绑定滚动到底部事件
},
computed: {
...mapGetters([
"getUserInfo",
"GET_MEETING_INFO"
]),
...mapState({
currentConversation: state=>state.conversation.currentConversation,//当前会话对象
curGroupSupportOffTalk: state=>state.conversation.curGroupSupportOffTalk,//当前群类型是否支持禁言 true:支持
curUserSupportOffTalk: state=>state.conversation.curUserSupportOffTalk,//当前用户是否有禁言权限
}),
},
methods: {
async init() {
//获取Key,id
await this.getImUserConfig()
await this.getImChatInfoAndConfig()
//获取到初始化后的tim实例
await timModule.initTIM(this.appId);
//获取签名
await this.getImSig()
//登录
this.tim.login({userID: this.userName, userSig: this.dataImUserSig}).then(imResponse=>{//登录
let params = {
Identifier: this.userName,
Nick: this.getUserInfo.realName || '',
FaceUrl: this.getUserInfo.headUrl || '',
mid: this.GET_MEETING_INFO.info.meeting.mid,
user_id: this.getUserInfo.id || ''
}
this.$api.imUserSave(params).then(res => {
this.dataImUserSaveInfo = res
})
}).catch(imError=>{
// console.log()
console.warn('登录失败:', imError); // 登录失败的相关信息
})
// 绑定监听事件:
this.bindEvents()
this.setServeDataJson('next')
},
getImUserConfig() {
return new Promise(resolve=>{
this.$api.getImConfig().then(res => {
this.appId = res.SDKIDForCloudlive
this.key = res.KEYForCloudlive
resolve()
})
})
},
getImChatInfoAndConfig() {
let params = {
type: this.imType,
mid: this.liveData.onliveSlot.mid,
onlive_room_id: this.liveData.onliveSlot.onlive_room_id,
onlive_slot_id: this.liveData.onliveSlot.id,
pageNo: this.pageNo,
pageSize: this.pageSize,
}
return new Promise(resolve=>{
this.$api.getImChat(params).then(res => {
if (res.success == true) {
this.dataIm = res.data.im
this.dataChatContent = res.data.chatContent
// console.log(res.data.chatContent,'========')
}
resolve()
})
})
},
getImSig() {
let params = {userId: this.userName}
return new Promise(resolve=>{
this.$api.getImSig(params).then(res => {
this.dataImUserSig = res
resolve()
})
})
},
//加载更多数据
async loadMoreList() {
if(this.pageNo < this.dataChatContent.pages) {
this.pageNo++
}
this.getImChatInfoAndConfig().then(res => {
this.setServeDataJson('pre')
})
},
//从后台返回的数据重新组装,并返回
setServeDataJson(type) {
if (this.dataChatContent) {
let arr = []
this.dataChatContent.dataList.forEach(item => {
arr.push(
{
"ID": "",
"conversationID": "",
"conversationType": "GROUP",
"time": new Date(item.create_time.replace(/\-/g, '/')).getTime() / 1000,
"sequence": 351,
"clientSequence": 1256270001,
"random": 18595726,
"priority": "Normal",
"nick": "",
"avatar": "",
"_elements": [ { "type": "TIMTextElem",
"content": { "text": item.content } } ],
"isPlaceMessage": 0,
"isRevoked": false,
"geo": {},
"from": item.user_name,
"to": "@TGS#aP26H4PGZ",
"flow": item.user_name == this.userName ? 'out' : 'in',
"isSystemMessage": false,
"protocol": "JSON",
"isResend": false,
"isRead": true,
"status": "success",
"payload": { "text": item.content },
"type": "TIMTextElem"
}
)
})
if (type == 'next')
this.currentMessageList = [...this.currentMessageList, ...arr]
else
this.currentMessageList = [...arr, ...this.currentMessageList]
}
},
bindEvents(){
//绑定tim的监听事件
this.tim.on(this.TIM.EVENT.SDK_READY, this.sdkReady);//sdkReady
this.tim.on(this.TIM.EVENT.KICKED_OUT,this.kickedOut);//有可能同名用户被踢出
this.tim.on(this.TIM.EVENT.ERROR,this.timError);//TIM内部出错
this.tim.on(this.TIM.EVENT.CONVERSATION_LIST_UPDATED,this.conversationListUpdated);//会话列表更新
this.tim.on(this.TIM.EVENT.MESSAGE_RECEIVED, this.messageReceived);//收到新消息
},
sdkReady({ name }) {
console.log("===SDKready===")
this.timSDKisReady = name === this.TIM.EVENT.SDK_READY ? true : false;
//加入群组
this.joinGroup()
// // 获取群组资料
this.tim.getGroupProfile({
groupID: this.dataIm.im_group_id,
groupCustomFieldFilter: []
})
.then(function(imResponse) {
var supportOffTalkGroupTypeArr=[this.TIM.TYPES.GRP_PUBLIC,this.TIM.TYPES.GRP_CHATROOM,this.TIM.TYPES.GRP_AVCHATROOM];
//当前群类型是否支持禁言功能
this.$store.commit("setCurGroupSupportOffTalk",supportOffTalkGroupTypeArr.includes(imResponse.data.group.type))
//若该群支持禁言功能
if(this.curGroupSupportOffTalk){
this.tim.getGroupMemberProfile({
groupID: this.groupID,
userIDList: [this.getUserInfo.id], // 请注意:即使只拉取一个群成员的资料,也需要用数组类型,例如:userIDList: ['user1']
memberCustomFieldFilter: [], // 筛选群成员自定义字段:group_member_custom
}).then(function(imResponse) {
// 非Member类型 都有禁言权限(app管理员、群主、管理员)
if(imResponse.data.memberList.length > 0 && imResponse.data.memberList[0].role != this.TIM.TYPES.GRP_MBR_ROLE_MEMBER){
this.$store.commit("setCurUserSupportOffTalk",true);
}
})
.catch(function(imError) {
console.warn('getGroupMemberProfile error:', imError);
});
}
}).catch(function(imError) {
console.log('getGroupProfile error:', imError); // 获取群详细资料失败的相关信息
})
},
joinGroup(){
// 加入群组
console.log("==准备加入群组===")
let that = this
this.tim.joinGroup({ groupID: this.dataIm.im_group_id}).then(function(imResponse) {
if(imResponse.data.status == that.TIM.TYPES.JOIN_STATUS_SUCCESS){
console.log("===加入群组成功===")
}
}).catch(function(imError){
console.log("===加入群组失败===")
console.warn('joinGroup error:', imError) // 申请加群失败的相关信息
})
},
kickedOut(event){//被踢出
console.log("===被剔出===")
// tools.msgErr("您已被踢出群组",3000);
},
conversationListUpdated(event) {
console.log("===会话列表更新===")
if(!this.conversationID){//如果还没拿到会话ID
var arr = event.data.filter(item=>item.type=="GROUP");
// console.log(arr)
if(arr.length > 0){
this.conversationID = arr[0].conversationID;
}
}else{
if(!this.haveCurrentConversation){//如果还未获取到会话资料 则获取一下
this.tim.getConversationProfile(this.conversationID).then(({ data }) => {
console.log("===获取会话资料成功===")
// 3.1 更新当前会话
this.$store.commit("setCurrentConversation",data.conversation);
this.haveCurrentConversation = true;//标记获取了会话资料
// 3.2 获取消息列表
this.getMessageList();
});
}
}
},
messageReceived({data:messageList}) {
// 收到推送的单聊、群聊、群提示、群系统通知的新消息,可通过遍历 event.data 获取消息列表数据并渲染到页面
// event.name - TIM.EVENT.MESSAGE_RECEIVED
// event.data - 存储 Message 对象的数组 - [Message]
console.log("===消息列表更新===")
// console.log(messageList)
this.pushCurrentMessageList(messageList);//向消息列表添加消息
},
pushCurrentMessageList(data) {
//向消息列表添加数据
// 还没当前会话,则跳过
// console.log(this.currentConversation.conversationID, 'this.currentConversation.conversationID')
if (!this.currentConversation.conversationID) {
return
}
if (Array.isArray(data)) {
// 筛选出当前会话的消息
const result = data.filter(item => item.conversationID === this.currentConversation.conversationID)
this.currentMessageList = [...this.currentMessageList, ...result]
} else if (data.conversationID === this.currentConversation.conversationID) {
this.currentMessageList = [...this.currentMessageList, data]
}
console.log(">>>>>>>>向消息列表添加成功>>>>>>>")
// console.log(this.currentMessageList, '正常')
},
timError() {
console.log("===SDK内部出错===")
if (data.message !== 'Network Error') {
// tools.msgErr(data.message)
}
},
scrollMessageListToButtom() {
this.$nextTick(() => {
let messageListNode = this.$refs['message-list']
if (!messageListNode) {
return
}
messageListNode.scrollTop = messageListNode.scrollHeight;
this.preScrollHeight = messageListNode.scrollHeight;
})
},
async checkSend() {
return new Promise(resolve=>{
this.$api.checkContentAuto({
content: this.messageContent,
user_name: this.userName,
user_head_url: this.getUserInfo.headUrl,
onlive_im_id: this.dataIm.id,
onlive_im_user_id: this.dataImUserSaveInfo.data.id
}).then(res => {
if (res.success == true) {
// 返回true直接发到IM
resolve()
} else {
this.msgStatus = true
this.msgText = '发送失败'
reject()
}
})
})
},
async sendTextMessage(){//tim发送消息
let that = this
// if(!self.getLoginAfterData.id){
// tools.msgErr("游客身份需要注册登录后才可以发言~",3000);
// return;
// }
//自动发
if (this.dataIm.audit_type == 1) {
await this.checkSend()
//
if(!this.timSDKisReady){
//timSDKisReady未准备成功
console.log('通信环境未准备完备,请稍后再试或者刷新网页')
// tools.msgErr("通信环境未准备完备,请稍后再试或者刷新网页",3000);
return;
} else {
console.log('通信环境准备完备,可以发送留言')
}
if(!(this.messageContent.trim())){
this.messageContent = "";//重置文本消息框
console.log('请输入将要发送的消息')
// tools.msgErr("请输入将要发送的消息");
return;
}
const message = this.tim.createTextMessage({
to: that.dataIm.im_group_id,//群组id
conversationType: that.TIM.TYPES.CONV_GROUP,
payload: { text: that.messageContent }
})
// message.avatar = this.getUserInfo.headUrl
this.pushCurrentMessageList(message);//向消息列表添加消息
this.$bus.$emit('scroll-messageList-bottom');//消息框滚动到底部
//向TIM发送数据
this.tim.sendMessage(message).then((imResponse)=>{
// 发送成功
console.log("=====消息发送成功=====")
// console.log(imResponse, '返回后的');
this.messageContent = "";//重置文本消息框
}).catch((imError)=>{
// 发送失败
console.log("=====消息发送失败=====")
// tools.msgErr(imError.message);
})
} else {
//非自动,向后台发送
this.$api.checkContentByManual({
content: this.messageContent,
user_name: this.userName,
user_head_url: this.getUserInfo.headUrl,
onlive_im_id: this.dataIm.id,
onlive_im_user_id: this.dataImUserSaveInfo.data.id
}).then(res => {
if (res.success == true) {
this.msgStatus = true
this.msgText = res.message
// console.log('发送后台成功')
//重置文本消息框
this.messageContent = ""
} else {
this.msgStatus = true
this.msgText = '发送失败'
}
return
})
}
},
async getMessageList(){
let that = this
//获取消息列表信息
return new Promise(resolve => {
that.tim.getMessageList({
conversationID: this.conversationID,
nextReqMessageID: this.nextReqMessageID,
count: 15
}).then(imReponse => {
// 更新messageID,续拉时要用到
that.nextReqMessageID = imReponse.data.nextReqMessageID;
that.isCompleted = imReponse.data.isCompleted;
// 更新当前消息列表,从头部插入
that.currentMessageList = [...imReponse.data.messageList,...that.currentMessageList];
// console.log("$$$$消息列表$$$$$");
// console.log(imReponse.data.messageList, 'empty')
resolve()
})
})
},
temporaryRepair() {
var currentPosition, timer
var speed = 1 //页面滚动距离
timer = setInterval(function() {
currentPosition =
document.documentElement.scrollTop || document.body.scrollTop
currentPosition -= speed
window.scrollTo(0, 0) //页面向上滚动
currentPosition += speed //speed变量
window.scrollTo(0, currentPosition) //页面向下滚动
clearInterval(timer)
}, 1)
},
randomString(len = 32) {
let chars = 'ABCDE_FGHJKMNPQRS_TWXYZabcd_efhijkmnprstw_xyz2345678';
let pwd = '';
for (var i = 0; i < len; i++) {
pwd += chars.charAt(Math.floor(Math.random() * chars.length));
}
return pwd;
},
changeMsgShow() {
this.msgStatus = false
this.msgText = ''
}
},
beforeDestroy() {
// 退出tim登陆
this.tim.logout();
// 取消绑定tim的各种事件
this.tim.off(this.TIM.EVENT.SDK_READY, this.sdkReady);//sdkReady
this.tim.off(this.TIM.EVENT.KICKED_OUT,this.kickedOut);//有可能同名用户被踢出
this.tim.off(this.TIM.EVENT.ERROR,this.timError);//TIM内部出错
this.tim.off(this.TIM.EVENT.CONVERSATION_LIST_UPDATED,this.conversationListUpdated);//会话列表更新
this.tim.off(this.TIM.EVENT.MESSAGE_RECEIVED, this.messageReceived);//收到新消息
},
}
</script>
<style lang="scss">
.discuss_box {
display: flex;
flex: 1;
height: 100%;
flex-direction: column;
}
.message_list{
flex: 1;
overflow-y: auto;
padding-bottom:60px;
}
textarea{
display: block;
border: 0;
height: .5rem;
font-size: .25rem;
width: calc(100% - .4rem);
padding: .2rem;
background-color: #f0f0f0;
}
.submit_button {
border-radius: 6px;
color: #ffffff;
font-weight: bold;
background-color: #2196F3;
font-size: 18px;
width: 100%;
line-height: .5rem;
line-height: .7rem;
margin:0 auto;
border-radius: 0 0 5px 5px;
text-align: center;
}
.bottomWrap{
box-shadow: 0 0px 5px rgba(0,0,0,.3);
}
.message_list img {
margin-top: 0;
}
.no_more{
display: flex;
justify-content: center;
color:#a7b5c1;
font-size: .16rem;
padding: 10px 10px;
}
.cursor{
color: #333;
cursor: pointer;
background-color: #f5f5f5;
}
</style>
。

浙公网安备 33010602011771号