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.
 
 
 
customAgent/src/utils/socket.js

450 lines
17 KiB

import config from './config'
import { Toast, Dialog } from 'vant'
import store from '@/store'
import utils from './utils'
/**
* 提示函数
* 禁止点击蒙层、显示3秒后关闭
*/
const toast = msg => {
Toast({
message: msg,
duration: 5000,
position: 'top',
});
}
const sendMessageFunction = (msgText) => {
return {
token: store.state.token,
fromFlag: 'other',
userId: store.state.userId,
sessionId: store.state.sessionId,
reqAndResType: '',
msgType: '', //
msgText: msgText,
intentId: '',
source: store.state.source,
timestamp: (new Date()).valueOf(),
msgSource: store.state.manualService, //1机器人 2人工
cmd: ''
}
}
//设置title
document.setTitle = function (title) {
title = title || '洋洋客服';
store.commit('set_otherTips', title);
document.title = title;
var iframe = document.createElement('iframe');
iframe.src = `${process.env.BASE_URL}favicon.ico`;
iframe.style.display = 'none';
iframe.onload = function () {
setTimeout(function () {
iframe.remove();
}, 9)
}
document.body.appendChild(iframe);
}
let wsConnection = {
WSS_URL: config.WSURL,
$ws: null,
lockReturn: false,
//6s发一次心跳
timeout: 60 * 100 * 1,
timeoutObj: null,
timeoutNum: null,
serverTimeoutObj: null,
globalCallback: null,
sendMessageData: null,
reconectNum: 0,
//最大限制 重连次数
reconectTimes: 20,
closeSession: false,//是否关闭当前会话
//初始化webSocket长连接
initWebSocket: function (callback) {
var that = this;
var userId = store.state.userId;
var checkParam = store.state.token;
var sessionId = store.state.sessionId;
try {
if ('WebSocket' in window) {
// this.$ws = new WebSocket(this.WSS_URL + userId + "," + sessionId);
this.$ws = new WebSocket(`${this.WSS_URL}${userId}&${encodeURIComponent(checkParam)}`);
} else if ('MozWebSocket' in window) {
// this.$ws = new MozWebSocket(this.WSS_URL + userId + "," + sessionId);
this.$ws = new MozWebSocket(`${this.WSS_URL}${userId}&${encodeURIComponent(checkParam)}`);
} else {
Dialog.alert({
message: '您的浏览器不支持websocket协议,建议您使用Android系统版本大于4.0,ios系统版本大于7.0。'
}).then(() => {
utils.closeWindow(); //关闭页面
});
}
// this.$ws.onopen = this.wsOpen;
this.$ws.addEventListener("open", event => {
this.wsOpen();
})
// this.$ws = new WebSocket(this.WSS_URL + userId + "," + sessionId);
this.$ws.onclose = this.wsClose;
this.$ws.onmessage = this.onMessage;
this.$ws.onerror = this.wsError;
callback && callback();
// store.commit('set_otherTips', "连接中...");
document.setTitle('连接中...')
} catch (e) {
wsConnection.reconnect()
console.log(e);
}
},
wsResendMessage() {
var sendFailList = store.state.sendFailList;//取出上次发送失败的消息
if (sendFailList.length > 0) {
for (let i = 0; i < sendFailList.length; i++) {
(function (i) {//这个匿名函数生成了闭包的效果,新建了一个作用域,这个作用域接收到每次循环的i值保存了下来,即使循环结束,闭包形成的作用域也不会被销毁
setTimeout(function () {
var dataResend = sendFailList[i];
console.log("发送失败的数据ID==", dataResend.timestamp);
wsConnection.sendMessage(dataResend, wsConnection.globalCallback);
store.commit('set_currentItemId', dataResend.timestamp);
store.commit('set_findActiveItem', false);//发送成功
}, 200);
})(i);
}
store.commit('del_sendFailList');//删除发送成功的
console.log(store.state.sendFailList);
}
},
//打开websocket
wsOpen: function (e) {
var that = this;
//开始websocket心跳
wsConnection.startWsHeartbeat();
// toast('会话建立成功');
// store.commit('set_otherTips', "洋洋客服");
document.setTitle('洋洋客服')
//执行重新发送
// if(wsConnection.isReconnet){
// wsConnection.wsResendMessage();
// wsConnection.isReconnet = false;
// }
console.log("ws success " + new Date().format("yyyy-MM-dd hh:mm:ss"));
},
onMessage: function (event) {
//每次接收到服务端消息后 重置websocket心跳
wsConnection.resetHeartbeat();
let res = event.data;
try {
if (event.data === 'pong') {
console.log("收到心跳了:", event.data);
return;
}
if (event.data.match(/^\d+$/)) {
wsConnection.globalCallback && wsConnection.globalCallback(event.data);
return;
}
res = JSON.parse(res);
console.log("收到消息啦:", res.data || res);
if (res.data.cmd === 'ServiceSessionClosedEvent' && store.state.hxOpenSucceseds.includes(res.data.sessionId)) {
if(store.state.integratedUser){
utils.useSdk(res.data)
}else{
setTimeout(() => {
utils.useSdk(res.data)
}, 100);
}
}
if (res.code != 0) {
// toast(data.msg);
if (res.code === 10001) {
// 删除已经失效或过期的token(不删除也可以,因为登录后覆盖)
sessionStorage.removeItem("token");
wsConnection.$ws.close();
if (store.state.notitle === '1') {
toast('当前会话已结束,请刷新页面或关闭页面重新进入');
return
}
Dialog.confirm({
title: '提示',
message: '当前会话已结束,请刷新页面或关闭页面重新进入',
confirmButtonText: '取消',
cancelButtonText: '确认',
confirmButtonColor: '#000000',
cancelButtonColor: '#000000'
}).then(() => {
// on cancel (现在是右边的取消按钮)
// utils.closeWindow();
// router.replace({
// path: '/404' // 到登录页重新获取token
// })
}).catch(() => {
// on confirm (现在是左边的确认按钮)
//确认重新刷新页面获取token
// window.location.reload();
utils.AppReloadHtml();
});
} else {
if (res.msg) {
toast(res.msg);
}
}
return;
}
//是否转接人工参数
// if (res.data.cmd && res.data.cmd == "ServiceSessionCreatedEvent") {
// store.dispatch('setTransferCustomer', 2);
// }
//客服接起不排队了
if (res.data.cmd && res.data.cmd == "ServiceSessionOpenedEvent") {
store.commit('set_queuedTimeout', true);
store.commit('set_msgStatus', '');//人工客服排队状态值 等待中:"1",其他:""
store.commit('set_msgReply', false);//人工客服排队是否调取自动回复话术
}
if (res.data.cmd && res.data.cmd == "ServiceSessionClosedEvent") {
wsConnection.closeSession = true;//是关闭会话
setTimeout(() => {
store.commit('set_queuedTimeout', true);
store.dispatch('setTransferCustomer', 1);//人工改为机器人
wsConnection.$ws.close();
}, 2500)
}
//服务端发送来的消息存到vuex
store.dispatch('sendingDrtificial', res.data).then((res) => {
}).catch(err => {
console.log(err)
});
//如果会话关闭不用推送消息回执
if (res.data && res.data.chatId) {
let chatParam = JSON.stringify(res.data);
// wsConnection.$ws.send(chatParam, '');
wsConnection.sendMessage(chatParam, '');
console.log("发送消息回执", chatParam)
}
} catch (error) {
console.log(error)
}
},
//发送数据,接收处理数据
sendMessage: function (data, callback) {
//存储事件
wsConnection.globalCallback = callback;
// console.log(data, callback)
switch (wsConnection.$ws.readyState) {
//CONNECTING:值为0,表示正在连接。
case wsConnection.$ws.CONNECTING:
setTimeout(function () {
wsConnection.sendMessage(data, callback);
}, 1000);
break;
//OPEN:值为1,表示连接成功,可以通信了。
case wsConnection.$ws.OPEN:
wsConnection.$ws.send(data);
break;
//CLOSING:值为2,表示连接正在关闭。
case wsConnection.$ws.CLOSING:
setTimeout(function () {
wsConnection.sendMessage(data, callback);
}, 1000);
break;
//CLOSED:值为3,表示连接已经关闭,或者打开连接失败。
case wsConnection.$ws.CLOSED:
// do something
break;
default:
// this never happens
break;
}
//重新监听onmessage,并把数据传给回调函数
// wsConnection.onmessage = ev =>{
// callback && callback(ev)
// }
},
//重启websocket
reconnect: function () {
let _this = this;
if (_this.lockReturn) {
return;
}
_this.isReconnet = true;
_this.lockReturn = true;
//没连接上会一直重连,设置延迟避免请求过多
if (_this.reconectNum < this.reconectTimes) {
_this.timeoutNum && clearTimeout(_this.timeoutNum);
_this.timeoutNum = setTimeout(function () {
_this.initWebSocket();
// toast('正在重连,请稍后...');
// store.commit('set_otherTips', "正在重连...");
document.setTitle('正在重连...')
console.info(`正在重连第${_this.reconectNum + 1}次`)
_this.reconectNum++
_this.lockReturn = false;
}, 4000);
} else {
// toast('重连次数超出设定值,不再重连,请检查配置项');
Dialog.alert({
message: '重连次数超出设定值,不再重连。请检查您的网络设置,点击“确定”刷新页面,重新建立会话。'
}).then(() => {
// window.location.reload();
utils.AppReloadHtml();
});
}
},
//心跳检测,每5s心跳一次
startWsHeartbeat: function () {
let _this = this;
this.timeoutObj && clearTimeout(this.timeoutObj);
this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
this.timeoutObj = setTimeout(() => {
//这里发送一个心跳,后端收到后,返回一个心跳消息,
//onmessage拿到返回的心跳就说明连接正常
if (wsConnection.$ws && wsConnection.$ws.readyState != wsConnection.$ws.CLOSED) {
//关闭当前会话后不发送ping
if (!wsConnection.closeSession) {
_this.$ws.send("ping");
console.log("ping!", new Date().format("yyyy-MM-dd hh:mm:ss"));
}
}
//如果超过一定时间还没重置,说明后端主动断开了
_this.serverTimeoutObj = setTimeout(() => {
//如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
_this.$ws.close();
}, _this.timeout)
}, this.timeout);
},
//重置websocket心跳
resetHeartbeat: function () {
let _this = this;
this.reconectNum = 0;
clearTimeout(_this.timeoutObj);
clearTimeout(_this.serverTimeoutObj);
_this.startWsHeartbeat();
},
wsError: function (err) {
console.log(err, 'ws error');
// store.commit('set_otherTips', "洋洋客服(未连接)");
document.setTitle('洋洋客服(未连接)')
wsConnection.reconnect()
},
wsClose: function (e) {
// console.log(e, 'ws close')
console.log("连接关闭! " + new Date().format("yyyy-MM-dd hh:mm:ss"));
console.log('websocket 断开: ' + e.code + ' 关闭的原因:' + e.reason + ' 是否正常关闭' + e.wasClean);
if (e.code !== 1000) {
// toast('当前会话已结束');
this.lockReturn = false
clearTimeout(this.timeoutNum)
wsConnection.reconnect();
// store.commit('set_otherTips', "洋洋客服(未连接)");
document.setTitle('洋洋客服(未连接)')
//当前转成机器人
// store.dispatch('setTransferCustomer', 1);
} else {
this.$ws = null;
clearInterval(this.timeoutObj)
clearTimeout(this.serverTimeoutObj)
// toast('会话已关闭');
// store.commit('set_otherTips', "洋洋客服");
document.setTitle('洋洋客服')
wsConnection.$ws.close();
}
},
};
//时间格式化
Date.prototype.format = function (fmt) {
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小时
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
"S": this.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
}
for (var k in o) {
if (new RegExp("(" + k + ")").test(fmt)) {
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
}
}
return fmt;
}
// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function (event) {
event = event || window.event;
try {
// toast('onbeforeunload关闭当前会话窗口啦');
var oldSessionId = localStorage.getItem('sessionId');
var liccsAds = localStorage.getItem('liccsAds'); // 记录用户弹窗提示
// sessionStorage.removeItem("manualService");
if (wsConnection.$ws) {
wsConnection.$ws.close();
}
//清除本地缓存
localStorage.clear();
localStorage.sessionId = oldSessionId || '';
localStorage.liccsAds = liccsAds || '';
//清除session
sessionStorage.clear();
} catch (error) {
console.log(error.message)
}
}
//安卓处理解决方案
window.onunload = function (event) {
event = event || window.event;
try {
// toast('onunload关闭当前会话窗口啦');
var oldSessionId = localStorage.getItem('sessionId');
var liccsAds = localStorage.getItem('liccsAds'); // 记录用户弹窗提示
// sessionStorage.removeItem("manualService");
if (wsConnection.$ws) {
wsConnection.$ws.close();
}
//清除本地缓存
localStorage.clear();
localStorage.sessionId = oldSessionId || '';
localStorage.liccsAds = liccsAds || '';
//清除session
sessionStorage.clear();
} catch (error) {
console.log(error.message)
}
}
//抛出websocket对象
export default wsConnection