vue項目中集成騰訊TIM即時通訊


近端時間有需求完成一個即時通訊的需求,選擇了騰訊的TIM及時通訊服務

TIM即時通訊。文檔地址:https://cloud.tencent.com/document/product/269/36887

常規TIM集成文檔:https://cloud.tencent.com/document/product/269/37412

最佳實踐文檔:https://cloud.tencent.com/document/product/269/43002

 

// IM Web SDK
npm install tim-js-sdk --save
// 發送圖片、文件等消息需要的 COS SDK
npm install cos-js-sdk-v5 --save

初始化(這是初始化一個 單個的而非群組的tim實例)

import TIM from 'tim-js-sdk';
// 發送圖片、文件等消息需要的 COS SDK
import COS from "cos-js-sdk-v5";

let options = {
  SDKAppID: 0 // 接入時需要將0替換為您的即時通信 IM 應用的 SDKAppID
};
// 創建 SDK 實例,TIM.create() 方法對於同一個 SDKAppID 只會返回同一份實例
let tim = TIM.create(options); // SDK 實例通常用 tim 表示

// 設置 SDK 日志輸出級別,詳細分級請參見 setLogLevel 接口的說明
tim.setLogLevel(0); // 普通級別,日志量較多,接入時建議使用
// tim.setLogLevel(1); // release 級別,SDK 輸出關鍵信息,生產環境時建議使用

// 注冊 COS SDK 插件
tim.registerPlugin({'cos-js-sdk': COS});

 這里可以綁定一些事件(例如):事件列表文檔:https://cloud.tencent.com/document/product/269/37416

bindEvents(){//綁定tim的監聽事件
      var self=this;
      self.tim.on(TIM.EVENT.SDK_READY, function(event) {
        // 收到離線消息和會話列表同步完畢通知,接入側可以調用 sendMessage 等需要鑒權的接口
        // event.name - TIM.EVENT.SDK_READY
        console.log(111)
      });
      tim.on(TIM.EVENT.KICKED_OUT, function (event) {// mutipleAccount(同一設備,同一帳號,多頁面登錄被踢)
        console.log(event.data.type); 
      });
    }

 

本地生成簽名

userid和秘鑰可以由后端接口返回,簽名也可以由后端返回,但是本地生成簽名時可以利用demo中提供的genTestUserSig.js來獲取,用於本地調試用,線上需要后台接口返回(這些操作應該在登錄之前)

genTestUserSig.js

/*eslint-disable*/
/*
 * Module:   GenerateTestUserSig
 *
 * Function: 用於生成測試用的 UserSig,UserSig 是騰訊雲為其雲服務設計的一種安全保護簽名。
 *           其計算方法是對 SDKAppID、UserID 和 EXPIRETIME 進行加密,加密算法為 HMAC-SHA256。
 *
 * Attention: 請不要將如下代碼發布到您的線上正式版本的 App 中,原因如下:
 *
 *            本文件中的代碼雖然能夠正確計算出 UserSig,但僅適合快速調通 SDK 的基本功能,不適合線上產品,
 *            這是因為客戶端代碼中的 SECRETKEY 很容易被反編譯逆向破解,尤其是 Web 端的代碼被破解的難度幾乎為零。
 *            一旦您的密鑰泄露,攻擊者就可以計算出正確的 UserSig 來盜用您的騰訊雲流量。
 *
 *            正確的做法是將 UserSig 的計算代碼和加密密鑰放在您的業務服務器上,然后由 App 按需向您的服務器獲取實時算出的 UserSig。
 *            由於破解服務器的成本要高於破解客戶端 App,所以服務器計算的方案能夠更好地保護您的加密密鑰。
 *
 * Reference:https://cloud.tencent.com/document/product/647/17275#Server
 */
function genTestUserSig(userID,sdkAppId, Secretkey) {
  /**
   * 騰訊雲 SDKAppId,需要替換為您自己賬號下的 SDKAppId。
   *
   * 進入騰訊雲實時音視頻[控制台](https://console.cloud.tencent.com/rav ) 創建應用,即可看到 SDKAppId,
   * 它是騰訊雲用於區分客戶的唯一標識。
   */
  var SDKAPPID = sdkAppId? Number(sdkAppId) : 必須為數字;

  /**
   * 簽名過期時間,建議不要設置的過短
   * <p>
   * 時間單位:秒
   * 默認時間:7 x 24 x 60 x 60 = 604800 = 7 天
   */
  var EXPIRETIME = 604800;

  /**
   * 計算簽名用的加密密鑰,獲取步驟如下:
   *
   * step1. 進入騰訊雲實時音視頻[控制台](https://console.cloud.tencent.com/rav ),如果還沒有應用就創建一個,
   * step2. 單擊“應用配置”進入基礎配置頁面,並進一步找到“帳號體系集成”部分。
   * step3. 點擊“查看密鑰”按鈕,就可以看到計算 UserSig 使用的加密的密鑰了,請將其拷貝並復制到如下的變量中
   *
   * 注意:該方案僅適用於調試Demo,正式上線前請將 UserSig 計算代碼和密鑰遷移到您的后台服務器上,以避免加密密鑰泄露導致的流量盜用。
   * 文檔:https://cloud.tencent.com/document/product/647/17275#Server
   */
  var SECRETKEY = Secretkey
  ? Secretkey
  : "xxxxxxx";

  var generator = new window.LibGenerateTestUserSig(SDKAPPID, SECRETKEY, EXPIRETIME);
  var userSig = generator.genTestUserSig(userID);
  return {
    SDKAppID: SDKAPPID,
    userSig: userSig
  };
}
export default {
  genTestUserSig //獲取簽名
}

 

