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.
450 lines
17 KiB
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
|
|
|