KEFU_ID=KEFU_ID!=""? KEFU_ID:"kefu2"; new Vue({ el: '#app', delimiters:["<{","}>"], data: { window:window, server:getWsBaseUrl()+"/ws_visitor", socket:null, msgList:[], msgListNum:[], messageContent:"", chatTitle:KEFU_LANG[LANG]['connecting'], visitor:{}, face:[], showKfonline:false, socketClosed:false, focusSendConn:false, wsSocketClosed:true, timer:null, loadingTimer:null, sendDisabled:false, entLogo:"", entName:"", peer:null, peerjsId:"", kefuPeerId:"", loading:null, localStream:null, flyLang:KEFU_LANG[LANG], lang:LANG, textareaFocused:false, replys:[], noticeName:"", noticeAvatar:"", allOffline:false, visitorContact:{ email:"", weixin:"", name:"", msg:"", }, haveUnreadMessage:false, audioDialog:false, recorder:null, recorderAudio:null, recordeTimer:null, recoderSecond:0, currentActiveTime:Date.now(), timeoutTimer:null, timeoutLongTime:20*60*1000,//20分钟没反应 allTimeouter:[], currentPage:1, showLoadMore:false, loadMoreDisable:false, websocketOpenNum:0,//websocket打开次数 websocketMaxOpenNum:10,//websocket最大打开次数 talkBtnText:"按住 说话", recorderEnd:false, isMobile:false, isIframe:false, onlineType:"success", }, methods: { //初始化websocket initConn:function() { this.socket = new ReconnectingWebSocket(this.server+"?visitor_id="+this.visitor.visitor_id+"&to_id="+this.visitor.to_id);//创建Socket实例 this.socket.debug = true; this.socket.onmessage = this.OnMessage; this.socket.onopen = this.OnOpen; this.socket.onerror = this.OnError; this.socket.onclose = this.OnClose; }, OnOpen:function() { console.log("ws:onopen"); //限制最大打开次数 if(this.websocketOpenNum>=this.websocketMaxOpenNum){ this.chatTitle=KEFU_LANG[LANG]['refresh']; this.socket.close(); return; } this.websocketOpenNum++; this.chatTitle=this.noticeName+" , "+KEFU_LANG[LANG]['connectok']; this.checkTimeout(); this.socketClosed=false; this.focusSendConn=false; this.wsSocketClosed=false; this.sendVisitorLogin(); this.getExtendInfo(); }, OnMessage:function(e) { console.log("ws:onmessage"); this.socketClosed=false; this.focusSendConn=false; const redata = JSON.parse(e.data); if (redata.type == "kfOnline") { let msg = redata.data if(this.showKfonline && this.visitor.to_id==msg.id){ return; } this.visitor.to_id=msg.id; this.chatTitle=msg.name+","+KEFU_LANG[LANG]['chating']; $(".chatBox").append("
"+this.chatTitle+"
"); this.scrollBottom(); this.showKfonline=true; } if (redata.type == "transfer") { var kefuId = redata.data if(!kefuId){ return; } this.visitor.to_id=kefuId; } if (redata.type == "notice") { let msg = redata.data if(!msg){ return; } this.chatTitle=msg $(".chatBox").append("
"+this.chatTitle+"
"); this.scrollBottom(); } if (redata.type == "peerid") { let msg = redata.data; if(!msg){ return; } this.kefuPeerId=msg; this.talkPeer(); } if (redata.type == "delete") { var msg = redata.data; for(var i=0;i"+this.chatTitle+""); this.scrollBottom(); this.socket.close(); //this.socketClosed=true; this.focusSendConn=true; } if (redata.type == "force_close") { //this.chatTitle=KEFU_LANG[LANG]['forceclosemes']; //$(".chatBox").append("
"+this.chatTitle+"
"); //this.scrollBottom(); this.socket.close(); this.socketClosed=true; } if (redata.type == "auto_close") { //this.chatTitle=KEFU_LANG[LANG]['autoclosemes']; //$(".chatBox").append("
"+this.chatTitle+"
"); //this.scrollBottom(); this.socket.close(); this.socketClosed=true; } if (redata.type == "change_id") { let msg = redata.data; var openId=msg.to; var visitor=this.getCache("visitor_"+ENT_ID); visitor.visitor_id=openId; this.setCache("visitor_"+ENT_ID,visitor); location.reload(); } window.parent.postMessage(redata,"*"); }, //发送给客户 chatToUser:function() { if(this.sendDisabled){ return; } var messageContent=this.messageContent.trim("\r\n"); messageContent=messageContent.replace("\n",""); messageContent=messageContent.replace("\r\n",""); if(messageContent==""||messageContent=="\r\n"){ this.messageContent=""; return; } this.messageContent=messageContent; this.currentActiveTime=Date.now(); if(this.socketClosed){ this.initConn(); // this.$message({ // message: '连接关闭!请重新打开页面', // type: 'warning' // }); //return; } this.sendDisabled=true; let _this=this; let content = {} content.avator=_this.visitor.avator; content.content = replaceContent(_this.messageContent); content.name = _this.visitor.name; content.is_kefu = true; content.read_status = KEFU_LANG[LANG]['unread']; content.time = _this.getNowDate(); content.show_time=false; _this.msgList.push(content); _this.scrollBottom(); let mes = {}; mes.type = "visitor"; mes.content = this.messageContent; mes.from_id = this.visitor.visitor_id; mes.to_id = this.visitor.to_id; mes.content = this.messageContent; //发送消息 $.post("/2/message",mes,function(res){ _this.sendDisabled=false; if(res.code!=200){ _this.msgList.pop(); _this.$message({ message: res.msg, type: 'error' }); if(res.code==401){ setTimeout(function(){ window.location.reload(); },2000); } return; } _this.messageContent = ""; _this.cleanAllTimeout(); _this.sendSound(); _this.sendDisabled=false; }); }, //正在输入 inputNextText:function(){ this.sendInputingStrNow(this.messageContent); }, sendInputingStrNow:function(str){ if(this.socketClosed||!this.socket||this.wsSocketClosed){ return; } var message = {} message.type = "inputing"; message.data = { from : this.visitor.visitor_id, to : this.visitor.to_id, content:str }; this.socket.send(JSON.stringify(message)); }, sendVisitorLogin:function(){ var _this=this; setTimeout(function(){ if(_this.socketClosed||!_this.socket||_this.wsSocketClosed){ return; } var message = {} message.type = "visitor_login"; message.data = { from : _this.visitor.visitor_id, to : _this.visitor.to_id, }; _this.socket.send(JSON.stringify(message)); }, 3000); }, OnClose:function() { console.log("ws:onclose"); this.focusSendConn=true; this.wsSocketClosed=true; this.closeTimeoutTimer(); }, OnError:function() { console.log("ws:onerror"); this.closeTimeoutTimer(); }, //获取当前用户信息 getUserInfo:function(){ let obj=this.getCache("visitor_"+ENT_ID); var visitor_id="" var to_id=KEFU_ID; if(obj){ visitor_id=obj.visitor_id; //to_id=obj.to_id; } let _this=this; var extra=getQuery("extra"); var url=getQuery("url"); var paramVisitorId=getQuery("visitor_id"); if(paramVisitorId!=""){ visitor_id=paramVisitorId; } var visitorName=getQuery("visitor_name"); if(extra==""){ var ext={}; var refer=document.referrer?document.referrer:"-"; ext.refer=refer; ext.host=document.location.href; extra=utf8ToB64(JSON.stringify(ext)); } //发送消息 $.post("/visitor_login",{visitor_id:visitor_id,visitor_name:visitorName,refer:REFER,to_id:to_id,extra:extra,ent_id:ENT_ID,url:url},function(res){ if(res.code!=200){ _this.$message({ message: res.msg, type: 'error' }); _this.chatTitle=res.msg; _this.sendDisabled=true; return; } if(result.alloffline){ _this.onlineType="danger"; }else{ _this.onlineType="success"; } if(KEFU_CONFIG.SHOW_OFFLINE_PAGE){ _this.allOffline=res.alloffline; } _this.sendDisabled=false; _this.visitor=res.result; _this.noticeName=res.kefu.username; _this.noticeAvatar=res.kefu.avatar; _this.setCache("visitor_"+ENT_ID,res.result); //_this.getMesssagesByVisitorIdUnread(); _this.loadMoreMessages(); //_this.getMesssagesByVisitorId(); _this.initConn(); //心跳 _this.ping(); }); // }else{ // this.visitor=obj; // this.initConn(); // } }, //获取信息列表 getMesssagesByVisitorId:function(isAll){ let _this=this; $.ajax({ type:"get", url:"/2/messages?visitor_id="+this.visitor.visitor_id, success: function(data) { if(data.code==200 && data.result!=null&&data.result.length!=0){ let msgList=data.result; _this.msgList=[]; for(var i=0;i= ms) { lastClick = Date.now(); //如果有未读消息,调用已读接口 _this.sendAjax("/2/messages_read","post",{"visitor_id":_this.visitor.visitor_id,"kefu":_this.visitor.to_id},function(data){ _this.haveUnreadMessage=false; }); } }); $('body').click(function(){ clearFlashTitle(); window.parent.postMessage({type:"focus"},"*"); $('.faceBox').hide(); //剪贴板 try{ var selecter = window.getSelection().toString(); if (selecter != null && selecter.trim() != ""){ var str=selecter.trim(); _this.sendInputingStrNow(str); } } catch (err){ var selecter = document.selection.createRange(); var s = selecter.text; if (s != null && s.trim() != ""){ var str=s.trim(); _this.sendInputingStrNow(str); } } }); window.onfocus = function () { //_this.scrollBottom(); clearFlashTitle(); window.parent.postMessage({type:"focus"},"*"); if(_this.socketClosed){ return; } if(!_this.focusSendConn){ return; } _this.initConn(); _this.scrollBottom(); } //判断当前是否在iframe中 if(self!=top){ _this.isIframe=true; } }, //表情点击事件 faceIconClick:function(index){ $('.faceBox').hide(); this.messageContent+="face"+this.face[index].name; }, //上传图片 uploadImg:function (url){ let _this=this; $('#uploadImg').after(''); $("#uploadImgFile").click(); $("#uploadImgFile").change(function (e) { var formData = new FormData(); var file = $("#uploadImgFile")[0].files[0]; formData.append("imgfile",file); //传给后台的file的key值是可以自己定义的 filter(file) && $.ajax({ url: url || '', type: "post", data: formData, contentType: false, processData: false, dataType: 'JSON', mimeType: "multipart/form-data", success: function (res) { if(res.code!=200){ _this.$message({ message: res.msg, type: 'error' }); }else{ _this.messageContent+='img[/' + res.result.path + ']'; _this.chatToUser(); } }, error: function (data) { console.log(data); } }); }); }, //上传文件 uploadFile:function (url){ let _this=this; $('#uploadFile').after(''); $("#uploadRealFile").click(); $("#uploadRealFile").change(function (e) { var formData = new FormData(); var file = $("#uploadRealFile")[0].files[0]; formData.append("realfile",file); //传给后台的file的key值是可以自己定义的 console.log(formData); $.ajax({ url: url || '', type: "post", data: formData, contentType: false, processData: false, dataType: 'JSON', mimeType: "multipart/form-data", success: function (res) { if(res.code!=200){ _this.$message({ message: res.msg, type: 'error' }); }else{ _this.messageContent+='file[/' + res.result.path + ']'; _this.chatToUser(); } }, error: function (data) { console.log(data); } }); }); }, //粘贴上传图片 onPasteUpload:function(event){ let items = event.clipboardData && event.clipboardData.items; let file = null if (items && items.length) { // 检索剪切板items for (var i = 0; i < items.length; i++) { if (items[i].type.indexOf('image') !== -1) { file = items[i].getAsFile() } } } if (!file) { return; } let _this=this; var formData = new FormData(); formData.append('imgfile', file); $.ajax({ url: '/uploadimg', type: "post", data: formData, contentType: false, processData: false, dataType: 'JSON', mimeType: "multipart/form-data", success: function (res) { if(res.code!=200){ _this.$message({ message: res.msg, type: 'error' }); }else{ _this.messageContent+='img[/' + res.result.path + ']'; _this.chatToUser(); } }, error: function (data) { console.log(data); } }); }, //自动 getAutoReply:function(){ var _this=this; $.get("/autoreply?ent_id="+ENT_ID,function(res) { if(res.code==200 && res.result){ _this.replys.push(res.result); } }); }, //提示音 alertSound:function(){ var b = document.getElementById("chatMessageAudio"); if (b.canPlayType('audio/ogg; codecs="vorbis"')) { b.type= 'audio/mpeg'; b.src= '/static/images/notification.mp3'; var p = b.play(); p && p.then(function () { }).catch(function (e) { }); } }, sendSound:function(){ var b = document.getElementById("chatMessageSendAudio"); if (b.canPlayType('audio/ogg; codecs="vorbis"')) { b.type= 'audio/mpeg'; b.src= '/static/images/sent.ogg'; var p = b.play(); p && p.then(function(){}).catch(function(e){}); } }, initPeerjs:function(){ var peer = new Peer(); this.peer=peer; var _this=this; peer.on('open', function(id) { console.log('My peer ID is: ' + id); _this.peerjsId=id; }); peer.on('close', function() { console.log('My peer close'); if(_this.loading!=null){ _this.loading.close(); } }); peer.on('disconnected', function() { console.log('My peer disconnected'); if(_this.loading!=null){ _this.loading.close(); } }); peer.on('error', function() { console.log('My peer error'); if(_this.loading!=null){ _this.loading.close(); } }); }, callPeer:function(){ var _this=this; this.loading = this.$loading({ lock: true, text: '正在请求通话', spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.7)' }); this.loadingTimer=setTimeout(function(){ _this.loading.close(); }, 20000); var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; getUserMedia({video: false, audio: true}, function(stream) { _this.localStream=stream; }, function(err) { console.log('Failed to get local stream' ,err); }); _this.sendAjax("/call_kefu","post",{kefu_id:_this.visitor.to_id,visitor_id:_this.visitor.visitor_id},function(result){ }); }, talkPeer:function(){ var remoteVideo = document.querySelector('video#chatRtc'); var _this=this; if(this.loading!=null){ this.loading.close(); } clearTimeout(this.loadingTimer); this.$message({ message: '正在通话...', type: 'success' }); if(_this.kefuPeerId==""||_this.localStream==null){ return; } var call = _this.peer.call(_this.kefuPeerId, _this.localStream); call.on('stream', function(remoteStream) { console.log(remoteStream); remoteVideo.srcObject = remoteStream; remoteVideo.autoplay = true; }); call.on('close', function() { console.log("call close"); _this.loading.close(); }); call.on('error', function(err) { console.log(err); _this.loading.close(); }); }, getExtendInfo:function(){ var _this=this; var extra=getQuery("extra"); if(extra==""){ return; } var extra=JSON.parse(b64ToUtf8(extra)); if (typeof extra=="string"){ extra=JSON.parse(extra); } for(var key in extra){ if(extra[key]==""){ extra[key]="无"; } if(key=="visitorProduct"){ _this.messageContent="product["+JSON.stringify(extra[key])+"]"; _this.chatToUser(); }; } }, sendAjax:function(url,method,params,callback){ let _this=this; $.ajax({ type: method, url: url, data:params, error:function(res){ var data=JSON.parse(res.responseText); console.log(data); if(data.code!=200){ _this.$message({ message: data.msg, type: 'error' }); } }, success: function(data) { if(data.code!=200){ _this.$message({ message: data.msg, type: 'error' }); }else if(data.result!=null){ callback(data.result); }else{ callback(data); } } }); }, showTitle:function(title){ $(".chatBox").append("
"+title+"
"); this.scrollBottom(); }, //开始录音 startRecoder:function(e){ if(this.recorder){ this.recorder.destroy(); this.recorder=null; } var _this=this; Recorder.getPermission().then(function() { _this.recorder = new Recorder(); _this.recorderAudio = document.querySelector('#audio'); _this.recorder.start(); _this.recorder.onprogress = function (params) { _this.recoderSecond = parseInt(params.duration); } this.talkBtnText = "松开 结束"; }, function(error){ _this.$message({ message: "请允许录音权限,以及浏览器限制非HTTPS下无法使用", type: 'error' }); return; }); e.preventDefault(); }, stopRecoder:function(e){ if(!this.recorder){ return; } var blob=this.recorder.getWAVBlob(); this.recorderAudio.src = URL.createObjectURL(blob); this.recorderAudio.controls = true; this.talkBtnText="按住 说话"; this.recorderEnd=true; e.preventDefault(); }, sendRecoder:function(){ if(!this.recorder){ return; } var blob=this.recorder.getWAVBlob(); var formdata = new FormData(); // form 表单 {key:value} formdata.append("realfile", blob); // form input type="file" var _this=this; this.loading = this.$loading({ lock: true, text: '正在发送', spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.7)' }); $.ajax({ url: "/uploadaudio", type: 'post', processData: false, contentType: false, data: formdata, dataType: 'JSON', mimeType: "multipart/form-data", success: function (res) { _this.loading.close(); if(res.code!=200){ _this.$message({ message: res.msg, type: 'error' }); }else{ _this.cancelRecoder(); _this.messageContent+='audio[/' + res.result.path + ']'; _this.chatToUser(); } } }) }, cancelRecoder:function(){ this.audioDialog=false; if(!this.recorder){ return; } this.recorder.destroy(); this.recorder=null; this.recoderSecond=0; }, recoderFormat:function(percentage){ return percentage+"s"; }, openNewWindow:function(){ var features = "height=580, width=400, top=10, left=500, toolbar=no, menubar=no,scrollbars=no,resizable=no, location=no, status=no"; //设置新窗口的特性 var me = window.open(location.href, "newW", features); }, //超时关闭 checkTimeout:function(){ var _this=this; this.timeoutTimer=setInterval(function(){ if (Date.now() - _this.currentActiveTime >= _this.timeoutLongTime) { console.log("长时间无操作"); if(_this.socket!=null){ _this.showTitle(KEFU_LANG[LANG]['autoclosemes']); _this.socket.close(); _this.socket=null; } var msg={type:'force_close'}; window.parent.postMessage(msg,"*"); } },55000); }, closeTimeoutTimer:function(){ clearInterval(this.timeoutTimer); }, cleanAllTimeout:function(){ for(var i in this.allTimeouter){ clearTimeout(this.allTimeouter[i]); } }, loadMoreMessages:function(){ var _this=this; var pagesize=5; if(this.currentPage>1){ this.replys=[]; } if(_this.loadMoreDisable){ return; } var moreMessage=KEFU_LANG[LANG]['moremessage']; this.flyLang.moremessage=this.flyLang.loading; this.loadMoreDisable=true; var hasUnread=false; this.sendAjax("/2/messages_page","get",{pagesize:pagesize,ent_id:ENT_ID,page:this.currentPage,visitor_id:_this.visitor.visitor_id},function(result){ var len=result.list.length; if(result.list.length!=0){ if(len'; child += '扫描左侧二维码可直接用微信登录。
可防止更换浏览器丢失消息、收不到回复。
并可接收回复通知'; $(".chatBox").append(child); }, //格式化时间 formatTime:function(time) { var timeStamp = Math.round(new Date(time).getTime()/1000); var nowTime=Math.round(new Date().getTime()/1000); if((nowTime-timeStamp)<=3600*24*30*3){ return beautifyTime(timeStamp,LANG); } return time; }, getVersion:function(){ }, }, mounted:function() { var _this=this; document.addEventListener('paste', this.onPasteUpload); document.addEventListener('scroll',this.textareaBlur); window.addEventListener('message',function(e){ var msg=e.data; if(msg.type=="inputing_message"){ _this.sendInputingStrNow(msg.content); } if(msg.type=="send_message"){ _this.messageContent=msg.content; _this.chatToUser(); } }); }, created: function () { this.init(); this.getUserInfo(); //加载历史记录 //this.msgList=this.getHistory(); //滚动底部 //this.scrollBottom(); //获取欢迎 //this.initPeerjs(); this.getAutoReply(); this.getVersion(); } })