近端时间有需求完成一个即时通讯的需求,选择了腾讯的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-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>
。