登錄

let promise = tim.login({userID: 'your userID', userSig: 'your userSig'});
promise.then(function(imResponse) {
  console.log(imResponse.data); // 登錄成功
}).catch(function(imError) {
  console.warn('login error:', imError); // 登錄失敗的相關信息
});

 登出

let promise = tim.logout();
promise.then(function(imResponse) {
  console.log(imResponse.data); // 登出成功
}).catch(function(imError) {
  console.warn('logout error:', imError);
});

 

發送消息(這里是給摸一個人發送消息,但是一般項是在某個群組發送消息,這里舉個例子)

sendTextMessage(){//tim發送消息
      var self=this;
      if(!self.messageContent){
        tools.msgErr("請輸入將要發送的消息");
        return;
      }
      const message = self.tim.createTextMessage({
        to: "user1",
        conversationType: TIM.TYPES.CONV_C2C,
        payload: { text: self.messageContent }
      })
      self.tim.sendMessage(message)
      .then((imResponse)=>{
        // 發送成功
        console.log(imResponse);
      })
      .catch((imError)=>{
        // 發送失敗
        console.warn('sendMessage error:', imError);
      })
    }

 加入群組(需要在騰訊控制台創建群組,然后就有了群組id)

加入群組需要在登錄成功回調再加入

// 加入群組
        self.tim.joinGroup({ groupID:"群組id"}).then(function(imResponse) {
          console.log("===================加入群組成功============")
          switch (imResponse.data.status) {
            case TIM.TYPES.JOIN_STATUS_WAIT_APPROVAL: // 等待管理員同意
              break
            case TIM.TYPES.JOIN_STATUS_SUCCESS: // 加群成功
              console.log(imResponse.data.group) // 加入的群組資料
              break
            case TIM.TYPES.JOIN_STATUS_ALREADY_IN_GROUP: // 已經在群中
              break
            default:
              break
          }
        }).catch(function(imError){
          console.log("===================加入群組失敗============")
          console.warn('joinGroup error:', imError) // 申請加群失敗的相關信息
        });

 

 項目實戰:僅供參考(出問題需要自己微調)

