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