import { getStorage, setStorage } from '@/utils/localStorage'; window.sessionTime = new Date(); var socketTaskList = []; //websocket 待发送任务列表 var socketInter = null; /** * websocket配置项 * @type {{serverTimeoutObj: null, timeoutObj: null, timeoutnum: null, lockReconnect: boolean, ws: null, params: {houseId: null, openid: null, userid: null}, timeout: number}} */ let wsConfig = { ws: null, lockReconnect: false, //是否真正建立连接 interval: null, timeoutObj: null, //心跳心跳倒计时 serverTimeoutObj: null, // 服务连接超时时间 timeoutnum: null, // 断开重连倒计时 timeout: 58 * 1000, // 58秒一次心跳 // 建立ws连接时,所需参数 params: { openid: null, userid: null, houseId: null } } /** * 初始化websocket */ function initWebsocket() { let str1 = parseInt(Math.random() * 10); let str2 = parseInt(Math.random() * 10); let str3 = parseInt(Math.random() * 10); let str4 = "" + str1 + str2 + str3; //初始化weosocket let websocketUrl = $config.ws_url; const wsuri = `${websocketUrl}gs-guide-websocket/` + str4 + "/shi23jfrw" + "/websocket"; wsConfig.ws = new WebSocket(wsuri); // 连接建立时触发 wsConfig.ws.onopen = websocketonopen; // 客户端接收服务端数据时触发 wsConfig.ws.onmessage = websocketonmessage; // 通信发生错误时触发 wsConfig.ws.onerror = websocketonerror; // 连接关闭时触发 wsConfig.ws.onclose = websocketclose; return wsConfig.ws; } /** * 连接建立时触发 */ function websocketonopen() { let data = initPage(); console.log('建立ws连接', data) start(); //发送链接身份数据 connectSend(data.openId, data.userId, data.houseId); } /** * 客户端接收服务端数据时触发 * @param e */ function websocketonmessage(e) { console.log('客户端接收服务端数据时触发', e); //收到服务器信息,心跳重置 // reset(); } /** * 通信发生错误时触发 */ function websocketonerror() { console.log("出现错误"); reconnect(); } /** * 连接关闭时触发 * @param e */ function websocketclose(e) { //关闭 console.log("断开连接", e); socketInter && clearInterval(socketInter);//清空心跳发送 socketInter = null; //重连 reconnect(); } function websocketsend(Data) { console.log('ws状态', wsConfig.ws) if(wsConfig.ws && wsConfig.ws.readyState==1){ let param = [ "SEND" + "\nproject:" + "elab-marketing-system" + "\nmethod:" + "POST" + "\npath:" + "/behavior/brandMiniWeb/upload" + "\ndestination:" + "/ws/remote/invoke" + "\n\n" + JSON.stringify(Data) + "\u0000", ]; //数据发送 wsConfig.ws.send(JSON.stringify(param)); }else{ // 如果还没有创建好socket链接或者链接还没打开,则放到待发送列表中 if(Data){ socketTaskList.push(Data); } console.log("***ws-socketTaskList列表count***", socketTaskList.length) return } } /** * 解析页面路由参数 * @param name * @returns {null} */ function getQueryString(name) { let reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i'); let arr = window.location.href.split('?'); let result = null; arr.forEach((item, index) => { let res = item.match(reg); if (res != null) { result = unescape(res[2]); } }) return result } /** * 初始进入页面参数 */ function initPage(){ let userInfo = getStorage('userInfo') ? JSON.parse(getStorage('userInfo')) : null; let queryObj = getStorage('queryObj') ? JSON.parse(getStorage('queryObj')) : null; let urlObj = queryObj || util.getUrlParams(location.href) || {}; let brandId = urlObj.brandId || urlObj.special_ID || $config.brandId || ''; let userId = urlObj.leavePhoneCustomerId ? urlObj.leavePhoneCustomerId : (userInfo?userInfo.userId:''); return { session: urlObj.session || '', // 项目id,默认仙女山项目 houseId: urlObj.xcxHouseId || '', userId: userId || '', openId: urlObj.openid || (userInfo ? userInfo.openId : ''), brandId: brandId || '', product: urlObj.xcxHouseId || '', fromPlatform: urlObj.fromProduce || '', platform: urlObj.platform || '', scene: urlObj.scene1 || '', layoutName: urlObj.layoutName || '', } } /** * 发送ws连接请求 */ function connectSend(openid, userid, houseId) { console.log('建立ws通信', openid, userid, houseId) //发送堆积的待发送消息 const param = [ "CONNECT" + "\nopenId:" + openid + "\nplatform:" + "1" + "\nhouseId:" + houseId + "\nuserId:" + userid + "\naccept-version:1.1,1.0\nheart-beat:5000,5000\n\n\u0000", ]; websocketsend(JSON.stringify(param)); if (socketTaskList && socketTaskList.length > 0) { for (var i = 0; i < socketTaskList.length; i++) { if(socketTaskList[i]){ // wsConfig.ws.send(socketTaskList[i]); if(!socketTaskList[i].userId){ socketTaskList[i].userId = userid; socketTaskList[i].brandUserId = userid; } if(!socketTaskList[i].openId){ socketTaskList[i].openId = openid; } // console.log("***ws-socketTaskList列表***", socketTaskList[i]) let param = [ "SEND" + "\nproject:" + "elab-marketing-system" + "\nmethod:" + "POST" + "\npath:" + "/behavior/brandMiniWeb/upload" + "\ndestination:" + "/ws/remote/invoke" + "\n\n" + JSON.stringify(socketTaskList[i]) + "\u0000", ]; // 发送堆积的待发送消息 wsConfig.ws.send(JSON.stringify(param)); socketTaskList[i] = null; } } for (var i = 0; i < socketTaskList.length; i++) { if(!socketTaskList[i]){ socketTaskList.splice(i,1); } } } } /** * 重新连接ws */ function reconnect() { console.log('重新连接ws'); //重新连接 if (wsConfig.lockReconnect) { return; } wsConfig.lockReconnect = true; //没连接上会一直重连,设置延迟避免请求过多 wsConfig.timeoutnum && clearTimeout(wsConfig.timeoutnum); wsConfig.timeoutnum = setTimeout(() => { //新连接 initWebsocket() wsConfig.lockReconnect = false }, 5000) socketInter && clearInterval(socketInter);//清空心跳发送 socketInter = null; } /** * 重置ws连接 */ function reset() { console.log('重启心跳') //重置心跳 // clearTimeout(wsConfig.timeoutObj); // //清除时间 // clearTimeout(wsConfig.serverTimeoutObj); //重启心跳 wsSendHeartBeat(); } // socket 心跳发送 function wsSendHeartBeat() { let ws = wsConfig.ws; // var data = ["\n"];//心跳的数据格式 if(!socketInter){ console.warn('***ws-开启WebSocket心跳***'); //5秒钟发送一次心跳 socketInter = setInterval(()=>{ // console.warn("***ws-SendHeartBeat-尝试心跳发送:"); //这里发送一个心跳,后端收到后,返回一个心跳消息, console.warn('***ws-心跳***'); if (ws.readyState == 1) { //如果连接正常 ws.send("heartCheck"); //这里可以自己跟后端约定 } else { //否则重连 reconnect(); } },5000) } } /** * 开启ws连接 */ function start() { let ws = wsConfig.ws; //开启心跳 // console.log("开启心跳", wsConfig,ws.readyState); wsConfig.timeoutObj && clearTimeout(wsConfig.timeoutObj); wsConfig.serverTimeoutObj && clearTimeout(wsConfig.serverTimeoutObj); wsConfig.timeoutObj = setTimeout(function() { wsConfig.serverTimeoutObj = setTimeout(function() { //超时关闭 ws.close(); }, wsConfig.timeout); }, wsConfig.timeout); wsSendHeartBeat();//开始心跳 } var util = { dateFormat(date, fmt) { let ret const opt = { 'y+': date.getFullYear().toString(), // 年 'M+': (date.getMonth() + 1).toString(), // 月 'd+': date.getDate().toString(), // 日 'H+': date.getHours().toString(), // 时 'm+': date.getMinutes().toString(), // 分 's+': date.getSeconds().toString(), // 秒 // 有其他格式化字符需求可以继续添加,必须转化成字符串 } for (let k in opt) { ret = new RegExp('(' + k + ')').exec(fmt) if (ret) { fmt = fmt.replace( ret[1], ret[1].length == 1 ? opt[k] : opt[k].padStart(ret[1].length, '0') ) } } return fmt }, formatDate: function(date, fmt) { if (/(y+)/.test(fmt)) { fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)) } let o = { 'M+': date.getMonth() + 1, 'd+': date.getDate(), 'h+': date.getHours(), 'm+': date.getMinutes(), 's+': date.getSeconds() } for (let k in o) { if (new RegExp(`(${k})`).test(fmt)) { let str = o[k] + '' fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? str : this.padLeftZero(str)) } } return fmt }, padLeftZero: function(str) { return ('00' + str).substr(str.length) }, formatDatetime(val, format) { const year = val.getFullYear(); const month = val.getMonth() + 1; const day = val.getDate(); const hour = val.getHours(); const minute = val.getMinutes(); const second = val.getSeconds(); return year + '-' + (month > 9 ? month : '0' + month) + '-' + day + ' ' + hour + ':' + (minute > 9 ? minute : '0' + minute) + ':' + (second > 9 ? second : '0' + second); }, formatDayTime(val) { const year = val.getFullYear(); const month = val.getMonth() + 1; const day = val.getDate(); const hour = val.getHours(); const minute = val.getMinutes(); const second = val.getSeconds(); return year + '-' + (month > 9 ? month : '0' + month) + '-' + day + ' ' + hour + ':' + (minute > 9 ? minute : '0' + minute); }, formatTodayTime(val) { const year = val.getFullYear(); const month = val.getMonth() + 1; const day = val.getDate(); const hour = val.getHours(); const minute = val.getMinutes(); if (month == new Date().getMonth() + 1 && day + 1 == new Date().getDate()) { return '昨天' + hour + ':' + (minute > 9 ? minute : '0' + minute); } else if (month == new Date().getMonth() + 1 && day == new Date().getDate()) { return hour + ':' + (minute > 9 ? minute : '0' + minute); } else { return year + '-' + (month > 9 ? month : '0' + month) + '-' + day + ' ' + hour + ':' + (minute > 9 ? minute : '0' + minute); } }, /** * 计算天数 * @param date1 * @param date2 * @returns {number} * @constructor */ getNumberOfDays(date1, date2) { //获得天数 if (!date1 || !date2) { return 0; } //date1:开始日期,date2结束日期 var a1 = Date.parse(new Date(date1)); var a2 = Date.parse(new Date(date2)); var day = parseInt((a2 - a1) / (1000 * 60 * 60 * 24)) + 1; //核心:时间戳相减,然后除以天数 return day }, getUrlParams(url) { url = url == null ? window.location.href : url; var search = url.substring(url.lastIndexOf("?") + 1); var obj = {}; var reg = /([^?&=]+)=([^?&=]*)/g; // [^?&=]+表示:除了?、&、=之外的一到多个字符 // [^?&=]*表示:除了?、&、=之外的0到多个字符(任意多个) search.replace(reg, function(rs, $1, $2) { var name = decodeURIComponent($1); var val = decodeURIComponent($2); val = String(val); obj[name] = val; return rs; }); return obj; }, formatTime(date) { var year = date.getFullYear() var month = date.getMonth() + 1 var day = date.getDate() var hour = date.getHours() var minute = date.getMinutes() var second = date.getSeconds() return [year, month, day].map(this.formatNumber).join('-') + ' ' + [hour, minute, second].map(this .formatNumber).join( ':') }, formatNumber(n) { n = n.toString() return n[1] ? n : '0' + n }, trackRequest(para, app = null) { if ((para.type && para.type.includes('Error'))) { //所有报错埋点以及曝光埋点不再发送至服务器 return } try { if(typeof (para.clkParams) == 'object'){ let obj = { locusBehaviorName: para.locusBehaviorName ? para.locusBehaviorName : '' } para.clkParams = Object.assign(obj,para.clkParams) } let pvCurPageParams = "";//字符串string对象 if(para.pvCurPageParams){//调用的时候传递进来的-先转为对象 pvCurPageParams = typeof para.pvCurPageParams === 'object' ? para.pvCurPageParams : JSON.parse(para.pvCurPageParams) }else{ pvCurPageParams = {}; } let queryObj = getStorage('queryObj') ? JSON.parse(getStorage('queryObj')) : null; let urlObj = queryObj || util.getUrlParams(location.href) || {}; let userInfo = getStorage('userInfo') ? JSON.parse(getStorage('userInfo')) : null; let userId = urlObj.leavePhoneCustomerId ? urlObj.leavePhoneCustomerId : (userInfo?userInfo.userId:''); let brandId = urlObj.special_ID || $config.brandId || '' //在页面参数里面手动添加path参数 pvCurPageParams.brandId = brandId; pvCurPageParams.locusBehaviorName = para.locusBehaviorName || ''; pvCurPageParams.locusValue = para.locusValue || ''; pvCurPageParams.locusName = para.locusName || ''; let data = { session: '', userAgent: navigator.userAgent.substring(0, 255) || '', browserName: navigator.appName || '', browserVersion: navigator.appVersion.substring(0, 255) || '', platform: 'h5', //iframeUrl代表是顾问分享的外链 fromPlatform: urlObj.fromPlatform || urlObj.fromProduce || 'h5', ip: window.ip || '', cookieId: from_cookie || getStorage("cookie_id") || '', openId: urlObj.openid || (userInfo ? userInfo.openId : ''), userId: userId, brandUserId: userId, createTime: this.formatTime(new Date()), uploadTime: this.formatTime(new Date()), product: 'h5', //iframeUrl代表是顾问分享的外链 project: para.project || urlObj.xcxHouseId || $config.xcxHouseId || '', brandId: brandId, expand: JSON.stringify(urlObj), //扩展字段 imTalkId: para.imTalkId || '', //IM对话编号 imTalkType: para.imTalkType || '', //IM对话类型 eventName: para.eventName || '', //事件名称 clkDesPage: para.clkDesPage || '', //点击前往的页面名称 clkId: para.clkId || '', //点击ID clkName: para.clkName || '', pvId: para.pvId || '', //PV埋点ID clkParams: typeof para.clkParams === 'object' ? JSON.stringify(para.clkParams) : (para.clkParams || ''), //点击参数 pvCurPageName: para.pvCurPageName || '', //当前页面名称 pvCurPageParams: typeof pvCurPageParams === 'object' ? JSON.stringify(pvCurPageParams) : (pvCurPageParams ||''), //当前页面参数 pvLastPageName: para.pvLastPageName || '', //上一页页面名称 pvLastPageParams: para.pvLastPageParams || '', //上一页页面参数 pvPageLoadTime: para.pvPageLoadTime || '', //加载时间 type: para.type || '', //埋点类型 reserve1: urlObj.channel || '', //来源平台,抖音百度微信 } let timeNow = new Date().getTime(); let session = getStorage('sessionNumber') ? Number(getStorage('sessionNumber')) : timeNow; if (timeNow - sessionTime > 180000 && !urlObj.session) { // session++; session = timeNow; setStorage('sessionNumber', session) } data.session = urlObj.session || data.userId + "_" + session || ''; sessionTime = timeNow; // return data; // app.globalData.session_id = data.session // app.globalData.sessionTime = timeNow; // requestConfig('upload', data, true); // let param = ["SEND" + // "\nproject:" + "elab-marketing-system" + // "\nmethod:" + 'POST' + // "\npath:" + '/behavior/brandMiniWeb/upload' + // "\ndestination:" + '/ws/remote/invoke' + // "\n\n" + JSON.stringify(data) + // "\u0000" // ]; // app.wsSendOrder(param,data);//socket 消息发送 console.warn("***mook***", (data.pvId || data.clkId || data.eventId), data) // let param = [ // "SEND" + // "\nproject:" + // "elab-marketing-system" + // "\nmethod:" + // "POST" + // "\npath:" + // "/behavior/brandMiniWeb/upload" + // "\ndestination:" + // "/ws/remote/invoke" + // "\n\n" + // JSON.stringify(data) + // "\u0000", // ]; // console.log("上报埋点数据", param); // websocketsend(JSON.stringify(param)); websocketsend(data); } catch (e) { console.warn("***util.js-onError***", e); } }, getSession() { //获取session let timeNow = new Date().getTime(); let session = uni.getStorageSync('sessionNumber') || timeNow; //session具体的值 uni.setStorage({ key: "sessionNumber", data: session }) return session; }, initWebsocket:initWebsocket, }; window.from_session = util.getUrlParams(location.href).session || ''; window.from_cookie = util.getUrlParams(location.href).cookie || ''; export default util; // module.exports = util;