// TIM相關
    async timInit(){//初始化tim
      var self=this;
      // 初始化tim
      // self.roomDetail.imAppId
      self.tim =await timModule.initTIM(self.selfAppID);//獲取到初始化后的tim實例
      // 綁定監聽事件:
      self.bindEvents();
      // 生成簽名
      // var userSig=await self.$store.dispatch("getTencentImUserSig",self.getLoginAfterData.id);
      var userSig=genTestUserSig.genTestUserSig(self.getLoginAfterData.id?self.getLoginAfterData.id:self.selfUserId,self.selfAppID,self.selfSecretkey)
      console.log(userSig)
      // 登錄
      // var allowLogin=await self.$store.dispatch("timloginBefore",self.getLoginAfterData.id);
      // if(allowLogin){//如果允許用戶登錄頁 則執行登錄
        self.tim.login({userID:self.getLoginAfterData.id?self.getLoginAfterData.id:self.selfUserId,userSig:userSig.userSig}).then(imResponse=>{//登錄
          console.log("===登錄成功===")
          // console.log(imResponse.data); // 登錄成功
        }).catch(imError=>{
          // console.warn('login error:', imError); // 登錄失敗的相關信息
        })
      // } 
    },
    joinGroup(){//加入群組 需要在登錄成功后才能加入群組
      var self=this;
      // 加入群組
      // self.roomDetail.imGroupId
      console.log("==准備加入群組===")
      self.tim.joinGroup({ groupID:self.groupID}).then(function(imResponse) {
        if(imResponse.data.status==self.TIM.TYPES.JOIN_STATUS_SUCCESS){
            console.log("===加入群組成功===")
            // self.tim.setMessageRead({conversationID:self.conversationID})
            
        }
      }).catch(function(imError){
        console.log("===加入群組失敗===")
        console.warn('joinGroup error:', imError) // 申請加群失敗的相關信息
      });
    },
    getAppIdAndSecretKey(){//獲取appid和秘鑰
      var self=this;
      return new Promise(reslove=>{
        self.$store
        .dispatch("getToken")
        .then((token) => {
          return self.$store.dispatch(
            "getTencentSecret",
            self.$store.getters.getToken
          )
        })
        .then((appIdAndSecretKey) => {
          reslove(appIdAndSecretKey)
        })
      })
    },
    getTencentImUserSig(userId){
      this.$store.dispatch("getTencentImUserSig",userId);
    },
    bindEvents(){//綁定tim的監聽事件
      var self=this;
      self.tim.on(self.TIM.EVENT.SDK_READY, this.sdkReady);//sdkReady
      self.tim.on(self.TIM.EVENT.KICKED_OUT,this.kickedOut);//有可能同名用戶被踢出
      self.tim.on(self.TIM.EVENT.ERROR,this.timError);//TIM內部出錯
      self.tim.on(self.TIM.EVENT.CONVERSATION_LIST_UPDATED,this.conversation_list_updated);//會話列表更新
      self.tim.on(self.TIM.EVENT.GROUP_LIST_UPDATED,this.group_list_updated);//群組列表更新
      self.tim.on(self.TIM.EVENT.MESSAGE_RECEIVED, this.message_received);//收到新消息
    },
    // 以下是tim的監聽的回調函數
    sdkReady({ name }){//sdkReady
      // 收到離線消息和會話列表同步完畢通知,接入側可以調用 sendMessage 等需要鑒權的接口
      // event.name - TIM.EVENT.SDK_READY
      console.log("===SDKready===")
      this.timSDKisReady= name === this.TIM.EVENT.SDK_READY ? true : false;
      this.tim
        .getMyProfile()
        .then(({ data }) => {
          this.$store.commit('updateCurrentUserProfile', data)
        })
        .catch(error => {
          tools.msgErr(error.message)
        })
      this.joinGroup();//加入群組
    },
    kickedOut(event){//被踢出
      console.log("===被剔出===")
      // console.log(event.data.type);
      tools.msgErr("您已被踢出群組",3000); 
    },
    timError({data}){//tim錯誤回調
      console.log("===SDK內部出錯===")
      if (data.message !== 'Network Error') {
        tools.msgErr(data.message)
      }
    },
    conversation_list_updated(event){//會話列表更新
      var self=this;
      console.log("===會話列表更新===")
      if(!self.conversationID){//如果還沒拿到會話ID
        var arr=event.data.filter(item=>item.type=="GROUP");
        if(arr.length>0){
          self.conversationID=arr[0].conversationID;
        }
        
      }else{
        if(!self.haveCurrentConversation){//如果還未獲取到會話資料 則獲取一下
          self.tim.getConversationProfile(self.conversationID).then(({ data }) => {
            console.log("===獲取會話資料成功===")
            // 3.1 更新當前會話
            self.$store.commit("setCurrentConversation",data.conversation);
            self.haveCurrentConversation=true;//標記獲取了會話資料
            // 3.2 獲取消息列表
            self.getMessageList();
          });
        } 
      }
    },
    group_list_updated(event){//群組列表更新
      console.log("===群組列表更新===")
      // console.log(event.data)
    },
    message_received({data:messageList}){//收到信息消息
      // 收到推送的單聊、群聊、群提示、群系統通知的新消息,可通過遍歷 event.data 獲取消息列表數據並渲染到頁面
      // event.name - TIM.EVENT.MESSAGE_RECEIVED
      // event.data - 存儲 Message 對象的數組 - [Message]
      
      console.log("===消息列表更新===")
      // console.log(messageList)
      this.pushCurrentMessageList(messageList);//向消息列表添加消息
    },
    sendTextMessage(){//tim發送消息
      var self=this;
      if(!self.timSDKisReady){//timSDKisReady未准備成功
        tools.msgErr("通信環境未准備完備,請稍后再試或者刷新網頁",3000);
        return;
      }
      if(!(self.messageContent.trim())){
        self.messageContent="";//重置文本消息框
        tools.msgErr("請輸入將要發送的消息");
        return;
      }
      const message = self.tim.createTextMessage({
        to: self.groupID,//群組id
        conversationType: self.TIM.TYPES.CONV_GROUP,
        payload: { text: self.messageContent }
      })
      self.pushCurrentMessageList(message);//向消息列表添加消息
      this.$bus.$emit('scroll-messageList-bottom');//消息框滾動到底部
      self.tim.sendMessage(message)
      .then((imResponse)=>{
        // 發送成功
        console.log("=====消息發送成功=====")
        // console.log(imResponse);
        self.messageContent="";//重置文本消息框
      })
      .catch((imError)=>{
        // 發送失敗
        console.log("=====消息發送失敗=====")
        tools.msgErr(imError.message);
      })
    },
    getMessageList(){//獲取消息列表信息
      var self=this;
      self.tim.getMessageList({ conversationID:self.conversationID, nextReqMessageID:self.nextReqMessageID, count: 15 }).then(imReponse => {
        
        // 更新messageID,續拉時要用到
        self.nextReqMessageID = imReponse.data.nextReqMessageID;
        self.isCompleted = imReponse.data.isCompleted;
        // 更新當前消息列表,從頭部插入
        self.currentMessageList = [...imReponse.data.messageList,...self.currentMessageList];
        console.log("$$$$消息列表$$$$$");
        console.log(self.currentMessageList)
      })
    },
    pushCurrentMessageList(data){//向消息列表添加數據
      var self=this;
      // 還沒當前會話,則跳過
      if (!self.currentConversation.conversationID) {
        return
      }
      if (Array.isArray(data)) {
        // 篩選出當前會話的消息
        const result = data.filter(item => item.conversationID === self.currentConversation.conversationID)
        self.currentMessageList = [...self.currentMessageList, ...result]
      } else if (data.conversationID === self.currentConversation.conversationID) {
        self.currentMessageList = [...self.currentMessageList, data]
      }
      console.log(">>>>>>>>向消息列表添加成功>>>>>>>")
      console.log(self.currentMessageList)
    },
    // 直接滾到底部
    scrollMessageListToButtom() {
      this.$nextTick(() => {
        let messageListNode = this.$refs['message-list']
        if (!messageListNode) {
          return
        }
        messageListNode.scrollTop = messageListNode.scrollHeight;
        this.preScrollHeight = messageListNode.scrollHeight;
      })
    },
  },
  destroyed() {
    // tim退出群組
    this.tim.quitGroup(this.groupID).then((imResponse)=>{
      console.log("退出群組成功")
      
    }).catch((imError)=>{
      console.warn('quitGroup error:', imError); // 退出群組失敗的相關信息
    })
    // 退出tim登陸
    this.tim.logout();
    // 取消綁定tim的各種事件
    this.tim.off(this.TIM.EVENT.SDK_READY, this.sdkReady);//sdkReady
    this.tim.off(this.TIM.EVENT.KICKED_OUT,this.kickedOut);//有可能同名用戶被踢出
    this.tim.off(this.TIM.EVENT.ERROR,this.timError);//TIM內部出錯
    this.tim.off(this.TIM.EVENT.CONVERSATION_LIST_UPDATED,this.conversation_list_updated);//會話列表更新
    this.tim.off(this.TIM.EVENT.GROUP_LIST_UPDATED,this.group_list_updated);//群組列表更新
    this.tim.off(this.TIM.EVENT.MESSAGE_RECEIVED, this.message_received);//收到新消息
    // 銷毀socket實例
    this.socket = null;
    
  }

 TIM設置禁言/解禁:

