<html lang="cn"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="description" content=""> <meta name="author" content="陶士涵"> <title>聊天界面</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-ui@2.13.1/lib/theme-chalk/index.css"> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="https://cdn.jsdelivr.net/npm/element-ui@2.13.1/lib/index.js"></script> <script src="https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js"></script> <script src="https://cdn.bootcss.com/reconnecting-websocket/1.0.0/reconnecting-websocket.min.js"></script> <style> html, body {height: 100%;padding: 0;margin: 0;background-color: #f5f5f5;} .el-row{width:100%}#app{margin-top: 10px;} .chatLeft{min-height: 100%;border-bottom: solid 1px #e6e6e6;overflow: hidden;border-top: solid 1px #e6e6e6;} .sw-bg{background: #fff;border: solid 1px #e6e6e6;boder-top:none;padding:5px 10px;} .chatContext .el-row{margin-bottom: 5px;} .chatUser{ line-height: 24px; font-size: 12px; white-space: nowrap; color: #999; } .chatContent{ text-align: left; background-color: rgb(166,212,242); color: #000; border: 1px solid rgb(152, 199, 230); padding: 8px 15px; min-height: 35px; word-break: break-all; position: relative; border-radius: 5px; } .chatContent:after { content: ''; position: absolute; left: -10px; top: 13px; width: 0; height: 0; border-style: dashed; border-color: transparent; overflow: hidden; border-width: 10px; border-top-style: solid; border-top-color: rgb(166,212,242); } .chatBoxMe .chatContent{background-color: rgb(152,225,101);border: 1px solid rgb(145, 215, 96);} .chatBoxMe .chatContent:after{border-top-color: rgb(152,225,101);} .chatBoxMe .el-col-3{float: right;text-align: right;} .chatBoxMe .chatUser{text-align: right} .chatBoxMe .chatContent:after{left:auto;right: -10px;} .chatArea{margin: 10px 0;} .chatBox{max-height: 350px;overflow-y: auto;overflow-x: hidden;} </style> </head> <body> <div id="app"> <template> <el-row :gutter="5"> <el-col :span="6"> <el-menu class="chatLeft" :default-active="currentGuest"> <el-menu-item> <i class="el-icon-s-promotion"></i> <span slot="title">在线用户</span> </el-menu-item> <el-menu-item :index="v.uid" v-for="v in users" v-bind:key="v.uid" v-on:click="talkTo(v.uid)"> <i class="el-icon-user"></i> <span slot="title"><{v.username}></span> </el-menu-item> </el-menu> </el-col> <el-col :span="12"> <div class="sw-bg chatContext"> <el-alert :title="chatTitle" type="success"> </el-alert> <div class="chatBox"> <el-row :gutter="2" v-for="v in msgList" v-bind:class="{'chatBoxMe': v.is_kefu==true}"> <el-col :span="3"><el-avatar :size="60" :src="v.avatar"></el-avatar></el-col> <el-col :span="21"> <div class="chatUser"><{v.name}></div> <div class="chatContent"><{v.content}></div> </el-col> </el-row> </div> <el-input type="textarea" class="chatArea" v-model="messageContent"></el-input> <el-button type="primary" v-on:click="chatToUser">发送</el-button> </div> </el-col> <el-col :span="6"> <el-menu class="chatLeft"> <el-menu-item> <i class="el-icon-s-tools"></i> <span slot="title">访客信息</span> </el-menu-item> </el-menu> </el-col> </el-row> </template> </div> </body> <script> var app=new Vue({ el: '#app', delimiters:["<{","}>"], data: { fullscreenLoading:true, users:[], usersMap:[], server:"ws://127.0.0.1:8080/chat_server", socket:null, messageContent:"", currentGuest:"", msgList:[], msgListUser:[], chatTitle:"暂时未处理咨询", kfConfig:{ id : "kf_1", name : "客服丽丽", avatar : "", to_id : "", } }, methods: { //跳转 openUrl(url) { window.location.href = url; }, getOnlineUsers() { let mes = {} mes.type = "getOnlineUsers"; mes.data = this.kfConfig; this.socket.send(JSON.stringify(mes)); }, sendKefuOnline(){ let mes = {} mes.type = "kfOnline"; mes.data = this.kfConfig; this.socket.send(JSON.stringify(mes)); }, //初始化websocket initConn() { let socket = new ReconnectingWebSocket(this.server);//创建Socket实例 this.socket = socket this.socket.onmessage = this.OnMessage; this.socket.onopen = this.OnOpen; }, OnOpen() { this.getOnlineUsers(); }, OnMessage(e) { const redata = JSON.parse(e.data); switch (redata.type){ case "getOnlineUsers": this.handleOnlineUsers(redata.data); this.sendKefuOnline(); break; case "notice": // if(!this.usersMap[redata.data.uid]){ // this.$notify({ // title: "通知", // message: "新客户访问", // type: 'success', // duration: 0, // }); // } this.getOnlineUsers(); this.sendKefuOnline(); break; } // if (redata.type == "notice") { // this.$notify({ // title: "通知", // message: "新客户访问", // type: 'success', // duration: 0, // }); //发送给客户我在线 // let mes = {} // mes.type = "kfConnect"; // kfConfig.guest_id=redata.data[0].uid; // mes.data = kfConfig; // this.socket.send(JSON.stringify(mes)); //} if (redata.type == "chatMessage") { let msg = redata.data let content = {} content.avatar = msg.from_avatar; content.name = msg.from_name; content.content = msg.content; content.is_kefu = false; content.time = msg.time; if (msg.from_id == this.currentGuest) { this.msgList.push(content); } if (typeof (this.msgListUser[msg.from_id]) == "undefined") { this.msgListUser[msg.from_id] = []; } this.msgListUser[msg.from_id].push(content); this.$nextTick(() => { $('.chatBox').scrollTop($(".chatBox")[0].scrollHeight); }); } }, //接手客户 talkTo(guestId) { this.currentGuest = guestId; this.chatTitle=this.usersMap[guestId]+guestId+",正在处理中..."; this.msgList = []; let buf = []; var i = this.msgListUser[guestId].length; while (i--) { buf[i] = this.msgListUser[guestId][i]; } this.msgList = buf; //发送给客户 let mes = {} mes.type = "kfConnect"; this.kfConfig.to_id=guestId; mes.data = this.kfConfig; this.socket.send(JSON.stringify(mes)); }, //发送给客户 chatToUser() { if(this.messageContent==""||this.currentGuest==""){ return; } let mes = {}; mes.type = "kfChatMessage"; this.kfConfig.content = this.messageContent; mes.data = this.kfConfig; this.socket.send(JSON.stringify(mes)); this.messageContent = ""; let content = {} content.avatar = this.kfConfig.avatar; content.name = this.kfConfig.name; content.content = this.kfConfig.content; content.is_kefu = true; content.time = ''; this.msgList.push(content); if (typeof (this.msgListUser[this.currentGuest]) == "undefined") { this.msgListUser[this.currentGuest] = []; } this.msgListUser[this.currentGuest].push(content); this.$nextTick(() => { $('.chatBox').scrollTop($(".chatBox")[0].scrollHeight); }); }, //处理当前在线用户列表 handleOnlineUsers:function (retData) { this.users = retData; if (this.currentGuest == "") { this.chatTitle = "连接成功,等待处理中..."; } for(let i=0;i<retData.length;i++){ this.usersMap[retData[i].uid]=retData[i].username; if (typeof (this.msgListUser[retData[i].uid]) == "undefined") { this.msgListUser[retData[i].uid] = []; } } }, //获取客服信息 getKefuInfo(){ let _this=this; $.ajax({ type:"get", url:"/kefuinfo", headers:{ "token":localStorage.getItem("token") }, success: function(data) { if(data.result!=null){ _this.kfConfig.id=data.result.id; _this.kfConfig.name=data.result.name; _this.kfConfig.avatar=data.result.avator; } if(data.code!=200){ _this.$message({ message: data.msg, type: 'error' }); } } }).then(function(data){ _this.initConn(); }); }, }, created: function () { this.getKefuInfo(); } }) </script> </html>