You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
go-fly/static/html/chat_main.html

508 lines
21 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<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;}
.chatBg{min-height: 100%;background: #fff;border: solid 1px #e6e6e6;overflow: hidden;}
.chatLeft{ margin-left: 4px;}
.chatLeft .el-tabs__header{margin: 0;}
.chatLeft .el-tabs__nav{margin-left: 20px;}
.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: 26px;
word-break: break-all;
position: relative;
border-radius: 5px;
display: inline-block;
}
.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{float: right;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;}
.onlineUsers{padding: 5px;height: 40px;line-height: 40px;font-size: 14px;border-bottom: solid 1px #e6e6e6;}
.onlineUsers:hover,.onlineUsers.cur{background-color: #f0f9eb;color: #67C23A;}
.imgGray {-webkit-filter: grayscale(100%);-ms-filter: grayscale(100%);filter: grayscale(100%);filter: gray;color:#888;}
.chatTime{text-align: center;color: #bbb;margin: 5px 0;font-size: 12px;}
</style>
</head>
<body>
<div id="app">
<template>
<el-row :gutter="2">
<el-col :span="6">
<div class="chatBg chatLeft">
<el-tabs v-model="leftTabActive" @tab-click="handleTabClick">
<el-tab-pane label="在线用户" name="first">
<el-row v-for="item in users" :key="item.uid" class="">
<div style="cursor:pointer" class="onlineUsers" v-bind:class="{'cur': item.uid==currentGuest }" v-on:click="talkTo(item.uid,item.username)">
<el-col :span="4">
<el-avatar :size="40" :src="item.avator"></el-avatar>
</el-col>
<el-col :span="16">
<{item.username}>
</el-col>
</div>
</el-row>
</el-tab-pane>
<el-tab-pane label="所有访客" name="second">
<el-row v-for="item in visitors" :key="item.uid" class="">
<div style="cursor:pointer" class="onlineUsers" v-bind:class="{'cur': item.visitor_id==currentGuest }" v-on:click="talkTo(item.visitor_id,item.name)">
<el-col :span="4">
<el-avatar v-bind:class="{'imgGray': item.status==0 }" :size="40" :src="item.avator"></el-avatar>
</el-col>
<el-col :span="16" v-bind:class="{'imgGray': item.status==0 }">
<{item.name}>
</el-col>
</div>
</el-row>
<el-pagination
background
@current-change="visitorPage"
:current-page="visitorCurrentPage"
layout="prev,pager, next"
:page-size="visitorPageSize"
:total="visitorCount">
</el-pagination>
</el-tab-pane>
</el-tabs>
</div>
</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}">
<div class="chatTime"><{v.time}></div>
<el-col :span="3"><el-avatar :size="60" :src="v.avator"></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">
<div class="chatBg">
<el-menu>
<el-menu-item>
<i class="el-icon-user"></i>
<span slot="title">访客信息</span>
</el-menu-item>
<el-menu-item>
<i class="el-icon-s-tools"></i>
<span slot="title">来源:<{visitor.refer}></span>
</el-menu-item>
<el-menu-item>
<i class="el-icon-s-tools"></i>
<span slot="title">IP<{visitor.client_ip}></span>
</el-menu-item>
<el-menu-item>
<i class="el-icon-s-tools"></i>
<span slot="title">城市:<{visitor.city}></span>
</el-menu-item>
<el-menu-item>
<i class="el-icon-s-tools"></i>
<span slot="title">状态:<{visitor.status}></span>
</el-menu-item>
</el-menu>
</div>
</el-col>
</el-row>
</template>
</div>
</body>
<script>
var app=new Vue({
el: '#app',
delimiters:["<{","}>"],
data: {
fullscreenLoading:true,
leftTabActive:"first",
users:[],
usersMap:[],
server:"ws://"+window.location.host+"/chat_server",
socket:null,
messageContent:"",
currentGuest:"",
msgList:[],
chatTitle:"暂时未处理咨询",
kfConfig:{
id : "kf_1",
name : "客服丽丽",
avator : "",
to_id : "",
},
visitor:{
refer:"",
client_ip:"",
city:"",
status:"",
},
visitors:[],
visitorCount:0,
visitorCurrentPage:1,
visitorPageSize:10,
},
methods: {
//跳转
openUrl(url) {
window.location.href = url;
},
sendKefuOnline(){
let mes = {}
mes.type = "kfOnline";
mes.data = this.kfConfig;
this.socket.send(JSON.stringify(mes));
},
//心跳
ping(){
let _this=this;
let mes = {}
mes.type = "ping";
mes.data = "";
setInterval(function () {
if(_this.socket!=null){
_this.socket.send(JSON.stringify(mes));
}
},5000)
},
//初始化websocket
initConn() {
let socket = new ReconnectingWebSocket(this.server);//创建Socket实例
this.socket = socket
this.socket.onmessage = this.OnMessage;
this.socket.onopen = this.OnOpen;
},
OnOpen() {
this.sendKefuOnline();
},
OnMessage(e) {
const redata = JSON.parse(e.data);
switch (redata.type){
case "getOnlineUsers":
this.handleOnlineUsers(redata.data);
//this.sendKefuOnline();
break;
case "userOnline":
this.addOnlineUser(redata.data);
break;
case "userOffline":
this.removeOfflineUser(redata.data);
//this.sendKefuOnline();
break;
case "notice":
// if(!this.usersMap[redata.data.uid]){
// this.$notify({
// title: "通知",
// message: "新客户访问",
// type: 'success',
// duration: 0,
// });
// }
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 == "message") {
let msg = redata.data
let content = {}
content.avator = msg.avator;
content.name = msg.name;
content.content = msg.content;
content.is_kefu = false;
content.time = msg.time;
if (msg.id == this.currentGuest) {
this.msgList.push(content);
}
this.scrollBottom();
}
},
//接手客户
talkTo(guestId,name) {
this.currentGuest = guestId;
this.chatTitle=name+"|"+guestId+",正在处理中...";
//发送给客户
let mes = {}
mes.type = "kfConnect";
this.kfConfig.to_id=guestId;
mes.data = this.kfConfig;
this.socket.send(JSON.stringify(mes));
//获取当前访客信息
this.getVistorInfo(guestId);
//获取当前客户消息
this.getMesssagesByVisitorId(guestId);
},
//发送给客户
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.avator = this.kfConfig.avator;
content.name = this.kfConfig.name;
content.content = this.kfConfig.content;
content.is_kefu = true;
content.time = '';
this.msgList.push(content);
this.scrollBottom();
},
//处理当前在线用户列表
addOnlineUser:function (retData) {
let vid=retData.uid;
this.users.push(retData);
for(let i=0;i<this.visitors.length;i++){
if(this.visitors[i].visitor_id==vid){
this.visitors[i].status=1;
break;
}
}
},
//处理当前在线用户列表
removeOfflineUser:function (retData) {
for(let i=0;i<this.users.length;i++){
if(this.users[i].uid==retData.uid){
this.users.splice(i,1);
}
}
let vid=retData.uid;
for(let i=0;i<this.visitors.length;i++){
if(this.visitors[i].visitor_id==vid){
this.visitors[i].status=0;
break;
}
}
},
//处理当前在线用户列表
handleOnlineUsers:function (retData) {
this.users = retData;
if (this.currentGuest == "") {
this.chatTitle = "连接成功,等待处理中...";
}
// this.usersMap=[];
// for(let i=0;i<retData.length;i++){
// this.usersMap[retData[i].uid]=retData[i].username;
// }
// for(let i=0;i<this.visitors.length;i++){
// let vid=this.visitors[i].visitor_id;
// if(typeof this.usersMap[vid]=="undefined"){
// this.visitors[i].status=0;
// }else{
// this.visitors[i].status=1;
// }
// }
},
//获取客服信息
getKefuInfo(){
let _this=this;
$.ajax({
type:"get",
url:"/kefuinfo",
headers:{
"token":localStorage.getItem("token")
},
success: function(data) {
if(data.code==200 && data.result!=null){
_this.kfConfig.id=data.result.id;
_this.kfConfig.name=data.result.name;
_this.kfConfig.avator=data.result.avator;
_this.initConn();
}
if(data.code!=200){
_this.$message({
message: data.msg,
type: 'error'
});
}
}
});
},
//获取信息列表
getMesssagesByVisitorId(visitorId){
let _this=this;
$.ajax({
type:"get",
url:"/messages?visitorId="+visitorId,
headers:{
"token":localStorage.getItem("token")
},
success: function(data) {
if(data.code==200 && data.result!=null){
let msgList=data.result;
_this.msgList=[];
for(let i=0;i<msgList.length;i++){
let visitorMes=msgList[i];
let content = {}
if(visitorMes["mes_type"]=="kefu"){
content.is_kefu = true;
content.avator = visitorMes["kefu_avator"];
content.name = visitorMes["kefu_name"];
}else{
content.is_kefu = false;
content.avator = visitorMes["visitor_avator"];
content.name = visitorMes["visitor_name"];
}
content.content = visitorMes["content"];
content.time = visitorMes["time"];
_this.msgList.push(content);
_this.scrollBottom();
}
}
if(data.code!=200){
_this.$message({
message: data.msg,
type: 'error'
});
}
}
});
},
//获取客服信息
getVistorInfo(vid){
let _this=this;
$.ajax({
type:"get",
url:"/visitor",
data:{visitorId:vid},
headers:{
"token":localStorage.getItem("token")
},
success: function(data) {
if(data.result!=null){
let r=data.result;
_this.visitor.refer=r.refer;
_this.visitor.city=r.city;
_this.visitor.client_ip=r.client_ip;
_this.visitor.status=r.status==1?"在线":"离线";
}
if(data.code!=200){
_this.$message({
message: data.msg,
type: 'error'
});
}
}
});
},
//处理tab切换
handleTabClick(tab, event){
let _this=this;
if(tab.name=="second"){
this.getVisitorPage(1);
}
},
//所有访客分页展示
visitorPage(page){
this.getVisitorPage(page);
},
//获取访客分页
getVisitorPage(page){
let _this=this;
$.ajax({
type:"get",
url:"/visitors",
data:{page:page},
headers:{
"token":localStorage.getItem("token")
},
success: function(data) {
if(data.result.list!=null){
_this.visitors=data.result.list;
_this.visitorCount=data.result.count;
_this.visitorPageSize=data.result.pagesize;
}
if(data.code!=200){
_this.$message({
message: data.msg,
type: 'error'
});
}
}
});
},
//滚到底部
scrollBottom(){
this.$nextTick(() => {
$('.chatBox').scrollTop($(".chatBox")[0].scrollHeight);
});
}
},
created: function () {
this.getKefuInfo();
//心跳
this.ping();
}
})
</script>
</html>