支持禁言的群類型:

 

 群類型:

GRP_AVCHATROOM: "AVChatRoom" //音視頻聊天
GRP_CHATROOM: "ChatRoom"//聊天室
GRP_PRIVATE: "Private"//私有群
GRP_PUBLIC: "Public"//公開群

群成員類型:

GRP_MBR_ROLE_ADMIN: "Admin"//管理員
GRP_MBR_ROLE_MEMBER: "Member"//群成員
GRP_MBR_ROLE_OWNER: "Owner"//群主

 確定群主類型是否有禁言功能,並且確認當前用戶是否有禁言權限:此步驟必須在SDKReady就緒后才能調用

// 獲取群組資料
      self.tim.getGroupProfile({ groupID: self.groupID, groupCustomFieldFilter: [] }).then(function(imResponse) {
        var supportOffTalkGroupTypeArr=[self.TIM.TYPES.GRP_PUBLIC,self.TIM.TYPES.GRP_CHATROOM,self.TIM.TYPES.GRP_AVCHATROOM];
        //當前群類型是否支持禁言功能
        self.curGroupSupportOffTalk=supportOffTalkGroupTypeArr.includes(imResponse.data.group.type);
        //若該群支持禁言功能
        if(self.curGroupSupportOffTalk){
          self.tim.getGroupMemberProfile({
            groupID: self.groupID,
            userIDList: [self.getLoginAfterData.id?self.getLoginAfterData.id:self.selfUserId], // 請注意:即使只拉取一個群成員的資料,也需要用數組類型,例如:userIDList: ['user1']
            memberCustomFieldFilter: [], // 篩選群成員自定義字段:group_member_custom
          }).then(function(imResponse) {
            console.log(imResponse.data.memberList); // 群成員列表
            // 非Member類型 都有禁言權限(app管理員、群主、管理員)
            if(imResponse.data.memberList.length>0&&imResponse.data.memberList[0].role!=self.TIM.TYPES.GRP_MBR_ROLE_MEMBER){
              console.log("當前用戶有禁言權限")
              self.curUserSupportOffTalk=true;
            }
          }).catch(function(imError) {
            console.warn('getGroupMemberProfile error:', imError);
          });
        }
      }).catch(function(imError) {
        console.warn('getGroupProfile error:', imError); // 獲取群詳細資料失敗的相關信息
      });

 禁言操作:

let promise = tim.setGroupMemberMuteTime({
  groupID: 'group1',
  userID: 'user1',
  muteTime: 1000,//秒
});

 在限制下拉組件顯示時可以采用將元素高度、寬度設置為0的方式實現,如果直接v-if,

