zoukankan      html  css  js  c++  java
  • 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;
         calc(100% - .4rem);
        padding: .2rem;
        background-color: #f0f0f0;
    }
    .submit_button {
      border-radius: 6px;
      color: #ffffff;
      font-weight: bold;
      background-color: #2196F3;
      font-size: 18px;
       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>

  • 相关阅读:
    硬件加速器为人工智能应用服务
    js 获取指定字符串个数
    js 仿微信投诉—引入vue.js,拆分组件为单个js
    css 图片波浪效果
    svg path命令
    谷歌浏览器—打断点调试页面
    js 实现加载百分比效果
    js 实现纵向轮播
    css 图片高度自适应
    js 禁止/允许页面滚动
  • 原文地址:https://www.cnblogs.com/fqh123/p/12696124.html
Copyright © 2011-2022 走看看