vue项目中集成腾讯TIM即时通讯

时间:2024-03-09 20:44:45

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