el-dropdown組件下沒有el-dropdown-menu會報錯,雖然不影響功能,但是有報錯很煩人。
需要用樣式穿透的方式去設置比如:、
<el-dropdown-menu slot="dropdown" :class="{width0:!bannedShow}">
        <!-- <el-dropdown-item command="revoke" v-if="isMine">撤回</el-dropdown-item> -->
        <el-dropdown-item command="bannerTalk" v-if="bannedShow" >禁言</el-dropdown-item>
      </el-dropdown-menu>

css:

.width0/deep/ .popper__arrow:after{
  border-bottom-width: 0;
  border-top-width: 0;
}
.width0/deep/ .popper__arrow{
  border-width:0;
}
.width0{
  border-width: 0;
}

 

 進一步實戰:

<template>
    <div class="IM">
        <msg :msg="msgText" v-if="msgStatus" @changeMsgShow="changeMsgShow"></msg>
        <div class="discuss_box">
            <div class="message_list" ref="message-list">
                <div class="no_more cursor" v-if="pageNo < dataChatContent.pages" @click="loadMoreList">點擊加載更多</div>
                <div class="no_more" v-else>沒有更多了</div>
                <message-item v-for="message in currentMessageList" :key="message.ID" :message="message"/>
            </div>
            <!--  -->
            <div class="inner_bottom_box">
                <!-- <div class="input_wrap">
                    <svg-icon style="font-size:20px;" icon-class="register"></svg-icon>
                    <div class="fakeInput">參與討論</div>
                </div> -->
                <div class="bottomWrap">
                    <div style="padding: .2rem">
                        <textarea v-model="messageContent" @blur="temporaryRepair()" ></textarea>
                    </div>
                    <div class="drawer_bottom_box">
                        <div class="submit_button" @click="sendTextMessage()">發送</div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>
<script>
import { mapGetters, mapActions, mapState } from "vuex"
import timModule from "./js/initTIM.js";
import genTestUserSig from "./js/GenerateTestUserSig.js";//用來本地生成tim的簽名
import MessageItem from './message/message-item.vue';
import msg from '../msg.vue'
import { promises } from 'fs';

