zoukankan      html  css  js  c++  java
  • vue 使用腾讯IM即时通信

    最近在做商城类的项目,需要使用到客服系统, 用户选择的腾讯IM即时通信,文档很。。。。 对Web很不友好, 弄了半天,总算出来。

     

     先记录,防止后期忘记

    1、 先安装依赖
    cnpm i cos-js-sdk-v5
    cnpm i tim-js-sdk
    2、 导入数据
    import TIM from 'tim-js-sdk';
    import COS from "cos-js-sdk-v5";
    let options = {
      SDKAppID: XASDSADSA// 接入时需要将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});
    export default tim

    在main的js导入
    
    
    <template>
    <div>
    <el-dialog title :visible.sync="dialogVisible" width="70%" :before-close="handleClose">
    <el-row :span="24">
    <div class="box" v-loading="loading" v-if="dialogVisible">
    <div class="t_left">
    <!-- <div class="seek">
    <el-input placeholder="请输入用户名进行搜索" v-model="lookup" @change="cLookup" clearable></el-input>
    </div>-->

    <div class="t_left_bot" v-if="rListOff">
    <div
    v-for="(item,index) in rList"
    :key="index"
    @click="setZi(item.conversationID,item.userProfile.userID,item.userProfile.avatar,item.userProfile.nick)"
    :class="{ active:item.conversationID==isActive }"
    >
    <img :src="item.userProfile.avatar || defaultAvatar" style="background: #c1c1c1;" />
    <div>{{item.userProfile.nick || item.userProfile.userID}}</div>
    <div v-show="item.lastMessage">{{item.lastMessage.messageForShow}}</div>
    <div>{{item.lastMessage.lastTime | offTime}}</div>
    <div
    v-if="item.unreadCount != 0"
    >{{item.unreadCount > 99 ? '99+' : item.unreadCount}}</div>
    </div>
    </div>
    </div>
    <!-- v-if="rRightOff" -->
    <div class="t_right">
    <!--名字-->
    <div class="t_right_top">{{chatName}}</div>
    <!--内容-->
    <div class="t_right_con" id="t_right_con">
    <div v-if="hList.isCompleted" class="t_r_nmore">没有更多了</div>
    <div v-else class="t_r_more" @click="seeMore()">查看更多</div>
    <div v-if="hList">
    <div class="hList-left" v-for="(item,index) in hList.messageList" :key="index">
    <!--他人发送的消息-->
    <div class="hList-left-a" v-if="item.to != toUserId">
    <img class="hlAva" :src="avatar || defaultAvatar" />
    <div>
    <!-- 判断消息是否是文字或者表情 -->
    <div v-if="item.type == 'TIMTextElem'" v-html="item.payload.text"></div>
    <!-- 消息时间 -->
    <div>{{item.time | offTime}}</div>
    </div>
    </div>
    <!--我自己发送的消息-->
    <div class="hList-left-b" v-else>
    <div>
    <!-- 判断消息是否是文字或者表情 -->
    <div v-if="item.type == 'TIMTextElem'" v-html="item.payload.text"></div>
    <!-- 消息时间 -->
    <div>{{item.time | offTime}}</div>
    </div>
    <img class="hlAva" :src="myAvatar" />
    </div>
    </div>
    </div>
    </div>

    <!--输出框-->
    <div class="t_right_bot">
    <div>
    <textarea
    placeholder="请输入消息内容,最多可输入200个字"
    v-model="textarea"
    maxlength="200"
    @keydown="messageSendlisten"
    ></textarea>
    <!-- <div class="t_limit">当前还可发送{{200-(textarea.length)}}个字</div> -->
    <el-button class="r_i" @click="setButton" type="primary">发送</el-button>
    </div>
    </div>
    </div>
    </div>
    </el-row>
    <!-- <span slot="footer" class="dialog-footer">
    <el-button @click="dialogVisible = false">取 消</el-button>
    <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
    </span>-->
    </el-dialog>
    </div>
    </template>

    <script>
    import { getToken, getUserInfo } from "@/utils/auth";
    // import { emojiMap, emojiUrl } from "../../../assets/emj";
    import defaultAvatar from "../assets/images/qian.png";
    export default {
    name: "",
    data() {
    return {
    dialogVisible: false,
    defaultAvatar,
    // "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1651318081,2860235060&fm=26&gp=0.jpg", //默认头像,如果用户没有上传头像或者头像路径错误展示这个路径
    myAvatar:
    "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2519824424,1132423651&fm=26&gp=0.jpg", //我的头像
    chatName: "", //查看的某个人name
    toUserId: "", //查看的某个人id
    avatar: "", //查看的某个人avatar
    lookup: "", //用户查找的名字
    isActive: "1",
    loading: false, //加载中
    textarea: "", //输入信息
    rListOff: false,
    rRightOff: false,
    // emojiMap: emojiMap,
    // emojiUrl: emojiUrl,
    rList: [], //会话列表
    hList: [], //具体信息
    };
    },
    filters: {
    //接收时间
    offTime: function (value) {
    var v = value;
    var date = new Date(v * 1000);
    var Y = date.getFullYear() + "-";
    var M =
    (date.getMonth() + 1 < 10
    ? "0" + (date.getMonth() + 1)
    : date.getMonth() + 1) + "-";
    var D = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
    var h =
    (date.getHours() < 10 ? "0" + date.getHours() : date.getHours()) + ":";
    var m =
    date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
    let dt = new Date(Date.parse(new Date()));
    let current = dt.getFullYear() + "-" + dt.getMonth() + "-" + dt.getDate();
    let system =
    date.getFullYear() + "-" + date.getMonth() + "-" + date.getDate();
    if (current == system) {
    return h + m;
    } else {
    return Y + M + D;
    }
    },
    },
    methods: {
    search(userIdMsg, shopName, shopLogo) {
    if (getUserInfo() == undefined){
    this.$message.error({
    message:"请先登录",
    duration:2000
    });
    this.$router.push({
    path:"/login",
    });
    return;
    }
    this.userIdMsg = userIdMsg;
    this.shopName = shopName;
    this.shopLogo = shopLogo;
    this.dialogVisible = true;
    let userID = getUserInfo().tengXunImId;
    let userSig = getUserInfo().userSig;
    this.logData(userID, userSig);
    this.setZi(conversationID, userIdMsg);
    },
    //消息查看更多
    seeMore() {
    const self = this;
    let nextReqMessageID = self.hList.nextReqMessageID;
    let promise = tim.getMessageList({
    conversationID: self.hList.messageList[0].conversationID,
    nextReqMessageID,
    count: 15,
    });
    promise.then(function (imResponse) {
    self.hList.messageList = [
    ...imResponse.data.messageList,
    ...self.hList.messageList,
    ];
    self.hList.nextReqMessageID = imResponse.data.nextReqMessageID; // 分页
    self.hList.isCompleted = imResponse.data.isCompleted; // 是否已经拉完
    if (self.hList) self.rRightOff = true;
    });
    },
    //查找用户 模糊查找
    cLookup() {
    const self = this;
    let promise = this.tim.getConversationList();
    promise
    .then(function (imResponse) {
    self.rList = imResponse.data.conversationList;
    self.rListOff = true;
    let arr = [];
    if (self.lookup.split(" ").join("").length == 0) {
    //业务逻辑
    //........
    } else {
    self.rList.map((item) => {
    if (
    item.userProfile.nick.indexOf(self.lookup) != -1 ||
    item.userProfile.userID.indexOf(self.lookup) != -1
    ) {
    arr.push(item);
    }
    });
    }
    arr.length == 0 ? self.hlData() : (self.rList = arr);
    })
    .catch(function (imError) {
    console.log(imError);
    // console.warn('getConversationList error:', imError); // 获取会话列表失败的相关信息
    });
    },
    //自动保持在最底部
    below() {
    this.$nextTick(() => {
    let container = this.$el.querySelector("#t_right_con");
    container.scrollTop = container.scrollHeight;
    });
    },
    //回车发送文本 阻止浏览器默认换行操作
    messageSendlisten(event) {
    if (event.keyCode === 13) {
    this.setButton(); // 发送文本
    event.preventDefault(); // 阻止浏览器默认换行操作
    return false;
    }
    },
    //消息已读
    read(id) {
    let promise = this.tim.setMessageRead({ conversationID: id });
    promise
    .then(function (imResponse) {
    // 已读上报成功,指定 ID 的会话的 unreadCount 属性值被置为0
    })
    .catch(function (imError) {
    // 已读上报失败
    console.warn("setMessageRead error:", imError);
    });
    },
    //发送消息
    setButton() {
    const self = this;
    if (self.textarea.split(" ").join("").length == 0)
    return this.$message({
    message: "请输入正确信息",
    type: "warning",
    });
    let message = this.tim.createTextMessage({
    to: self.hList.userID ? self.hList.userID : "约定的名字_" + self.userIdMsg,
    // to: "youqianchengjin_" + self.userIdMsg,
    conversationType: this.TIM.TYPES.CONV_C2C,
    payload: {
    text: self.textarea,
    },
    });
    // 发送消息
    let promise = tim.sendMessage(message);
    promise
    .then(function (imResponse) {
    // 发送成功
    self.textarea = "";
    self.hList.messageList.push(imResponse.data.message);
    self.below();
    })
    .catch(function (imError) {
    // 发送失败
    console.warn("sendMessage error:", imError);
    });
    },
    //获取会话资料
    setZi(conversationID, userID, avatar, chatName) {
    console.log(conversationID,'conversationID====')
    console.log(userID,'userID====')
    const self = this;
    if (userID == self.toUserId) {
    return;
    } else {
    self.hList = [];
    }
    self.toUserId = userID;
    self.avatar = avatar;
    self.isActive = conversationID;
    self.chatName = chatName || userID;
    let promise = this.tim.getMessageList({
    conversationID: conversationID,
    count: 15,
    });
    promise.then(function (imResponse) {
    let hList = {};
    hList.messageList = imResponse.data.messageList; // 消息列表。
    hList.nextReqMessageID = imResponse.data.nextReqMessageID; // 用于续拉,分页续拉时需传入该字段。
    hList.isCompleted = imResponse.data.isCompleted; // 表示是否已经拉完所有消息。
    hList.userID = userID; // 点击进去的用户id。
    hList.conversationID = conversationID;
    self.hList = hList;
    if (self.hList) self.rRightOff = true;
    self.below();
    //设置消息已读
    self.read(conversationID);
    });
    },
    //获取会话列表
    hlData() {
    const self = this;
    let promise = this.tim.getConversationList();
    promise
    .then(function (imResponse) {
    self.rList = imResponse.data.conversationList;
    self.rListOff = true;
    })
    .catch(function (imError) {
    console.log(imError);
    });
    },
    logData(userID, userSig) {
    const self = this;
    console.log("logData =============", userID, userSig);

    // 监听事件
    this.tim.on(this.TIM.EVENT.SDK_READY, function (event) {
    // 收到离线消息和会话列表同步完毕通知,接入侧可以调用 sendMessage 等需要鉴权的接口
    console.log("SDK_READY ===================");
    self.hlData();
    });

    this.tim.on(this.TIM.EVENT.ERROR, function (event) {
    // 收到离线消息和会话列表同步完毕通知,接入侧可以调用 sendMessage 等需要鉴权的接口
    console.error("ERROR ===================", event);
    });

    this.tim.on(this.TIM.EVENT.KICKED_OUT, function (event) {
    // 收到离线消息和会话列表同步完毕通知,接入侧可以调用 sendMessage 等需要鉴权的接口
    console.error("KICKED_OUT ===================", event);
    });

    this.tim.on(this.TIM.EVENT.NET_STATE_CHANGE, function (event) {
    // 收到离线消息和会话列表同步完毕通知,接入侧可以调用 sendMessage 等需要鉴权的接口
    console.error("NET_STATE_CHANGE ===================", event);
    });

    console.log(
    "this.TIM.EVENT.MESSAGE_RECEIVED",
    this.TIM.EVENT.MESSAGE_RECEIVED
    );
    this.tim.on(this.TIM.EVENT.MESSAGE_RECEIVED, function (event) {
    // 收到推送的单聊、群聊、群提示、群系统通知的新消息,可通过遍历 event.data 获取消息列表数据并渲染到页面
    console.log("MESSAGE_RECEIVED ===================");
    self.hlData();
    if (self.hList) {
    if (event.data[0].from == self.hList.userID) {
    // console.log('这是正在聊天的聊天界面')
    // console.log(event.data[0].conversationID)
    self.read(event.data[0].conversationID);
    self.hList.messageList.push(event.data[0]);
    self.below();
    }
    }
    });

    let promise = this.tim.login({ userID: userID, userSig: userSig });
    promise
    .then(function (imResponse) {
    console.log("login success ======================");
    //获取会话列表
    if (imResponse.data.repeatLogin === true) {
    // 标识账号已登录,本次登录操作为重复登录。v2.5.1 起支持
    console.log(imResponse.data.errorInfo);
    }
    })
    .catch(function (imError) {
    console.warn("login error:", imError); // 登录失败的相关信息
    });
    },
    handleClose() {
    let promise = this.tim.logout();
    this.dialogVisible = false;
    promise
    .then(function (imResponse) {
    console.log(imResponse.data);
    })
    .catch(function (imError) {
    console.warn("logout error:", imError);
    });
    },
    },
    destroyed() {
    // 离开页面退出当前账号
    let promise = this.tim.logout();
    // promise
    // .then(function (imResponse) {
    // console.log(imResponse.data);
    // })
    // .catch(function (imError) {
    // console.warn("logout error:", imError);
    // });
    },
    };
    </script>

    <style scoped lang="scss">
    @mixin toCla {
    color: #a5b5c1;
    font-size: 12px;
    }
    @mixin toClb {
    display: inline-block;
    > div:nth-child(1):before {
    content: "";
    0px;
    height: 0px;
    border-top: 7px solid transparent;
    border-bottom: 7px solid transparent;

    position: absolute;
    top: 10px;
    font-size: 7px;
    }
    > div:nth-child(2) {
    color: #a5b5c1;
    font-size: 12px;
    margin-top: 9px;
    }
    > div:nth-child(1) {
    outline: none;
    font-size: 14px;
    position: relative;
    max- 350px;
    word-wrap: break-word;
    word-break: break-all;
    background: #fff;
    border-radius: 5px;
    display: inline-block;
    padding: 10px;
    -webkit-box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.1);
    box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.1);
    margin-top: 20px;
    }
    }
    .box {
    100%;
    height: 100%;
    margin: 0 auto;
    margin-top: 2%;
    display: flex;
    // -moz-box-shadow: 2px 2px 5px #333333;
    // -webkit-box-shadow: 2px 2px 5px #333333;
    //box-shadow: 1px 1px 1px #333333;
    border: 1px solid #3d3d3d;
    position: relative;
    .t_left {
    260px;
    height: 600px;
    overflow: auto;
    border-right: 1px solid #e5e5e5;
    .seek {
    overflow: hidden;
    background: red;
    position: absolute;
    256px;
    z-index: 9;
    top: 0;
    left: 0;
    /deep/.el-input__inner {
    height: 35px;
    border: 0 !important;
    border-radius: 0 !important;
    border-bottom: 1px solid #b2b2b2 !important;
    }
    }
    .t_left_bot {
    // padding-top: 36px;
    overflow: auto;
    background: #3d3d3d;
    > div {
    100%;
    height: 80px;
    background: #3333;
    border-bottom: 1px solid #e5e5e5;
    cursor: pointer;
    position: relative;
    div:nth-child(5) {
    position: absolute;
    18px;
    height: 18px;
    line-height: 18px;
    text-align: center;
    font-size: 11px;
    top: 4px;
    left: 58px;
    color: #fff;
    background: red;
    border-radius: 50%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    }
    div:nth-child(4) {
    position: absolute;
    80px;
    font-size: 14px;
    top: 15px;
    left: 169px;
    color: #999;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    text-align: right;
    }
    div:nth-child(3) {
    position: absolute;
    163px;
    font-size: 14px;
    top: 45px;
    left: 83px;
    color: #999;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    }
    div:nth-child(2) {
    position: absolute;
    90px;
    font-size: 16px;
    top: 13px;
    left: 83px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: #ffffff;
    }
    img {
    60px;
    height: 60px;
    position: absolute;
    top: 10px;
    left: 10px;
    border-radius: 2px;
    }
    }
    }
    }
    .t_right {
    flex: 1;
    background: #ffffff;

    .t_right_bot {
    border-top: 1px solid #e5e5e5;
    height: 139px;
    100%;
    background: #fff;
    position: relative;
    /deep/.t_limit {
    position: absolute;
    right: 93px;
    bottom: 17px;
    color: #b2b2b2;
    }
    /deep/textarea {
    resize: none;
    height: 100px;
    border: 0;
    96%;
    display: block;
    margin: 0 auto;
    outline: none;
    }
    .r_i {
    position: absolute;
    right: 12px;
    bottom: 7px;
    color: #fff;
    }
    > div:nth-child(1) {
    display: flex;
    align-items: center;
    .icture_a {
    display: inline-block;
    cursor: pointer;
    position: relative;
    margin-left: 5px;

    /deep/.el-popover {
    400px !important;
    height: 160px !important;
    overflow: auto !important;
    }
    }
    .icture {
    30px;
    height: 30px;
    display: inline-block;
    margin: 4px 15px;
    cursor: pointer;
    overflow: hidden;
    position: relative;
    }
    input[type="file"] {
    color: transparent;
    }
    input {
    cursor: pointer !important;
    position: absolute;
    top: 0;
    left: 0;
    30px;
    height: 30px;
    opacity: 0;
    }
    /deep/i {
    font-size: 27px;
    }
    }
    }
    .t_right_con {
    height: 410px;
    overflow: auto;
    .t_r_nmore {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-pack: center;
    -ms-flex-pack: center;
    justify-content: center;
    font-size: 13px;
    color: #a5b5c1;
    background: 0 0;
    padding-left: 0;
    padding-right: 0;
    cursor: pointer;
    }
    .t_r_more {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-pack: center;
    -ms-flex-pack: center;
    justify-content: center;
    font-size: 13px;
    color: #409eff;
    background: 0 0;
    padding-left: 0;
    padding-right: 0;
    cursor: pointer;
    }
    }

    .t_right_top {
    padding: 0 20px;
    color: #1c2438;
    font-size: 18px;
    font-weight: bold;
    line-height: 50px;
    text-shadow: #76828c 0 0 0.1em;
    }
    .hList-left {
    100%;
    position: relative;
    overflow: auto;
    .hlAva {
    56px;
    height: 56px;
    border-radius: 50%;
    display: block;
    display: inline-block;
    margin: 10px 20px;
    vertical-align: top;
    }
    .hList-left-b {
    text-align: right;
    > div:nth-child(2) {
    @include toCla;
    }
    > div:nth-child(1) {
    @include toClb;
    > div:nth-child(1):before {
    border-top: 7px solid transparent !important;
    border-bottom: 7px solid transparent !important;
    border-left: 7px solid #fff !important;
    right: -7px !important;
    }
    }
    }
    .hList-left-a {
    > div:nth-child(3) {
    @include toCla;
    }
    > div:nth-child(2) {
    @include toClb;
    > div:nth-child(1):before {
    left: -7px !important;
    border-right: 7px solid #fff !important;
    }
    }
    }
    }
    }
    .active {
    transition: 300ms;
    background: #d6d6d6 !important;
    }
    }

    /* 设置滚动条的样式 */
    ::-webkit-scrollbar {
    3px;
    height: 3px;
    }

    /* 滚动槽 */
    ::-webkit-scrollbar-track {
    border-radius: 10px;
    }

    /* 滚动条滑块 */
    ::-webkit-scrollbar-thumb {
    border-radius: 10px;
    background: rgba(0, 0, 0, 0.1);
    }
    </style>


  • 相关阅读:
    将指定json格式的内容,写入文件中,构造测试数据
    shell对比用=时 记得加空格
    scp带私钥使用以及免密配置
    kafka知识补充
    根据frm和ibd文件恢复数据库表结构和数据
    登录页面 逻辑:当用户进来的时候, 全局检查一下是否有用户的信息,如果用则显示用户信息页面;没有,则显示用户登录页面
    理解Spring 容器、BeanFactory 以及 ApplicationContext
    Java 中 CAS
    volatile 关键字
    JenKins docker 集群
  • 原文地址:https://www.cnblogs.com/0520euv/p/13178525.html
Copyright © 2011-2022 走看看