export default {
    components: {
        MessageItem,
        msg
    },
    data() {
        return {
            msgText: '',
            msgStatus: false,
            appId: null,
            appKey: null,
            userId: '',
            userName: this.$store.getters.UserInfo,
            dataIm: {},
            dataImUserSig: '',
            dataChatContent: {},
            dataImUserSaveInfo: {}, //用戶保存后的返回信息
            pageSize: 30,
            pageNo: 1,
            total: 0,
            messageContent: '',//發送的消息內容
            timSDKisReady: false,//tim是否准備好
            conversationID: '', //會話ID
            nextReqMessageID:"",//獲取下一個消息列表的ID 目前默認一頁15條
            isCompleted:false,//消息分頁 是否到最后一頁
            currentMessageList: [],//當前消息列表
            haveCurrentConversation: false,//判斷是否獲取了當前會話 自己設置的flag
        }
    },
    props: ['liveData', 'imType'],

    created() {
        this.userName = `${this.getUserInfo.realName}_${this.getUserInfo.sn}` || this.randomString(16)
        // this.userName = `${this.getUserInfo.realName}` || this.randomString(16)

        this.init()
        // this.sendTextMessage()
        // console.log(this.getUserInfo)
    },
    mounted() {
        this.$bus.$on('scroll-messageList-bottom', this.scrollMessageListToButtom);//綁定滾動到底部事件
    },
    computed: {
        ...mapGetters([
            "getUserInfo",
            "GET_MEETING_INFO"
        ]),
        ...mapState({
            currentConversation: state=>state.conversation.currentConversation,//當前會話對象
            curGroupSupportOffTalk: state=>state.conversation.curGroupSupportOffTalk,//當前群類型是否支持禁言 true:支持
            curUserSupportOffTalk: state=>state.conversation.curUserSupportOffTalk,//當前用戶是否有禁言權限
        }),
    },
    methods: {
        async init() {
            //獲取Key,id
            await this.getImUserConfig()
            await this.getImChatInfoAndConfig()
            

            //獲取到初始化后的tim實例
            await timModule.initTIM(this.appId);

            //獲取簽名
            await this.getImSig()

            //登錄
            this.tim.login({userID: this.userName, userSig: this.dataImUserSig}).then(imResponse=>{//登錄
                let params = {
                    Identifier: this.userName,
                    Nick: this.getUserInfo.realName || '',
                    FaceUrl: this.getUserInfo.headUrl || '',
                    mid: this.GET_MEETING_INFO.info.meeting.mid,
                    user_id: this.getUserInfo.id || ''
                }
                this.$api.imUserSave(params).then(res => {
                    this.dataImUserSaveInfo = res
                })
            }).catch(imError=>{
                // console.log()
                console.warn('登錄失敗:', imError); // 登錄失敗的相關信息
            })

            

            // 綁定監聽事件:
            this.bindEvents()


            this.setServeDataJson('next')
        },
        getImUserConfig() {
            return new Promise(resolve=>{
                this.$api.getImConfig().then(res => {
                   this.appId = res.SDKIDForCloudlive
                   this.key = res.KEYForCloudlive
                    resolve()
                })
            })
        },
        getImChatInfoAndConfig() {
           let params = {
                    type: this.imType,
                    mid: this.liveData.onliveSlot.mid,
                    onlive_room_id: this.liveData.onliveSlot.onlive_room_id,
                    onlive_slot_id: this.liveData.onliveSlot.id,
                    pageNo: this.pageNo,
                    pageSize: this.pageSize,
            }
           return new Promise(resolve=>{
                this.$api.getImChat(params).then(res => {
                    if (res.success == true) {
                       this.dataIm = res.data.im
                       this.dataChatContent = res.data.chatContent
                    //    console.log(res.data.chatContent,'========')
                    }
                    resolve()
                })
            })
        },
        getImSig() {
            let params = {userId: this.userName}
            return new Promise(resolve=>{
                this.$api.getImSig(params).then(res => {
                    this.dataImUserSig = res
                    resolve()
                })
            })
        },
        //加載更多數據
        async loadMoreList() {
            if(this.pageNo < this.dataChatContent.pages) {
                this.pageNo++
            }
            this.getImChatInfoAndConfig().then(res => {
                this.setServeDataJson('pre')
            })
        },
        //從后台返回的數據重新組裝,並返回
        setServeDataJson(type) {
            if (this.dataChatContent) {
                let arr = []
                this.dataChatContent.dataList.forEach(item => {
                    arr.push(
                        {
                            "ID": "",
                            "conversationID": "",
                            "conversationType": "GROUP",
                            "time": new Date(item.create_time.replace(/\-/g, '/')).getTime() / 1000,
                            "sequence": 351,
                            "clientSequence": 1256270001,
                            "random": 18595726,
                            "priority": "Normal",
                            "nick": "",
                            "avatar": "",
                            "_elements": [ { "type": "TIMTextElem",
                            "content": { "text": item.content } } ],
                            "isPlaceMessage": 0,
                            "isRevoked": false,
                            "geo": {},
                            "from": item.user_name,
                            "to": "@TGS#aP26H4PGZ",
                            "flow": item.user_name == this.userName ? 'out' : 'in',
                            "isSystemMessage": false,
                            "protocol": "JSON",
                            "isResend": false,
                            "isRead": true,
                            "status": "success",
                            "payload": { "text": item.content },
                            "type": "TIMTextElem"
                        }
                    )
                })
                if (type == 'next')
                    this.currentMessageList = [...this.currentMessageList, ...arr]
                else
                    this.currentMessageList = [...arr, ...this.currentMessageList]
            }
        },
        bindEvents(){
        //綁定tim的監聽事件
            this.tim.on(this.TIM.EVENT.SDK_READY, this.sdkReady);//sdkReady
            this.tim.on(this.TIM.EVENT.KICKED_OUT,this.kickedOut);//有可能同名用戶被踢出
            this.tim.on(this.TIM.EVENT.ERROR,this.timError);//TIM內部出錯
            this.tim.on(this.TIM.EVENT.CONVERSATION_LIST_UPDATED,this.conversationListUpdated);//會話列表更新
            this.tim.on(this.TIM.EVENT.MESSAGE_RECEIVED, this.messageReceived);//收到新消息
        },
        sdkReady({ name }) {
            console.log("===SDKready===")
            this.timSDKisReady = name === this.TIM.EVENT.SDK_READY ? true : false;

            //加入群組
            this.joinGroup()

            // // 獲取群組資料
            this.tim.getGroupProfile({ 
                groupID: this.dataIm.im_group_id, 
                groupCustomFieldFilter: [] 
            })
            .then(function(imResponse) {
                var supportOffTalkGroupTypeArr=[this.TIM.TYPES.GRP_PUBLIC,this.TIM.TYPES.GRP_CHATROOM,this.TIM.TYPES.GRP_AVCHATROOM];
                //當前群類型是否支持禁言功能
                this.$store.commit("setCurGroupSupportOffTalk",supportOffTalkGroupTypeArr.includes(imResponse.data.group.type))
                //若該群支持禁言功能
                if(this.curGroupSupportOffTalk){
                    this.tim.getGroupMemberProfile({
                        groupID: this.groupID,
                        userIDList: [this.getUserInfo.id], // 請注意:即使只拉取一個群成員的資料,也需要用數組類型,例如:userIDList: ['user1']
                        memberCustomFieldFilter: [], // 篩選群成員自定義字段:group_member_custom
                    }).then(function(imResponse) {
                        // 非Member類型 都有禁言權限(app管理員、群主、管理員)
                        if(imResponse.data.memberList.length > 0 && imResponse.data.memberList[0].role != this.TIM.TYPES.GRP_MBR_ROLE_MEMBER){
                        this.$store.commit("setCurUserSupportOffTalk",true);
                        }
                    })
                    .catch(function(imError) {
                        console.warn('getGroupMemberProfile error:', imError);
                    });
                }
                
            }).catch(function(imError) {
                console.log('getGroupProfile error:', imError); // 獲取群詳細資料失敗的相關信息
            })
        },
        joinGroup(){
            // 加入群組
            console.log("==准備加入群組===")
            let that = this
            this.tim.joinGroup({ groupID: this.dataIm.im_group_id}).then(function(imResponse) {
                if(imResponse.data.status == that.TIM.TYPES.JOIN_STATUS_SUCCESS){
                    console.log("===加入群組成功===")
                }
            }).catch(function(imError){
                console.log("===加入群組失敗===")
                console.warn('joinGroup error:', imError) // 申請加群失敗的相關信息
            })
        },
        kickedOut(event){//被踢出
            console.log("===被剔出===")
        // tools.msgErr("您已被踢出群組",3000); 
        },
        conversationListUpdated(event) {
            console.log("===會話列表更新===")
            if(!this.conversationID){//如果還沒拿到會話ID
                var arr = event.data.filter(item=>item.type=="GROUP");
                // console.log(arr)
                if(arr.length > 0){
                    this.conversationID = arr[0].conversationID;
                }
            }else{

                if(!this.haveCurrentConversation){//如果還未獲取到會話資料 則獲取一下
                    this.tim.getConversationProfile(this.conversationID).then(({ data }) => {
                        console.log("===獲取會話資料成功===")
                        // 3.1 更新當前會話
                        this.$store.commit("setCurrentConversation",data.conversation);
                        this.haveCurrentConversation = true;//標記獲取了會話資料
                        // 3.2 獲取消息列表
                        this.getMessageList();
                    });
                } 
            }
        },
        messageReceived({data:messageList}) {
            // 收到推送的單聊、群聊、群提示、群系統通知的新消息,可通過遍歷 event.data 獲取消息列表數據並渲染到頁面
            // event.name - TIM.EVENT.MESSAGE_RECEIVED
            // event.data - 存儲 Message 對象的數組 - [Message]
            
            console.log("===消息列表更新===")
            // console.log(messageList)
            this.pushCurrentMessageList(messageList);//向消息列表添加消息
        },
        pushCurrentMessageList(data) {
            //向消息列表添加數據
            // 還沒當前會話,則跳過
            // console.log(this.currentConversation.conversationID, 'this.currentConversation.conversationID')
            if (!this.currentConversation.conversationID) {
                return
            }
            if (Array.isArray(data)) {
                // 篩選出當前會話的消息
                const result = data.filter(item => item.conversationID === this.currentConversation.conversationID)
                this.currentMessageList = [...this.currentMessageList, ...result]
            } else if (data.conversationID === this.currentConversation.conversationID) {
                this.currentMessageList = [...this.currentMessageList, data]
            }
            console.log(">>>>>>>>向消息列表添加成功>>>>>>>")
            // console.log(this.currentMessageList, '正常')
        },
        timError() {
            console.log("===SDK內部出錯===")
            if (data.message !== 'Network Error') {
                // tools.msgErr(data.message)
            } 
        },
        scrollMessageListToButtom() {
            this.$nextTick(() => {
                let messageListNode = this.$refs['message-list']
                if (!messageListNode) {
                    return
                }
                messageListNode.scrollTop = messageListNode.scrollHeight;
                this.preScrollHeight = messageListNode.scrollHeight;
            })
        },
        async checkSend() {
            return new Promise(resolve=>{
                this.$api.checkContentAuto({
                        content: this.messageContent,
                        user_name: this.userName,
                        user_head_url: this.getUserInfo.headUrl,
                        onlive_im_id: this.dataIm.id,
                        onlive_im_user_id: this.dataImUserSaveInfo.data.id
                    }).then(res => {
                    if (res.success == true) {
                        // 返回true直接發到IM
                        resolve()
                    } else {
                        this.msgStatus = true
                        this.msgText = '發送失敗'
                        reject()
                    }
                })
            })
        },
        async sendTextMessage(){//tim發送消息
            let that = this
            // if(!self.getLoginAfterData.id){
            //   tools.msgErr("游客身份需要注冊登錄后才可以發言~",3000);
            //   return;
            // }
            //自動發
            if (this.dataIm.audit_type == 1) {
                await this.checkSend()
                //
                if(!this.timSDKisReady){
                    //timSDKisReady未准備成功
                    console.log('通信環境未准備完備,請稍后再試或者刷新網頁')
                    // tools.msgErr("通信環境未准備完備,請稍后再試或者刷新網頁",3000);
                    return;
                } else {
                    console.log('通信環境准備完備,可以發送留言')
                }
                if(!(this.messageContent.trim())){
                    this.messageContent = "";//重置文本消息框
                    console.log('請輸入將要發送的消息')
                    // tools.msgErr("請輸入將要發送的消息");
                    return;
                }
                const message = this.tim.createTextMessage({
                    to: that.dataIm.im_group_id,//群組id
                    conversationType: that.TIM.TYPES.CONV_GROUP,
                    payload: { text: that.messageContent }
                })
                // message.avatar = this.getUserInfo.headUrl
                this.pushCurrentMessageList(message);//向消息列表添加消息
                this.$bus.$emit('scroll-messageList-bottom');//消息框滾動到底部

                //向TIM發送數據
                this.tim.sendMessage(message).then((imResponse)=>{
                    // 發送成功
                    console.log("=====消息發送成功=====")
                    // console.log(imResponse, '返回后的');
                    this.messageContent = "";//重置文本消息框
                }).catch((imError)=>{
                    // 發送失敗
                    console.log("=====消息發送失敗=====")
                    // tools.msgErr(imError.message);
                })
            } else {
                //非自動,向后台發送
                this.$api.checkContentByManual({
                    content: this.messageContent,
                    user_name: this.userName,
                    user_head_url: this.getUserInfo.headUrl,
                    onlive_im_id: this.dataIm.id,
                    onlive_im_user_id: this.dataImUserSaveInfo.data.id
                }).then(res => {
                    if (res.success == true) {
                        this.msgStatus = true
                        this.msgText = res.message
                        // console.log('發送后台成功')
                        //重置文本消息框
                        this.messageContent = ""
                    } else {
                        this.msgStatus = true
                        this.msgText = '發送失敗'
                    }
                    return
                })
                      
            }
        },
        async getMessageList(){
            let that = this
            //獲取消息列表信息
            return new Promise(resolve => {
                that.tim.getMessageList({ 
                    conversationID: this.conversationID, 
                    nextReqMessageID: this.nextReqMessageID,
                    count: 15
                }).then(imReponse => {
                    // 更新messageID,續拉時要用到
                    that.nextReqMessageID = imReponse.data.nextReqMessageID;
                    that.isCompleted = imReponse.data.isCompleted;
                    // 更新當前消息列表,從頭部插入
                    that.currentMessageList = [...imReponse.data.messageList,...that.currentMessageList];
                    // console.log("$$$$消息列表$$$$$");
                    // console.log(imReponse.data.messageList, 'empty')
                    resolve()
                })
            })
        },

        temporaryRepair() {
            var currentPosition, timer
            var speed = 1 //頁面滾動距離
            timer = setInterval(function() {
                currentPosition =
                document.documentElement.scrollTop || document.body.scrollTop
                currentPosition -= speed
                window.scrollTo(0, 0) //頁面向上滾動
                currentPosition += speed //speed變量
                window.scrollTo(0, currentPosition) //頁面向下滾動
                clearInterval(timer)
            }, 1)
        },
        randomString(len = 32) {
            let chars = 'ABCDE_FGHJKMNPQRS_TWXYZabcd_efhijkmnprstw_xyz2345678';
            let pwd = '';
          for (var i = 0; i < len; i++) {
            pwd += chars.charAt(Math.floor(Math.random() * chars.length));
          }
          return pwd;
        },
        changeMsgShow() {
            this.msgStatus = false
            this.msgText = ''
        }
    },
    beforeDestroy() {
        // 退出tim登陸
        this.tim.logout();
        // 取消綁定tim的各種事件
        this.tim.off(this.TIM.EVENT.SDK_READY, this.sdkReady);//sdkReady
        this.tim.off(this.TIM.EVENT.KICKED_OUT,this.kickedOut);//有可能同名用戶被踢出
        this.tim.off(this.TIM.EVENT.ERROR,this.timError);//TIM內部出錯
        this.tim.off(this.TIM.EVENT.CONVERSATION_LIST_UPDATED,this.conversationListUpdated);//會話列表更新
        this.tim.off(this.TIM.EVENT.MESSAGE_RECEIVED, this.messageReceived);//收到新消息
    },
}
</script>
<style lang="scss">
.discuss_box {
  display: flex;
  flex: 1;
  height: 100%;
  flex-direction: column;
}
.message_list{
  flex: 1;
  overflow-y: auto;
  padding-bottom:60px;
}
textarea{
    display: block;
    border: 0;
    height: .5rem;
    font-size: .25rem;
    width: calc(100% - .4rem);
    padding: .2rem;
    background-color: #f0f0f0;
}
.submit_button {
  border-radius: 6px;
  color: #ffffff;
  font-weight: bold;
  background-color: #2196F3;
  font-size: 18px;
  width: 100%;
  line-height: .5rem;
  line-height: .7rem;
  margin:0 auto;
  border-radius: 0 0 5px 5px;
  text-align: center;
}
.bottomWrap{
    
    box-shadow: 0 0px 5px rgba(0,0,0,.3);
}
.message_list img {
    margin-top: 0;
}
.no_more{
  display: flex;
  justify-content: center;
  color:#a7b5c1;
  font-size: .16rem;
  padding: 10px 10px;
}
.cursor{
    color: #333;
    cursor: pointer;
    background-color: #f5f5f5;
}
</style>

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM