@fle-sdk/event-tracking-web 1.2.2 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.min.js CHANGED
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).WebTracking=t()}(this,(function(){"use strict";var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])})(t,n)};var t=function(){return(t=Object.assign||function(e){for(var t,n=1,r=arguments.length;n<r;n++)for(var i in t=arguments[n])Object.prototype.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e}).apply(this,arguments)};function n(e,t){for(var n=0,r=t.length,i=e.length;n<r;n++,i++)e[i]=t[n];return e}function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}return new(function(r){function i(){var e=r.call(this)||this;return e.batchQueue=[],e.batchTimer=null,e.BATCH_QUEUE_STORAGE_KEY="web_tracking_batch_queue",e.useCustomPageKey=!1,e.pendingRequests=[],e.isUnloadListenerSetup=!1,e.PENDING_REQUESTS_STORAGE_KEY="web_tracking_pending_requests",e.DEFAULT_PENDING_REQUESTS_MAX_SIZE=50,e.MAX_STORAGE_SIZE=4194304,e.userInfo=null,e.currentUrl="",e.pageKey="",e.deviceId="",e.eventDescMap={PageView:"Web 浏览页面",WebClick:"Web 元素点击",PageRetained:"Web 页面浏览时长",CustomTrack:"Web 自定义代码上报"},e.init=function(t){e.preset(t);var n=window.location.pathname;e.currentUrl=window.location.href,t.pageKey?(e.pageKey=t.pageKey,e.useCustomPageKey=!0):(e.pageKey=n.replace(/\//g,"_").substring(1),e.useCustomPageKey=!1),e.systemsInfo=e.getSystemsInfo(t.platform),e.deviceId=e.getDeviceId(),t.userInfo&&e.isObject(t.userInfo)&&(e.userInfo=t.userInfo),e.setCookie("retainedStartTime",e.getTimeStamp()),e.initConfig.batchSend&&e.restoreBatchQueueFromStorage(),e.restorePendingRequestsFromStorage(),e.setupBeforeUnloadListener()},e.preset=function(t){if(t instanceof Object){if(void 0!==t.pageKey)if(null===t.pageKey||""===t.pageKey){e.useCustomPageKey=!1;var n=window.location.pathname;e.pageKey=n.replace(/\//g,"_").substring(1)}else e.pageKey=t.pageKey,e.useCustomPageKey=!0;e.each(t,(function(t,n){"pageKey"!==n&&e.initConfig.hasOwnProperty(n)&&(e.initConfig[n]=t)}))}/^(((ht|f)tps?):\/\/)?[\w-]+(\.[\w-]+)+([\w.,@?^=%&:/~+#-\(\)]*[\w@?^=%&/~+#-\(\)])?$/.test(e.initConfig.serverUrl)||(e.printLog("当前 server_url 为空或不正确,只在控制台打印日志,network 中不会发数据,请配置正确的 server_url!"),e.initConfig.showLog=!0),e.initConfig.autoTrack||e.initConfig.trackPartKeyClick?e.listener():e.unlistener()},e.login=function(t){e.isObject(t)&&(e.userInfo=t)},e.getDeviceId=function(){if(e.deviceId)return e.deviceId;var t=e.getCookie("device_id")||e.getLocalStorage("device_id");if(t)return e.deviceId=t,e.deviceId;var n=e.collectFingerprint(),r=e.hashFingerprint(n);return e.setCookie("device_id",r,730),e.setLocalStorage("device_id",r),e.deviceId=r,e.deviceId},e.resetDeviceId=function(){return document.cookie="device_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;",localStorage.removeItem("device_id"),e.deviceId="",e.getDeviceId()},e.track=function(t){var n=t.desc,r=t.pageKey,i=t.partkey,o=t.business,a=t.header,s=e.getParams({desc:n,event:"CustomTrack",itemKey:e.getItemKey(i,r),privateParamMap:{business:o}});return e.sendData(s,a)},e.listener=function(){e.initConfig.autoTrack&&(e.initConfig.isTrackSinglePage&&(e.rewriteHistory(),e.addSinglePageEvent(e.onPageViewCallback)),e.each(["load","beforeunload"],(function(t){e.addEventListener(window,t,e.onPageViewCallback)}))),(e.initConfig.autoTrack||e.initConfig.trackPartKeyClick)&&e.addEventListener(window,"click",e.onClickCallback)},e.unlistener=function(){if(e.initConfig.isTrackSinglePage){var t=window.history.pushState?"popstate":"hashchange";e.each(["pushState","replaceState",t],(function(t){e.removeEventListener(window,t,e.onPageViewCallback)}))}e.each(["load","beforeunload"],(function(t){e.removeEventListener(window,t,e.onPageViewCallback)})),e.removeEventListener(window,"click",e.onClickCallback),e.clearBatchTimer()},e.clearBatchTimer=function(){null!==e.batchTimer&&(clearTimeout(e.batchTimer),e.batchTimer=null)},e.clearBatchQueue=function(){e.batchQueue=[],e.setLocalStorage(e.BATCH_QUEUE_STORAGE_KEY,"[]"),e.initConfig.showLog&&e.printLog("批量队列已清空")},e.setPageKey=function(t,n){if(void 0===n&&(n=!1),null===t||""===t){e.useCustomPageKey=!1;var r=window.location.pathname;e.pageKey=r.replace(/\//g,"_").substring(1),e.initConfig.showLog&&e.printLog("页面标识已恢复自动生成: "+e.pageKey)}else e.pageKey=t,e.useCustomPageKey=!n,e.initConfig.showLog&&e.printLog("页面标识已设置为: "+t+", 自动更新: "+n)},e.getPageKey=function(){return e.pageKey},e.onClickCallback=function(t){var n,r=t.target;if(null===(n=null==r?void 0:r.dataset)||void 0===n?void 0:n.partKey){var i=[t.pageX,t.pageY],o=r.id,a=r.className,s={id:o,nodeName:r.nodeName,className:a,position:i},c=e.getParams({event:"WebClick",desc:e.eventDescMap.WebClick,itemKey:e.getItemKey(r.dataset.partKey),privateParamMap:{targetEle:s,pointerType:t.pointerType,currentUrl:e.currentUrl,elementSelector:e.getDomSelector(r)||""}});return e.sendData(c)}},e.onPageViewCallback=function(t){var n,r;(e.pendingRequests.length>0||e.initConfig.batchSend&&e.batchQueue.length>0)&&e.flushPendingData();var i=window.location.origin,o=e.getParams({event:"PageView",desc:e.eventDescMap.PageView,privateParamMap:{currentUrl:e.currentUrl,targetUrl:(null===(n=t.arguments)||void 0===n?void 0:n[2])?i+(null===(r=t.arguments)||void 0===r?void 0:r[2]):null}});e.currentUrl=window.location.href,e.useCustomPageKey||(e.pageKey=window.location.pathname.replace(/\//g,"_").substring(1)),e.sendRetained(t.type),e.sendData(o)},e.getParams=function(t){var n=t.event,r=t.desc,i=t.privateParamMap,o=void 0===i?{}:i,a=t.itemKey,s=e.initConfig.business,c=window.innerWidth,u=window.innerHeight,g=window.screen.width,l=window.screen.height,d=e.filterSensitiveData(s||{}),p=e.filterSensitiveData(e.userInfo||{}),h=e.filterSensitiveData(o||{}),f=e.filterSensitiveData(e.getQueryValue()||{}),v={currentUrl:h.currentUrl||e.currentUrl,business:Object.assign({},d,h.business||{}),pageWidth:c,pageHeight:u,screenWidth:g,screenHeight:l,sdkVersion:e.sdkVersion,systemsInfo:e.systemsInfo,urlParams:f,userInfo:p,deviceId:e.deviceId};return h.targetEle&&(v.targetEle=h.targetEle),h.targetUrl&&(v.targetUrl=h.targetUrl),h.pointerType&&(v.pointerType=h.pointerType),h.elementSelector&&(v.elementSelector=h.elementSelector),h.retainedDuration&&(v.retainedDuration=h.retainedDuration),{event:n,desc:r,itemKey:a||e.getItemKey(),requestTime:e.getTimeStamp(),privateParamMap:v}},e.shouldSample=function(){var t=e.initConfig.sampleRate;return t>=1||!(t<=0)&&Math.random()<t},e.flushBatchQueue=function(){if(0!==e.batchQueue.length){var t=n([],e.batchQueue);e.batchQueue=[],e.saveBatchQueueToStorage(),e.sendBatchData(t)}},e.sendBatchData=function(t){var n=e.initConfig,r=n.serverUrl,i=n.contentType;n.showLog&&(e.printLog("批量发送 "+t.length+" 条数据"),t.forEach((function(t){return e.printLog(t)}))),e.ajax({url:r,type:"POST",data:JSON.stringify({events:t}),contentType:i,credentials:!1,timeout:e.initConfig.sendTimeout,cors:!0,success:function(){e.initConfig.showLog&&e.printLog("批量发送成功: "+t.length+" 条数据")},error:function(n){var r;e.printLog("批量发送失败: "+n+",数据已重新加入队列"),(r=e.batchQueue).unshift.apply(r,t),e.batchQueue.length>2*e.initConfig.batchMaxSize&&(e.batchQueue=e.batchQueue.slice(0,e.initConfig.batchMaxSize)),e.saveBatchQueueToStorage()}})},e.addToBatchQueue=function(t){var n=e.initConfig,r=n.batchInterval,i=n.batchMaxSize;e.batchQueue.push(t),e.saveBatchQueueToStorage(),e.batchQueue.length>=i?e.flushBatchQueue():e.batchTimer||(e.batchTimer=window.setTimeout((function(){e.flushBatchQueue(),e.batchTimer=null}),r))},e.restoreBatchQueueFromStorage=function(){try{var t=e.getLocalStorage(e.BATCH_QUEUE_STORAGE_KEY);if(t){var n=JSON.parse(t);if(Array.isArray(n)&&n.length>0){e.batchQueue=n,e.initConfig.showLog&&e.printLog("从 LocalStorage 恢复 "+n.length+" 条待发送数据");var r=e.initConfig.batchMaxSize;if(e.batchQueue.length>=r)e.flushBatchQueue();else{var i=e.initConfig.batchInterval;e.batchTimer||(e.batchTimer=window.setTimeout((function(){e.flushBatchQueue(),e.batchTimer=null}),i))}}}}catch(t){e.printLog("恢复批量队列失败: "+t),e.setLocalStorage(e.BATCH_QUEUE_STORAGE_KEY,"[]")}},e.addToPendingRequests=function(t){e.pendingRequests.push(t);var n=e.initConfig.pendingRequestsMaxSize||e.DEFAULT_PENDING_REQUESTS_MAX_SIZE;e.pendingRequests.length>n&&(e.pendingRequests=e.pendingRequests.slice(-n),e.initConfig.showLog&&e.printLog("待发送请求队列已满,已移除最旧的数据(最大限制: "+n+")"))},e.restorePendingRequestsFromStorage=function(){try{var t=e.getLocalStorage(e.PENDING_REQUESTS_STORAGE_KEY);if(t){var n=JSON.parse(t);Array.isArray(n)&&n.length>0&&(e.pendingRequests=n,e.initConfig.showLog&&e.printLog("从 LocalStorage 恢复 "+n.length+" 条待发送请求"),e.pendingRequests.length>0&&e.flushPendingRequests())}}catch(t){e.printLog("恢复待发送请求失败: "+t),e.setLocalStorage(e.PENDING_REQUESTS_STORAGE_KEY,"[]")}},e.isPageUnloading=function(){return"hidden"===document.visibilityState},e.sendWithBeacon=function(t,n,r){try{var i=new Blob([JSON.stringify(t)],{type:r||"application/json"});return navigator.sendBeacon(n,i)}catch(t){return e.initConfig.showLog&&e.printLog("sendBeacon 发送失败: "+t),!1}},e.flushPendingRequests=function(){if(0!==e.pendingRequests.length){var t=n([],e.pendingRequests);e.pendingRequests=[],e.setLocalStorage(e.PENDING_REQUESTS_STORAGE_KEY,"[]"),t.forEach((function(t){e.sendData(t).catch((function(t){e.initConfig.showLog&&e.printLog("待发送请求发送失败(不再重试): "+t)}))}))}},e.saveBatchQueueToStorage=function(){try{if(JSON.stringify(e.batchQueue).length>e.MAX_STORAGE_SIZE){var t=Math.floor(.8*e.batchQueue.length);e.batchQueue=e.batchQueue.slice(-t),e.printLog("队列过大,已截断保留最新 "+t+" 条数据(限制: "+e.MAX_STORAGE_SIZE/1024/1024+"MB)")}e.setLocalStorage(e.BATCH_QUEUE_STORAGE_KEY,JSON.stringify(e.batchQueue))}catch(t){e.printLog("保存批量队列到 LocalStorage 失败: "+t)}},e.setupBeforeUnloadListener=function(){e.isUnloadListenerSetup||(e.isUnloadListenerSetup=!0,document.addEventListener("visibilitychange",(function(){e.isPageUnloading()&&e.flushPendingData()})),window.addEventListener("beforeunload",(function(){e.flushPendingData()})),window.addEventListener("pagehide",(function(){e.flushPendingData()})))},e.flushPendingData=function(){var t=[];if(e.batchQueue.length>0&&t.push.apply(t,e.batchQueue),e.pendingRequests.length>0&&t.push.apply(t,e.pendingRequests),0!==t.length)if(navigator.sendBeacon&&e.initConfig.serverUrl)try{var n=1===t.length?t[0]:{events:t},r=new Blob([JSON.stringify(n)],{type:e.initConfig.contentType||"application/json"});if(navigator.sendBeacon(e.initConfig.serverUrl,r))e.batchQueue=[],e.pendingRequests=[],e.setLocalStorage(e.BATCH_QUEUE_STORAGE_KEY,"[]"),e.initConfig.showLog&&e.printLog("页面卸载时成功发送 "+t.length+" 条数据");else if(e.initConfig.batchSend&&e.batchQueue.length>0&&e.saveBatchQueueToStorage(),e.pendingRequests.length>0)try{e.setLocalStorage(e.PENDING_REQUESTS_STORAGE_KEY,JSON.stringify(e.pendingRequests))}catch(t){e.initConfig.showLog&&e.printLog("保存待发送请求到 LocalStorage 失败: "+t)}}catch(t){if(e.initConfig.batchSend&&e.batchQueue.length>0&&e.saveBatchQueueToStorage(),e.pendingRequests.length>0)try{e.setLocalStorage(e.PENDING_REQUESTS_STORAGE_KEY,JSON.stringify(e.pendingRequests))}catch(e){}e.initConfig.showLog&&e.printLog("页面卸载时发送数据失败: "+t)}else if(e.initConfig.batchSend&&e.batchQueue.length>0&&e.saveBatchQueueToStorage(),e.pendingRequests.length>0)try{e.setLocalStorage(e.PENDING_REQUESTS_STORAGE_KEY,JSON.stringify(e.pendingRequests))}catch(e){}},e.sendData=function(t,n){if(!e.shouldSample())return Promise.resolve({success:!0,message:"数据已采样跳过"});var r=e.initConfig,i=r.serverUrl,o=r.sendTimeout,a=r.contentType,s=r.showLog,c=r.header,u=r.batchSend;return s&&e.printLog(t),u?(e.addToBatchQueue(t),Promise.resolve({success:!0,message:"已添加到批量队列"})):!0!==e.isSupportBeaconSend()||n||c?new Promise((function(r,s){if(e.isPageUnloading()&&e.isSupportBeaconSend()&&!n&&!c&&e.sendWithBeacon(t,i,a))return void r({success:!0,message:"页面卸载时使用 sendBeacon 发送成功"});e.ajax({header:n||c,url:i,type:"POST",data:JSON.stringify(t),contentType:a,credentials:!1,timeout:o,cors:!0,success:function(e){return r({success:!0,data:e})},error:function(o,u){if(e.isPageUnloading()&&e.isSupportBeaconSend()&&!n&&!c&&e.sendWithBeacon(t,i,a))return void r({success:!0,message:"XMLHttpRequest 失败,已使用 sendBeacon 发送"});s({success:!1,message:String(o),code:u})}})})):e.isPageUnloading()?e.sendWithBeacon(t,i,a)?Promise.resolve({success:!0,message:"页面卸载时发送成功"}):(e.addToPendingRequests(t),Promise.resolve({success:!0,message:"已添加到待发送队列"})):e.sendBeacon({contentType:a,url:i,data:t}).catch((function(n){return e.addToPendingRequests(t),Promise.resolve({success:!0,message:"sendBeacon 失败,已添加到待发送队列"})}))},e.sendRetained=function(n){var r=e.getParams({event:"PageRetained",desc:e.eventDescMap.PageRetained});if(["beforeunload","pushState","replaceState","hashchange","popstate"].indexOf(n)>=0){var i=e.getCookie("retainedStartTime"),o=i?+i:e.getTimeStamp(),a=t(t({},r),{privateParamMap:t(t({},r.privateParamMap),{retainedDuration:Math.max(r.requestTime-o,0)})});e.sendData(a),e.setCookie("retainedStartTime",e.getTimeStamp())}},e.getItemKey=function(t,n){return[e.initConfig.appKey,(n||e.pageKey).toString(),t?t.toString():void 0].filter((function(e){return!!e})).reduce((function(e,t){return e+(e.length?".":"")+t}),"")},e.sdkVersion="1.2.0",e.initConfig={appKey:"",platform:void 0,showLog:!1,serverUrl:"",autoTrack:!1,sendTimeout:3e3,isTrackSinglePage:!1,contentType:"application/json",business:{},header:void 0,sampleRate:1,batchSend:!1,batchInterval:5e3,batchMaxSize:10,trackPartKeyClick:!1,pendingRequestsMaxSize:50},e.systemsInfo={},e}return function(t,n){if("function"!=typeof n&&null!==n)throw new TypeError("Class extends value "+String(n)+" is not a constructor or null");function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}(i,r),i.prototype.addSinglePageEvent=function(e){var t=this,n=window.history.pushState?"popstate":"hashchange";this.each(["pushState","replaceState",n],(function(n){t.addEventListener(window,n,e)}))},i}(function(){function e(){var e=this;this.getSystemsInfo=function(e){var t=navigator.userAgent,n="other",r=[],i={language:navigator.language},o=t.match(/MicroMessenger\/([\d\.]+)/i),a=o&&o[1]?o[1]:null,s=t.match(/(ipod).*\s([\d_]+)/i),c=t.match(/(ipad).*\s([\d_]+)/i),u=t.match(/(iphone)\sos\s([\d_]+)/i),g=t.match(/(android)\s([\d\.]+)/i),l=t.match(/(Windows NT)\s([\d\.]+)/i),d=t.match(/(Mac OS X)\s([\d_]+)/i);r=[],g?(r.push("Android "+g[2]),n="h5"):u?(r.push("iPhone, iOS "+u[2].replace(/_/g,".")),n="h5"):c?(r.push("iPad, iOS "+c[2].replace(/_/g,".")),n="ipad"):s?(r.push("iPod, iOS "+s[2].replace(/_/g,".")),n="h5"):l?(r.push("Windows "+l[2].replace(/_/g,".")),n="pc"):d&&(r.push("Mac, MacOS "+d[2].replace(/_/g,".")),n="pc"),a&&r.push("WeChat "+a),i.client=r.length?r.join(", "):"Unknown",i.platform=e||n;var p=t.toLowerCase().match(/ nettype\/([^ ]+)/g);return p&&p[0]&&(r=[(p=p[0].split("/"))[1]],i.network=r.length?r.join(", "):"Unknown"),i.ua=t,i},this.addEventListener=function(e,t,n){e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent&&e.attachEvent("on"+t,(function(t){return n.call(e,t)}),!1)},this.removeEventListener=function(e,t,n){e.removeEventListener?e.removeEventListener(t,n):e.detachEvent&&e.detachEvent("on"+t,(function(t){return n.call(e,t)}),!0)},this.rewriteHistory=function(){var e=window.history,t=function(e){var t=window.history,n=t[e],r=new Event(e);return function(){var e=n.apply(t,arguments);return r.arguments=arguments,window.dispatchEvent(r),e}};window.history.pushState&&(e.pushState=t("pushState"),e.replaceState=t("replaceState"))},this.isArray=Array.isArray||function(e){return"[object Array]"===toString.call(e)},this.formatJsonString=function(e){try{return JSON.stringify(e,null," ")}catch(t){return JSON.stringify(e)}},this.nativeForEach=Array.prototype.forEach,this.slice=Array.prototype.slice,this.hasOwnProperty=Object.prototype.hasOwnProperty,this.breaker={},this.each=function(t,n,r){if(null==t)return!1;if(e.nativeForEach&&t.forEach===e.nativeForEach)t.forEach(n,r);else if(e.isArray(t)&&t.length===+t.length){for(var i=0,o=t.length;i<o;i++)if(i in t&&n.call(r,t[i],i,t)===e.breaker)return!1}else for(var a in t)if(e.hasOwnProperty.call(t,a)&&n.call(r,t[a],a,t)===e.breaker)return!1;return!0},this.getDomIndex=function(e){if(!e.parentNode)return-1;for(var t=0,n=e.tagName,r=e.parentNode.children,i=0;i<r.length;i++)if(r[i].tagName===n){if(e===r[i])return t;t++}return-1},this.selector=function(t){var n=t.parentNode&&9==t.parentNode.nodeType?-1:e.getDomIndex(t);return t.getAttribute&&t.getAttribute("id")&&/^[A-Za-z][-A-Za-z0-9_:.]*$/.test(t.getAttribute("id"))?"#"+t.getAttribute("id"):t.tagName.toLowerCase()+(~n?":nth-of-type("+(n+1)+")":"")},this.getDomSelector=function(t,n){if(!t||!t.parentNode||!t.parentNode.children)return!1;n=n&&n.join?n:[];var r=t.nodeName.toLowerCase();return t&&"body"!==r&&1==t.nodeType?(n.unshift(e.selector(t)),t.getAttribute&&t.getAttribute("id")&&/^[A-Za-z][-A-Za-z0-9_:.]*$/.test(t.getAttribute("id"))?n.join(" > "):e.getDomSelector(t.parentNode,n)):(n.unshift("body"),n.join(" > "))},this.getCookie=function(e){for(var t=e+"=",n=document.cookie.split(";"),r=0;r<n.length;r++){for(var i=n[r];" "==i.charAt(0);)i=i.substring(1,i.length);if(0==i.indexOf(t))return this._decodeURIComponent(i.substring(t.length,i.length))}return null},this.setCookie=function(e,t,n){var r,i="";n=null==n?73e3:n;var o=this.getMainHost();if(r=o?"; domain="+o:"",0!==n){var a=new Date;"s"===String(n).slice(-1)?a.setTime(a.getTime()+1e3*Number(String(n).slice(0,-1))):a.setTime(a.getTime()+24*n*60*60*1e3),i="; expires="+a.toUTCString()}function s(e){return e||!1}var c="",u="",g="";e&&(c=s(e)),t&&(u=s(t)),r&&(g=s(r)),c&&u&&(document.cookie=c+"="+encodeURIComponent(u)+i+"; path=/"+g)},this.getLocalStorage=function(e){try{return localStorage.getItem(e)}catch(e){return null}},this.setLocalStorage=function(e,t){try{localStorage.setItem(e,t)}catch(e){}},this.removeCookie=function(t){e.setCookie(t,"",-1)},this.getTimeStamp=function(){return(new Date).getTime()},this.uuid=function(){return"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".replace(/[xy]/g,(function(e){var t=16*Math.random()|0;return("x"==e?t:3&t|8).toString(16)}))},this.getDistinctId=function(){var t=e.getCookie("distinctId");return t||(t=e.uuid(),e.setCookie("distinctId",t),t)},this.filterSensitiveData=function(t,n){if(void 0===n&&(n=["password","token","secret","key"]),!e.isObject(t))return t;var r={};return e.each(t,(function(t,i){n.some((function(e){return"string"==typeof i&&i.toLowerCase().includes(e.toLowerCase())}))?r[i]="***":e.isObject(t)?r[i]=e.filterSensitiveData(t,n):r[i]=t})),r},this.xssFilter=function(e){return e?"string"!=typeof e?e.toString():e.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;"):""},this.getQueryValue=function(){for(var e=decodeURI(window.location.href).match(new RegExp("[?&][^?&]+=[^?&]+","g"))||[],t={},n=0;n<e.length;n++){var r=e[n].replace(/\?|\&/,"").split("=");t[r[0]]=r[1]}return Object.keys(t).length>0?t:null},this.ajax=function(t){function n(e){if(!e)return{};if("string"==typeof e)try{return JSON.parse(e)}catch(e){return{}}return"object"===r(e)?e:{}}t.timeout=t.timeout||3e4,t.credentials=void 0===t.credentials||t.credentials;var i=e.xhr(t.cors);if(!i)return!1;t.type||(t.type=t.data?"POST":"GET");var o,a=t.success,s=t.error;t.success=function(e){a&&a(e),o&&(clearTimeout(o),o=null)},t.error=function(e,t){s&&s(e,t),o&&(clearTimeout(o),o=null)},o=window.setTimeout((function(){!function(){try{e.isObject(i)&&i.abort&&i.abort()}catch(t){e.printLog(t)}o&&(clearTimeout(o),o=null,t.error&&t.error(),i.onreadystatechange=null,i.onload=null,i.onerror=null)}()}),t.timeout),i.onreadystatechange=function(){try{4==i.readyState&&(i.status>=200&&i.status<300||304==i.status?t.success&&t.success(n(i.responseText)):t.error&&t.error(n(i.responseText),i.status),i.onreadystatechange=null,i.onload=null)}catch(e){i.onreadystatechange=null,i.onload=null}},i.open(t.type||"GET",t.url,!0);try{t.credentials&&(i.withCredentials=!0),e.isObject(t.header)&&e.each(t.header,(function(e,t){i.setRequestHeader&&i.setRequestHeader(t,e)})),t.data&&(t.cors||i.setRequestHeader&&i.setRequestHeader("X-Requested-With","XMLHttpRequest"),"application/json"===t.contentType?i.setRequestHeader&&i.setRequestHeader("Content-type","application/json; charset=UTF-8"):i.setRequestHeader&&i.setRequestHeader("Content-type","application/x-www-form-urlencoded"))}catch(t){e.printLog(t)}i.send(t.data||null)},this.xhr=function(e){return e?void 0!==window.XMLHttpRequest&&"withCredentials"in new XMLHttpRequest?new XMLHttpRequest:null:void 0!==window.XMLHttpRequest?new XMLHttpRequest:null},this.getUA=function(){var e,t={},n=navigator.userAgent.toLowerCase();return(e=n.match(/opera.([\d.]+)/))?t.opera=Number(e[1].split(".")[0]):(e=n.match(/msie ([\d.]+)/))?t.ie=Number(e[1].split(".")[0]):(e=n.match(/edge.([\d.]+)/))?t.edge=Number(e[1].split(".")[0]):(e=n.match(/firefox\/([\d.]+)/))?t.firefox=Number(e[1].split(".")[0]):(e=n.match(/chrome\/([\d.]+)/))?t.chrome=Number(e[1].split(".")[0]):(e=n.match(/version\/([\d.]+).*safari/))?t.safari=Number(e[1].match(/^\d*.\d*/)):(e=n.match(/trident\/([\d.]+)/))&&(t.ie=11),t},this.isSupportBeaconSend=function(){var t=!1;if("object"!==("undefined"==typeof navigator?"undefined":r(navigator))||"function"!=typeof navigator.sendBeacon)return t;var n=e.getUA(),i=navigator.userAgent.toLowerCase();if(/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent)){var o=(i.match(/os [\d._]*/gi)+"").replace(/[^0-9|_.]/gi,"").replace(/_/gi,".").split(".");void 0===n.safari&&(n.safari=Number(o[0])),o[0]&&+o[0]<13?(n.chrome>41||n.firefox>30||n.opera>25||n.safari>12)&&(t=!0):(n.chrome>41||n.firefox>30||n.opera>25||n.safari>11.3)&&(t=!0)}else(n.chrome>38||n.edge>13||n.firefox>30||n.opera>25||n.safari>11)&&(t=!0);return t},this.throttle=function(e,t){var n=null,r=0;return function(){for(var i=[],o=0;o<arguments.length;o++)i[o]=arguments[o];var a=Date.now(),s=t-(a-r);s<=0||s>t?(n&&(clearTimeout(n),n=null),r=a,e.apply(void 0,i)):n||(n=window.setTimeout((function(){r=Date.now(),n=null,e.apply(void 0,i)}),s))}},this.debounce=function(e,t){var n=null;return function(){for(var r=[],i=0;i<arguments.length;i++)r[i]=arguments[i];n&&clearTimeout(n),n=window.setTimeout((function(){e.apply(void 0,r)}),t)}},this.sendBeacon=function(t){if(!0===e.isSupportBeaconSend()){var n={type:t.contentType},r=new Blob([JSON.stringify(t.data)],n);return navigator.sendBeacon(t.url,r)?Promise.resolve({success:!0,message:"发送成功"}):Promise.reject({success:!1,message:"sendBeacon返回false"})}return Promise.reject({success:!1,message:"不支持sendBeacon,发送失败!"})},this.getDeviceId=function(){var t=e.getCookie("device_id")||e.getLocalStorage("device_id");if(t)return t;var n=e.collectFingerprint(),r=e.hashFingerprint(n);return e.setCookie("device_id",r,730),e.setLocalStorage("device_id",r),r},this.collectFingerprint=function(){var t={};return t.userAgent=navigator.userAgent,t.screenWidth=screen.width,t.screenHeight=screen.height,t.colorDepth=screen.colorDepth,t.pixelDepth=screen.pixelDepth,t.timezone=Intl.DateTimeFormat().resolvedOptions().timeZone,t.timezoneOffset=(new Date).getTimezoneOffset(),t.language=navigator.language,t.languages=Array.from(navigator.languages),t.platform=navigator.platform,t.webgl=e.getWebGLFingerprint(),t.canvas=e.getCanvasFingerprint(),t.audio=e.getAudioFingerprint(),t.fonts=e.getFontFingerprint(),t.plugins=e.getPluginsFingerprint(),t.localStorage=e.hasLocalStorage(),t.sessionStorage=e.hasSessionStorage(),t.indexedDB=e.hasIndexedDB(),t.hardwareConcurrency=navigator.hardwareConcurrency,t.deviceMemory=navigator.deviceMemory,t.maxTouchPoints=navigator.maxTouchPoints,t.connection=e.getConnectionFingerprint(),t},this.getWebGLFingerprint=function(){try{var e=document.createElement("canvas"),t=e.getContext("webgl")||e.getContext("experimental-webgl");if(!t)return"not-supported";var n=t.getExtension("WEBGL_debug_renderer_info");return(n?t.getParameter(n.UNMASKED_VENDOR_WEBGL):"unknown")+"|"+(n?t.getParameter(n.UNMASKED_RENDERER_WEBGL):"unknown")}catch(e){return"error"}},this.getCanvasFingerprint=function(){try{var e=document.createElement("canvas"),t=e.getContext("2d");return t?(t.textBaseline="top",t.font="14px Arial",t.fillStyle="#f60",t.fillRect(125,1,62,20),t.fillStyle="#069",t.fillText("Canvas fingerprint",2,15),t.fillStyle="rgba(102, 204, 0, 0.7)",t.fillText("Canvas fingerprint",4,17),e.toDataURL().slice(-50)):"not-supported"}catch(e){return"error"}},this.getAudioFingerprint=function(){try{var e=window.AudioContext||window.webkitAudioContext;if(!e)return"not-supported";var t=new e,n=t.createOscillator(),r=t.createAnalyser(),i=t.createGain(),o=t.createScriptProcessor(4096,1,1);n.type="triangle",n.frequency.value=1e4,i.gain.value=0,n.connect(r),r.connect(o),o.connect(i),i.connect(t.destination),n.start(0);var a=t.sampleRate+"|"+t.currentTime;return n.stop(),t.close(),a}catch(e){return"error"}},this.getFontFingerprint=function(){try{var e=["monospace","sans-serif","serif"],t="mmmmmmmmmmlli",n=document.createElement("canvas").getContext("2d");if(!n)return"not-supported";var r=[],i={};return e.forEach((function(e){n.font="72px "+e,i[e]=n.measureText(t).width})),["Arial","Arial Black","Comic Sans MS","Courier New","Georgia","Helvetica","Impact","Times New Roman","Trebuchet MS","Verdana"].forEach((function(o){var a=!1;e.forEach((function(e){n.font="72px '"+o+"', "+e,n.measureText(t).width!==i[e]&&(a=!0)})),a&&r.push(o)})),r.join(",")}catch(e){return"error"}},this.getPluginsFingerprint=function(){try{var e=[];if(navigator.plugins)for(var t=0;t<navigator.plugins.length;t++){var n=navigator.plugins[t];n&&e.push(n.name+"|"+n.description+"|"+n.filename)}return e.join(";")}catch(e){return"error"}},this.hasLocalStorage=function(){try{var e="__test__";return localStorage.setItem(e,e),localStorage.removeItem(e),!0}catch(e){return!1}},this.hasSessionStorage=function(){try{var e="__test__";return sessionStorage.setItem(e,e),sessionStorage.removeItem(e),!0}catch(e){return!1}},this.hasIndexedDB=function(){return"indexedDB"in window&&null!==indexedDB},this.getConnectionFingerprint=function(){try{var e=navigator.connection||navigator.mozConnection||navigator.webkitConnection;return e?e.effectiveType+"|"+e.downlink+"|"+e.rtt:"not-supported"}catch(e){return"error"}},this.hashFingerprint=function(e){for(var t=JSON.stringify(e,Object.keys(e).sort()),n=5381,r=52711,i=0;i<t.length;i++){var o=t.charCodeAt(i);n=(n<<5)+n+o,r=(r<<5)+r+o}return"fp_"+(4096*(n>>>0)+(r>>>0)).toString(36)}}return e.prototype.printLog=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];if(this.isObject(e[0])&&(e[0]=this.formatJsonString(e[0])),"object"===("undefined"==typeof console?"undefined":r(console))&&console.log)try{return console.log.apply(console,e)}catch(t){console.log(e[0])}},e.prototype.isObject=function(e){return null!=e&&"[object Object]"==toString.call(e)},e.prototype.isUndefined=function(e){return void 0===e},e.prototype.isString=function(e){return"[object String]"==toString.call(e)},e.prototype.isDate=function(e){return"[object Date]"==toString.call(e)},e.prototype.isBoolean=function(e){return"[object Boolean]"==toString.call(e)},e.prototype.isNumber=function(e){return"[object Number]"==toString.call(e)&&/[\d\.]+/.test(String(e))},e.prototype.isElement=function(e){return!(!e||1!==e.nodeType)},e.prototype.isFunction=function(e){if(!e)return!1;var t=toString.call(e);return"[object Function]"==t||"[object AsyncFunction]"==t},e.prototype.isJSONString=function(e){if(!this.isString(e))return!1;try{JSON.parse(e)}catch(e){return!1}return!0},e.prototype._decodeURIComponent=function(e){var t=e;try{t=decodeURIComponent(e)}catch(n){t=e}return t},e.prototype.getMainHost=function(){var e="mh_"+Math.random(),t=new RegExp("(^|;)\\s*"+e+"=12345"),n=new Date(0),r=document.domain,i=r.split("."),o=[];for(o.unshift(i.pop());i.length;){o.unshift(i.pop());var a=o.join("."),s=e+"=12345;domain=."+a;if(document.cookie=s,t.test(document.cookie))return document.cookie=s+";expires="+n,a}return r},e}()))}));
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).WebTracking=t()}(this,(function(){"use strict";function e(t){return(e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(t)}var t=function(e,n){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])})(e,n)};var n=function(){return(n=Object.assign||function(e){for(var t,n=1,r=arguments.length;n<r;n++)for(var i in t=arguments[n])Object.prototype.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e}).apply(this,arguments)};function r(e,t){for(var n=0,r=t.length,i=e.length;n<r;n++,i++)e[i]=t[n];return e}return new(function(i){function o(){var t=i.call(this)||this;return t.batchTimer=null,t.BATCH_QUEUE_STORAGE_KEY="web_tracking_batch_queue",t.useCustomPageKey=!1,t.isUnloadListenerSetup=!1,t.pageDurationTimer=null,t.PENDING_REQUESTS_STORAGE_KEY="web_tracking_pending_requests",t.DEFAULT_PENDING_REQUESTS_MAX_SIZE=50,t.MAX_STORAGE_SIZE=4194304,t.exposureObserver=null,t.exposureElementsMap=new Map,t.userInfo=null,t.currentUrl="",t.pageKey="",t.deviceId="",t.eventDescMap={PageView:"Web 浏览页面",WebClick:"Web 元素点击",PageRetained:"Web 页面浏览时长",CustomTrack:"Web 自定义代码上报",WebExposure:"Web 元素曝光"},t.init=function(e){t.preset(e);var n=window.location.pathname;t.currentUrl=window.location.href,e.pageKey?(t.pageKey=e.pageKey,t.useCustomPageKey=!0):(t.pageKey=n.replace(/\//g,"_").substring(1),t.useCustomPageKey=!1),t.systemsInfo=t.getSystemsInfo(e.platform),t.deviceId=t.getDeviceId(),e.userInfo&&t.isObject(e.userInfo)&&(t.userInfo=e.userInfo),t.setCookie("retainedStartTime",t.getTimeStamp()),t.initConfig.batchSend&&t.restoreBatchQueueFromStorage(),t.restorePendingRequestsFromStorage(),t.setupBeforeUnloadListener(),t.initConfig.autoTrackPageDurationInterval&&t.startPageDurationTimer(),t.initConfig.autoTrackExposure&&t.initExposureObserver()},t.preset=function(e){if(e instanceof Object){if(void 0!==e.pageKey)if(null===e.pageKey||""===e.pageKey){t.useCustomPageKey=!1;var n=window.location.pathname;t.pageKey=n.replace(/\//g,"_").substring(1)}else t.pageKey=e.pageKey,t.useCustomPageKey=!0;t.each(e,(function(e,n){if("pageKey"!==n&&t.initConfig.hasOwnProperty(n)){var r=t.validateConfigParam(String(n),e);r.valid?t.initConfig[n]=e:t.printLog("配置参数验证失败: "+String(n)+" = "+e+", 原因: "+r.message)}}))}/^(((ht|f)tps?):\/\/)?[\w-]+(\.[\w-]+)+([\w.,@?^=%&:/~+#-\(\)]*[\w@?^=%&/~+#-\(\)])?$/.test(t.initConfig.serverUrl)||(t.printLog("当前 server_url 为空或不正确,只在控制台打印日志,network 中不会发数据,请配置正确的 server_url!"),t.initConfig.showLog=!0),t.initConfig.autoTrack||t.initConfig.trackPartKeyClick?t.listener():t.unlistener(),t.initConfig.autoTrackPageDurationInterval?t.startPageDurationTimer():t.stopPageDurationTimer(),t.initConfig.autoTrackExposure?t.initExposureObserver():t.stopExposureObserver()},t.validateConfigParam=function(t,n){switch(t){case"sampleRate":if("number"!=typeof n||n<0||n>1)return{valid:!1,message:"sampleRate 必须是 0-1 之间的数字"};break;case"sendTimeout":if("number"!=typeof n||n<=0)return{valid:!1,message:"sendTimeout 必须是大于 0 的数字"};break;case"batchInterval":if("number"!=typeof n||n<=0)return{valid:!1,message:"batchInterval 必须是大于 0 的数字"};break;case"batchMaxSize":if("number"!=typeof n||n<=0||!Number.isInteger(n))return{valid:!1,message:"batchMaxSize 必须是大于 0 的整数"};break;case"pendingRequestsMaxSize":if("number"!=typeof n||n<=0||!Number.isInteger(n))return{valid:!1,message:"pendingRequestsMaxSize 必须是大于 0 的整数"};break;case"pageDurationInterval":if("number"!=typeof n||n<=0)return{valid:!1,message:"pageDurationInterval 必须是大于 0 的数字"};break;case"sendMethod":if("string"!=typeof n||!["auto","xhr","beacon"].includes(n))return{valid:!1,message:"sendMethod 必须是 auto、xhr 或 beacon"};break;case"exposureThreshold":if("number"!=typeof n||n<0||n>1)return{valid:!1,message:"exposureThreshold 必须是 0-1 之间的数字"};break;case"exposureTime":if("number"!=typeof n||n<=0)return{valid:!1,message:"exposureTime 必须是大于 0 的数字"};break;case"exposureNum":if(void 0!==n&&("number"!=typeof n||n<=0||!Number.isInteger(n)))return{valid:!1,message:"exposureNum 必须是大于 0 的整数或不限制"};break;case"showLog":case"autoTrack":case"isTrackSinglePage":case"batchSend":case"trackPartKeyClick":case"autoTrackPageDurationInterval":if("boolean"!=typeof n)return{valid:!1,message:t+" 必须是布尔值"};break;case"business":case"header":if(null!==n&&"object"!==e(n))return{valid:!1,message:t+" 必须是对象或 null"};break;case"contentType":if("application/json"!==n&&"application/x-www-form-urlencoded"!==n)return{valid:!1,message:"contentType 必须是 application/json 或 application/x-www-form-urlencoded"};break;case"platform":if("string"!=typeof n)return{valid:!1,message:"platform 必须是字符串"}}return{valid:!0}},t.login=function(e){t.isObject(e)&&(t.userInfo=e)},t.getDeviceId=function(){if(t.deviceId)return t.deviceId;var e=t.getCookie("device_id")||t.getLocalStorage("device_id");if(e)return t.deviceId=e,t.deviceId;var n=t.collectFingerprint(),r=t.hashFingerprint(n);return t.setCookie("device_id",r,730),t.setLocalStorage("device_id",r),t.deviceId=r,t.deviceId},t.resetDeviceId=function(){return document.cookie="device_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;",localStorage.removeItem("device_id"),t.deviceId="",t.getDeviceId()},t.track=function(e){var n=e.desc,r=e.pageKey,i=e.partkey,o=e.business,a=e.header,s=t.getParams({desc:n,event:"CustomTrack",itemKey:t.getItemKey(i,r),privateParamMap:{business:o}});return t.sendData(s,a)},t.listener=function(){t.unlistener(),t.initConfig.autoTrack&&(t.initConfig.isTrackSinglePage&&(t.rewriteHistory(),t.addSinglePageEvent(t.onPageViewCallback)),t.each(["load","beforeunload"],(function(e){t.addEventListener(window,e,t.onPageViewCallback)}))),(t.initConfig.autoTrack||t.initConfig.trackPartKeyClick)&&t.addEventListener(window,"click",t.onClickCallback)},t.unlistener=function(){if(t.initConfig.isTrackSinglePage){var e=window.history.pushState?"popstate":"hashchange";t.each(["pushState","replaceState",e],(function(e){t.removeEventListener(window,e,t.onPageViewCallback)}))}t.each(["load","beforeunload"],(function(e){t.removeEventListener(window,e,t.onPageViewCallback)})),t.removeEventListener(window,"click",t.onClickCallback),t.clearBatchTimer(),t.stopPageDurationTimer()},t.clearBatchTimer=function(){null!==t.batchTimer&&(clearTimeout(t.batchTimer),t.batchTimer=null)},t.clearBatchQueue=function(){t.setLocalStorage(t.BATCH_QUEUE_STORAGE_KEY,"[]"),t.initConfig.showLog&&t.printLog("批量队列已清空")},t.getBatchQueueFromStorage=function(){try{var e=t.getLocalStorage(t.BATCH_QUEUE_STORAGE_KEY);if(e){var n=JSON.parse(e);if(Array.isArray(n))return n}}catch(e){t.printLog("读取批量队列失败: "+e),t.setLocalStorage(t.BATCH_QUEUE_STORAGE_KEY,"[]")}return[]},t.saveBatchQueueToStorage=function(e){try{var n=JSON.stringify(e);if(n.length>t.MAX_STORAGE_SIZE){var r=Math.floor(.8*e.length),i=e.slice(-r);t.printLog("队列过大,已截断保留最新 "+r+" 条数据(限制: "+t.MAX_STORAGE_SIZE/1024/1024+"MB)"),t.setLocalStorage(t.BATCH_QUEUE_STORAGE_KEY,JSON.stringify(i))}else t.setLocalStorage(t.BATCH_QUEUE_STORAGE_KEY,n)}catch(e){t.printLog("保存批量队列到 LocalStorage 失败: "+e)}},t.getPendingRequestsFromStorage=function(){try{var e=t.getLocalStorage(t.PENDING_REQUESTS_STORAGE_KEY);if(e){var n=JSON.parse(e);if(Array.isArray(n))return n}}catch(e){t.printLog("读取待发送请求失败: "+e),t.setLocalStorage(t.PENDING_REQUESTS_STORAGE_KEY,"[]")}return[]},t.savePendingRequestsToStorage=function(e){try{t.setLocalStorage(t.PENDING_REQUESTS_STORAGE_KEY,JSON.stringify(e))}catch(e){t.printLog("保存待发送请求到 LocalStorage 失败: "+e)}},t.setPageKey=function(e,n){if(void 0===n&&(n=!1),null===e||""===e){t.useCustomPageKey=!1;var r=window.location.pathname;t.pageKey=r.replace(/\//g,"_").substring(1),t.initConfig.showLog&&t.printLog("页面标识已恢复自动生成: "+t.pageKey)}else t.pageKey=e,t.useCustomPageKey=!n,t.initConfig.showLog&&t.printLog("页面标识已设置为: "+e+", 自动更新: "+n)},t.getPageKey=function(){return t.pageKey},t.onClickCallback=function(e){var n,r=e.target;if(null===(n=null==r?void 0:r.dataset)||void 0===n?void 0:n.partKey){var i=[e.pageX,e.pageY],o=r.id,a=r.className,s={id:o,nodeName:r.nodeName,className:a,position:i},u=t.getParams({event:"WebClick",desc:t.eventDescMap.WebClick,itemKey:t.getItemKey(r.dataset.partKey),privateParamMap:{targetEle:s,pointerType:e.pointerType,currentUrl:t.currentUrl,elementSelector:t.getDomSelector(r)||""}});t.sendData(u)}},t.onPageViewCallback=function(e){var n,r,i=t.getPendingRequestsFromStorage(),o=t.initConfig.batchSend?t.getBatchQueueFromStorage():[];(i.length>0||o.length>0)&&t.flushPendingData();var a=window.location.origin,s=t.getParams({event:"PageView",desc:t.eventDescMap.PageView,privateParamMap:{currentUrl:t.currentUrl,targetUrl:(null===(n=e.arguments)||void 0===n?void 0:n[2])?a+(null===(r=e.arguments)||void 0===r?void 0:r[2]):null}});t.currentUrl=window.location.href,t.useCustomPageKey||(t.pageKey=window.location.pathname.replace(/\//g,"_").substring(1)),t.initConfig.autoTrackPageDurationInterval&&(t.stopPageDurationTimer(),t.startPageDurationTimer()),t.sendRetained(e.type),t.sendData(s)},t.getParams=function(e){var n=e.event,r=e.desc,i=e.privateParamMap,o=void 0===i?{}:i,a=e.itemKey,s=t.initConfig.business,u=window.innerWidth,c=window.innerHeight,g=window.screen.width,l=window.screen.height,p=t.filterSensitiveData(s||{}),d=t.filterSensitiveData(t.userInfo||{}),f=t.filterSensitiveData(o||{}),h=t.filterSensitiveData(t.getQueryValue()||{}),m={currentUrl:f.currentUrl||t.currentUrl,business:Object.assign({},p,f.business||{}),pageWidth:u,pageHeight:c,screenWidth:g,screenHeight:l,sdkVersion:t.sdkVersion,systemsInfo:t.systemsInfo,urlParams:h,userInfo:d,deviceId:t.deviceId};return f.targetEle&&(m.targetEle=f.targetEle),f.targetUrl&&(m.targetUrl=f.targetUrl),f.pointerType&&(m.pointerType=f.pointerType),f.elementSelector&&(m.elementSelector=f.elementSelector),f.retainedDuration&&(m.retainedDuration=f.retainedDuration),{event:n,desc:r,itemKey:a||t.getItemKey(),requestTime:t.getTimeStamp(),privateParamMap:m}},t.shouldSample=function(){var e=t.initConfig.sampleRate;return e>=1||!(e<=0)&&Math.random()<e},t.flushBatchQueue=function(){var e=t.getBatchQueueFromStorage();if(0!==e.length){var n=t.getTimeStamp(),r=e.filter((function(e){return!e._nextRetryTime||e._nextRetryTime<=n}));if(0!==r.length){var i=e.filter((function(e){return!!e._nextRetryTime&&e._nextRetryTime>n}));t.saveBatchQueueToStorage(i),t.sendBatchData(r)}else t.initConfig.showLog&&t.printLog("批量队列中有 "+e.length+" 条数据等待重试")}},t.sendBatchData=function(e){var n=t.initConfig,r=n.serverUrl,i=n.contentType,o=n.showLog,a=n.sendMethod,s=n.header;if(o&&(t.printLog("批量发送 "+e.length+" 条数据"),e.forEach((function(e){return t.printLog(e)}))),t.shouldUseBeacon(a,void 0,s))try{var u=new Blob([JSON.stringify(e)],{type:i||"application/json"});navigator.sendBeacon(r,u)?(t.saveBatchQueueToStorage([]),o&&t.printLog("批量发送成功: "+e.length+" 条数据")):(t.printLog("批量发送失败: sendBeacon 返回 false,数据已重新加入队列"),t.retryBatchData(e))}catch(n){t.printLog("批量发送失败: "+n+",数据已重新加入队列"),t.retryBatchData(e)}else t.ajax({url:r,type:"POST",data:JSON.stringify({events:e}),contentType:i,credentials:!1,timeout:t.initConfig.sendTimeout,cors:!0,success:function(){t.saveBatchQueueToStorage([]),t.initConfig.showLog&&t.printLog("批量发送成功: "+e.length+" 条数据")},error:function(n){t.printLog("批量发送失败: "+n+",数据已重新加入队列"),t.retryBatchData(e)}})},t.retryBatchData=function(e){var n=t.getBatchQueueFromStorage(),i=function(e){return e.event+"_"+e.itemKey+"_"+e.requestTime},o=new Set(n.map(i)),a=t.getTimeStamp(),s=e.filter((function(e){var n=i(e);if(o.has(n))return!1;var r=(e._retryCount||0)+1;return r>3?(t.initConfig.showLog&&t.printLog("数据已达到最大重试次数,放弃重试: "+n),!1):(e._retryCount=r,e._nextRetryTime=a+1e3*Math.pow(2,r),o.add(n),!0)})),u=r(r([],s),n),c=2*t.initConfig.batchMaxSize,g=u.length>c?u.slice(0,c):u;t.saveBatchQueueToStorage(g),t.initConfig.showLog&&t.printLog("已将 "+s.length+" 条数据加入重试队列")},t.addToBatchQueue=function(e){var n=t.initConfig,r=n.batchInterval,i=n.batchMaxSize;if(t.shouldSample()){var o=t.getBatchQueueFromStorage();o.push(e),t.saveBatchQueueToStorage(o),o.length>=i?t.flushBatchQueue():t.batchTimer||(t.batchTimer=window.setTimeout((function(){t.flushBatchQueue(),t.batchTimer=null}),r))}else t.initConfig.showLog&&t.printLog("数据已采样跳过(批量模式)")},t.restoreBatchQueueFromStorage=function(){var e=t.getBatchQueueFromStorage();if(e.length>0){t.initConfig.showLog&&t.printLog("从 LocalStorage 恢复 "+e.length+" 条待发送数据");var n=t.initConfig.batchMaxSize;if(e.length>=n)t.flushBatchQueue();else{var r=t.initConfig.batchInterval;t.batchTimer||(t.batchTimer=window.setTimeout((function(){t.flushBatchQueue(),t.batchTimer=null}),r))}}},t.addToPendingRequests=function(e){var n=t.getPendingRequestsFromStorage();n.push(e);var r=t.initConfig.pendingRequestsMaxSize||t.DEFAULT_PENDING_REQUESTS_MAX_SIZE;if(n.length>r){var i=n.slice(-r);t.initConfig.showLog&&t.printLog("待发送请求队列已满,已移除最旧的数据(最大限制: "+r+")"),t.savePendingRequestsToStorage(i)}else t.savePendingRequestsToStorage(n)},t.restorePendingRequestsFromStorage=function(){var e=t.getPendingRequestsFromStorage();e.length>0&&t.initConfig.showLog&&t.printLog("从 LocalStorage 恢复 "+e.length+" 条待发送请求")},t.isPageUnloading=function(){return"hidden"===document.visibilityState},t.sendWithBeacon=function(e,n,r){try{var i=new Blob([JSON.stringify(e)],{type:r||"application/json"});return navigator.sendBeacon(n,i)}catch(e){return t.initConfig.showLog&&t.printLog("sendBeacon 发送失败: "+e),!1}},t.flushPendingRequests=function(){var e=t.getPendingRequestsFromStorage();if(0!==e.length){t.savePendingRequestsToStorage([]);var n=t.initConfig,r=n.serverUrl,i=n.sendTimeout,o=n.contentType,a=n.showLog,s=n.header;e.forEach((function(e){t.shouldSample()?(a&&t.printLog(e),t.ajax({header:s,url:r,type:"POST",data:JSON.stringify(e),contentType:o,credentials:!1,timeout:i,cors:!0,success:function(){a&&t.printLog("待发送请求发送成功")},error:function(e){a&&t.printLog("待发送请求发送失败(不再重试): "+e)}})):a&&t.printLog("待发送请求已采样跳过")}))}},t.setupBeforeUnloadListener=function(){t.isUnloadListenerSetup||(t.isUnloadListenerSetup=!0,document.addEventListener("visibilitychange",(function(){t.isPageUnloading()&&t.flushPendingData()})),window.addEventListener("beforeunload",(function(){t.flushPendingData()})),window.addEventListener("pagehide",(function(){t.flushPendingData()})))},t.isFlushingPendingData=!1,t.flushPendingData=function(){if(!t.isFlushingPendingData){t.stopPageDurationTimer();var e=[],n=t.getBatchQueueFromStorage();n.length>0&&e.push.apply(e,n);var r=t.getPendingRequestsFromStorage();if(r.length>0&&e.push.apply(e,r),0!==e.length){t.isFlushingPendingData=!0;try{t.initConfig.batchSend?t.setLocalStorage(t.BATCH_QUEUE_STORAGE_KEY,JSON.stringify(e)):t.setLocalStorage(t.PENDING_REQUESTS_STORAGE_KEY,JSON.stringify(e))}catch(e){t.initConfig.showLog&&t.printLog("保存待发送请求到 LocalStorage 失败: "+e)}if(navigator.sendBeacon&&t.initConfig.serverUrl)try{var i=1===e.length?e[0]:e,o=new Blob([JSON.stringify(i)],{type:t.initConfig.contentType||"application/json"});navigator.sendBeacon(t.initConfig.serverUrl,o)?(t.setLocalStorage(t.BATCH_QUEUE_STORAGE_KEY,"[]"),t.setLocalStorage(t.PENDING_REQUESTS_STORAGE_KEY,"[]"),t.initConfig.showLog&&t.printLog("页面卸载时成功发送 "+e.length+" 条数据")):t.initConfig.showLog&&t.printLog("sendBeacon 返回 false,数据已保存到 LocalStorage 等待下次恢复")}catch(e){t.initConfig.showLog&&t.printLog("页面卸载时发送数据失败: "+e+",数据已保存到 LocalStorage")}finally{t.isFlushingPendingData=!1}else t.initConfig.showLog&&t.printLog("不支持 sendBeacon,数据已保存到 LocalStorage 等待下次恢复"),t.isFlushingPendingData=!1}}},t.sendData=function(e,n){if(!t.shouldSample())return Promise.resolve({success:!0,message:"数据已采样跳过"});var r=t.initConfig,i=r.serverUrl,o=r.sendTimeout,a=r.contentType,s=r.showLog,u=r.header,c=r.batchSend,g=r.sendMethod;return s&&t.printLog(e),c?(t.addToBatchQueue(e),Promise.resolve({success:!0,message:"已添加到批量队列"})):t.shouldUseBeacon(g,n,u)?t.isPageUnloading()?t.sendWithBeacon(e,i,a)?Promise.resolve({success:!0,message:"页面卸载时发送成功"}):(t.addToPendingRequests(e),Promise.resolve({success:!0,message:"已添加到待发送队列"})):t.sendBeacon({contentType:a,url:i,data:e}).catch((function(n){return t.addToPendingRequests(e),Promise.resolve({success:!0,message:"sendBeacon 失败,已添加到待发送队列"})})):new Promise((function(r,s){if(t.isPageUnloading()&&"auto"===g&&t.isSupportBeaconSend()&&!n&&!u&&t.sendWithBeacon(e,i,a))return void r({success:!0,message:"页面卸载时使用 sendBeacon 发送成功"});t.ajax({header:n||u,url:i,type:"POST",data:JSON.stringify(e),contentType:a,credentials:!1,timeout:o,cors:!0,success:function(e){return r({success:!0,data:e})},error:function(o,c){if(t.isPageUnloading()&&"auto"===g&&t.isSupportBeaconSend()&&!n&&!u&&t.sendWithBeacon(e,i,a))return void r({success:!0,message:"XMLHttpRequest 失败,已使用 sendBeacon 发送"});s({success:!1,message:String(o),code:c})}})}))},t.shouldUseBeacon=function(e,n,r){return"xhr"!==e&&("beacon"===e?!0===t.isSupportBeaconSend():!0===t.isSupportBeaconSend()&&!n&&!r)},t.sendRetained=function(e){var r=t.getParams({event:"PageRetained",desc:t.eventDescMap.PageRetained});if(["beforeunload","pushState","replaceState","hashchange","popstate"].indexOf(e)>=0){var i=t.getCookie("retainedStartTime"),o=i?+i:t.getTimeStamp(),a=n(n({},r),{privateParamMap:n(n({},r.privateParamMap),{retainedDuration:Math.max(r.requestTime-o,0)})});t.sendData(a),t.setCookie("retainedStartTime",t.getTimeStamp())}},t.trackPageDuration=function(e,n,r){var i;if(void 0===r&&(r=!0),null!=e)i=Math.max(e,0);else{var o=t.getCookie("retainedStartTime"),a=o?+o:t.getTimeStamp(),s=t.getTimeStamp();i=Math.max(s-a,0)}var u=(null==n?void 0:n.desc)||t.eventDescMap.PageRetained,c=(null==n?void 0:n.pageKey)||t.pageKey,g=(null==n?void 0:n.business)||{},l=null==n?void 0:n.header,p=t.getParams({event:"PageRetained",desc:u,itemKey:t.getItemKey(void 0,c),privateParamMap:{business:g,retainedDuration:i}}),d=t.sendData(p,l);return r&&t.setCookie("retainedStartTime",t.getTimeStamp()),d},t.startPageDurationTimer=function(){t.stopPageDurationTimer();var e=t.initConfig.pageDurationInterval||3e4;e<=0?t.initConfig.showLog&&t.printLog("定时上报间隔时间无效,已禁用定时上报"):(t.pageDurationTimer=window.setInterval((function(){"visible"===document.visibilityState&&t.trackPageDuration(e,{desc:"定时上报页面停留时长",business:{reportType:"interval",interval:e}},!0).catch((function(e){t.initConfig.showLog&&t.printLog("定时上报页面停留时长失败: "+e)}))}),e),t.initConfig.showLog&&t.printLog("定时上报页面停留时长已启动,间隔: "+e+"ms"))},t.stopPageDurationTimer=function(){null!==t.pageDurationTimer&&(clearInterval(t.pageDurationTimer),t.pageDurationTimer=null,t.initConfig.showLog&&t.printLog("定时上报页面停留时长已停止"))},t.getItemKey=function(e,n){return[t.initConfig.appKey,(n||t.pageKey).toString(),e?e.toString():void 0].filter((function(e){return!!e})).reduce((function(e,t){return e+(e.length?".":"")+t}),"")},t.extractDataAttributes=function(e){for(var t={},n=e;n;){for(var r=n.attributes,i=0;i<r.length;i++){var o=r[i],a=o.name;if(a.startsWith("data-")&&"data-exposure"!==a&&"data-part-key"!==a&&"data-desc"!==a){var s=o.value;if(s)t[a.replace(/^data-/,"").split("-").map((function(e,t){return 0===t?e:e.charAt(0).toUpperCase()+e.slice(1)})).join("")]=s}}if((n=n.parentElement)&&"BODY"===n.tagName)break}return t},t.initExposureObserver=function(){if(t.initConfig.autoTrackExposure)if("IntersectionObserver"in window){var e=t.initConfig.exposureThreshold||.5;t.exposureObserver=new IntersectionObserver((function(e){e.forEach((function(e){var n=e.target,r=t.exposureElementsMap.get(n);if(r){var i=t.initConfig.exposureTime||500;e.isIntersecting?(r.isVisible=!0,r.visibleStartTime=t.getTimeStamp(),r.exposureTimer&&clearTimeout(r.exposureTimer),r.exposureTimer=window.setTimeout((function(){r.isVisible&&t.reportExposure(n)}),i)):(r.isVisible=!1,r.exposureTimer&&(clearTimeout(r.exposureTimer),r.exposureTimer=null))}}))}),{threshold:e}),t.observeExposureElements()}else t.initConfig.showLog&&t.printLog("当前浏览器不支持 IntersectionObserver,无法启用曝光埋点")},t.observeExposureElements=function(){if(t.exposureObserver){var e=document.querySelectorAll('[data-exposure="true"]');e.forEach((function(e){if(!t.exposureElementsMap.has(e)){var n=e;t.exposureElementsMap.set(n,{element:n,visibleStartTime:0,exposureCount:0,isVisible:!1,exposureTimer:null}),t.exposureObserver.observe(n)}})),t.initConfig.showLog&&e.length>0&&t.printLog("已监听 "+e.length+" 个曝光元素")}},t.reportExposure=function(e){var n=t.exposureElementsMap.get(e);if(n){var r=t.initConfig.exposureNum;if(void 0!==r&&n.exposureCount>=r)t.initConfig.showLog&&t.printLog("元素已达到最大曝光次数限制: "+r);else{var i=t.extractDataAttributes(e),o=e.getAttribute("data-desc")||t.eventDescMap.WebExposure,a=e.getAttribute("data-part-key")||"exposure",s=t.getParams({event:"WebExposure",desc:o,itemKey:t.getItemKey(a),privateParamMap:{business:i}});t.sendData(s).then((function(){n.exposureCount++,n.exposureTimer&&(clearTimeout(n.exposureTimer),n.exposureTimer=null),t.initConfig.showLog&&t.printLog("曝光上报成功,当前曝光次数: "+n.exposureCount)})).catch((function(e){t.initConfig.showLog&&t.printLog("曝光上报失败: "+e)}))}}},t.stopExposureObserver=function(){t.exposureObserver&&(t.exposureObserver.disconnect(),t.exposureObserver=null,t.exposureElementsMap.forEach((function(e){e.exposureTimer&&clearTimeout(e.exposureTimer)})),t.exposureElementsMap.clear(),t.initConfig.showLog&&t.printLog("曝光监听已停止"))},t.sdkVersion="1.2.4",t.initConfig={appKey:"",platform:void 0,showLog:!1,serverUrl:"",autoTrack:!1,sendTimeout:3e3,isTrackSinglePage:!1,contentType:"application/json",business:{},header:void 0,sampleRate:1,batchSend:!1,batchInterval:5e3,batchMaxSize:10,trackPartKeyClick:!1,pendingRequestsMaxSize:50,autoTrackPageDurationInterval:!1,pageDurationInterval:3e4,sendMethod:"auto",autoTrackExposure:!1,exposureThreshold:.5,exposureTime:500,exposureNum:void 0},t.systemsInfo={},t}return function(e,n){if("function"!=typeof n&&null!==n)throw new TypeError("Class extends value "+String(n)+" is not a constructor or null");function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}(o,i),o.prototype.addSinglePageEvent=function(e){var t=this,n=window.history.pushState?"popstate":"hashchange";this.each(["pushState","replaceState",n],(function(n){t.addEventListener(window,n,e)}))},o}(function(){function t(){var t=this;this.getSystemsInfo=function(e){var t=navigator.userAgent,n="other",r=[],i={language:navigator.language},o=t.match(/MicroMessenger\/([\d\.]+)/i),a=o&&o[1]?o[1]:null,s=t.match(/(ipod).*\s([\d_]+)/i),u=t.match(/(ipad).*\s([\d_]+)/i),c=t.match(/(iphone)\sos\s([\d_]+)/i),g=t.match(/(android)\s([\d\.]+)/i),l=t.match(/(Windows NT)\s([\d\.]+)/i),p=t.match(/(Mac OS X)\s([\d_]+)/i);r=[],g?(r.push("Android "+g[2]),n="h5"):c?(r.push("iPhone, iOS "+c[2].replace(/_/g,".")),n="h5"):u?(r.push("iPad, iOS "+u[2].replace(/_/g,".")),n="ipad"):s?(r.push("iPod, iOS "+s[2].replace(/_/g,".")),n="h5"):l?(r.push("Windows "+l[2].replace(/_/g,".")),n="pc"):p&&(r.push("Mac, MacOS "+p[2].replace(/_/g,".")),n="pc"),a&&r.push("WeChat "+a),i.client=r.length?r.join(", "):"Unknown",i.platform=e||n;var d=t.toLowerCase().match(/ nettype\/([^ ]+)/g);return d&&d[0]&&(r=[(d=d[0].split("/"))[1]],i.network=r.length?r.join(", "):"Unknown"),i.ua=t,i},this.addEventListener=function(e,t,n){e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent&&e.attachEvent("on"+t,(function(t){return n.call(e,t)}),!1)},this.removeEventListener=function(e,t,n){e.removeEventListener?e.removeEventListener(t,n):e.detachEvent&&e.detachEvent("on"+t,(function(t){return n.call(e,t)}),!0)},this.rewriteHistory=function(){var e=window.history,t=function(e){var t=window.history,n=t[e],r=new Event(e);return function(){var e=n.apply(t,arguments);return r.arguments=arguments,window.dispatchEvent(r),e}};window.history.pushState&&(e.pushState=t("pushState"),e.replaceState=t("replaceState"))},this.isArray=Array.isArray||function(e){return"[object Array]"===toString.call(e)},this.formatJsonString=function(e){try{return JSON.stringify(e,null," ")}catch(t){return JSON.stringify(e)}},this.nativeForEach=Array.prototype.forEach,this.slice=Array.prototype.slice,this.hasOwnProperty=Object.prototype.hasOwnProperty,this.breaker={},this.each=function(e,n,r){if(null==e)return!1;if(t.nativeForEach&&e.forEach===t.nativeForEach)e.forEach(n,r);else if(t.isArray(e)&&e.length===+e.length){for(var i=0,o=e.length;i<o;i++)if(i in e&&n.call(r,e[i],i,e)===t.breaker)return!1}else for(var a in e)if(t.hasOwnProperty.call(e,a)&&n.call(r,e[a],a,e)===t.breaker)return!1;return!0},this.getDomIndex=function(e){if(!e.parentNode)return-1;for(var t=0,n=e.tagName,r=e.parentNode.children,i=0;i<r.length;i++)if(r[i].tagName===n){if(e===r[i])return t;t++}return-1},this.selector=function(e){var n=e.parentNode&&9==e.parentNode.nodeType?-1:t.getDomIndex(e);return e.getAttribute&&e.getAttribute("id")&&/^[A-Za-z][-A-Za-z0-9_:.]*$/.test(e.getAttribute("id"))?"#"+e.getAttribute("id"):e.tagName.toLowerCase()+(~n?":nth-of-type("+(n+1)+")":"")},this.getDomSelector=function(e,n){if(!e||!e.parentNode||!e.parentNode.children)return!1;n=n&&n.join?n:[];var r=e.nodeName.toLowerCase();return e&&"body"!==r&&1==e.nodeType?(n.unshift(t.selector(e)),e.getAttribute&&e.getAttribute("id")&&/^[A-Za-z][-A-Za-z0-9_:.]*$/.test(e.getAttribute("id"))?n.join(" > "):t.getDomSelector(e.parentNode,n)):(n.unshift("body"),n.join(" > "))},this.getCookie=function(e){for(var t=e+"=",n=document.cookie.split(";"),r=0;r<n.length;r++){for(var i=n[r];" "==i.charAt(0);)i=i.substring(1,i.length);if(0==i.indexOf(t))return this._decodeURIComponent(i.substring(t.length,i.length))}return null},this.setCookie=function(e,t,n){var r,i="";n=null==n?73e3:n;var o=this.getMainHost();if(r=o?"; domain="+o:"",0!==n){var a=new Date;"s"===String(n).slice(-1)?a.setTime(a.getTime()+1e3*Number(String(n).slice(0,-1))):a.setTime(a.getTime()+24*n*60*60*1e3),i="; expires="+a.toUTCString()}function s(e){return e||!1}var u="",c="",g="";e&&(u=s(e)),t&&(c=s(t)),r&&(g=s(r)),u&&c&&(document.cookie=u+"="+encodeURIComponent(c)+i+"; path=/"+g)},this.getLocalStorage=function(e){try{return localStorage.getItem(e)}catch(e){return null}},this.setLocalStorage=function(e,t){try{localStorage.setItem(e,t)}catch(e){}},this.removeCookie=function(e){t.setCookie(e,"",-1)},this.getTimeStamp=function(){return(new Date).getTime()},this.uuid=function(){return"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".replace(/[xy]/g,(function(e){var t=16*Math.random()|0;return("x"==e?t:3&t|8).toString(16)}))},this.getDistinctId=function(){var e=t.getCookie("distinctId");return e||(e=t.uuid(),t.setCookie("distinctId",e),e)},this.filterSensitiveData=function(e,n){if(void 0===n&&(n=["password","token","secret","key"]),!t.isObject(e))return e;var r={};return t.each(e,(function(e,i){n.some((function(e){return"string"==typeof i&&i.toLowerCase().includes(e.toLowerCase())}))?r[i]="***":t.isObject(e)?r[i]=t.filterSensitiveData(e,n):r[i]=e})),r},this.xssFilter=function(e){return e?"string"!=typeof e?e.toString():e.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;"):""},this.getQueryValue=function(){for(var e=decodeURI(window.location.href).match(new RegExp("[?&][^?&]+=[^?&]+","g"))||[],t={},n=0;n<e.length;n++){var r=e[n].replace(/\?|\&/,"").split("=");t[r[0]]=r[1]}return Object.keys(t).length>0?t:null},this.ajax=function(n){function r(t){if(!t)return{};if("string"==typeof t)try{return JSON.parse(t)}catch(e){return{}}return"object"===e(t)?t:{}}n.timeout=n.timeout||3e4,n.credentials=void 0===n.credentials||n.credentials;var i=t.xhr(n.cors);if(!i)return!1;n.type||(n.type=n.data?"POST":"GET");var o,a=n.success,s=n.error;n.success=function(e){a&&a(e),o&&(clearTimeout(o),o=null)},n.error=function(e,t){s&&s(e,t),o&&(clearTimeout(o),o=null)},o=window.setTimeout((function(){!function(){try{t.isObject(i)&&i.abort&&i.abort()}catch(e){t.printLog(e)}o&&(clearTimeout(o),o=null,n.error&&n.error(),i.onreadystatechange=null,i.onload=null,i.onerror=null)}()}),n.timeout),i.onreadystatechange=function(){try{4==i.readyState&&(i.status>=200&&i.status<300||304==i.status?n.success&&n.success(r(i.responseText)):n.error&&n.error(r(i.responseText),i.status),i.onreadystatechange=null,i.onload=null)}catch(e){i.onreadystatechange=null,i.onload=null}},i.open(n.type||"GET",n.url,!0);try{n.credentials&&(i.withCredentials=!0),t.isObject(n.header)&&t.each(n.header,(function(e,t){i.setRequestHeader&&i.setRequestHeader(t,e)})),n.data&&(n.cors||i.setRequestHeader&&i.setRequestHeader("X-Requested-With","XMLHttpRequest"),"application/json"===n.contentType?i.setRequestHeader&&i.setRequestHeader("Content-type","application/json; charset=UTF-8"):i.setRequestHeader&&i.setRequestHeader("Content-type","application/x-www-form-urlencoded"))}catch(e){t.printLog(e)}i.send(n.data||null)},this.xhr=function(e){return e?void 0!==window.XMLHttpRequest&&"withCredentials"in new XMLHttpRequest?new XMLHttpRequest:null:void 0!==window.XMLHttpRequest?new XMLHttpRequest:null},this.getUA=function(){var e,t={},n=navigator.userAgent.toLowerCase();return(e=n.match(/opera.([\d.]+)/))?t.opera=Number(e[1].split(".")[0]):(e=n.match(/msie ([\d.]+)/))?t.ie=Number(e[1].split(".")[0]):(e=n.match(/edge.([\d.]+)/))?t.edge=Number(e[1].split(".")[0]):(e=n.match(/firefox\/([\d.]+)/))?t.firefox=Number(e[1].split(".")[0]):(e=n.match(/chrome\/([\d.]+)/))?t.chrome=Number(e[1].split(".")[0]):(e=n.match(/version\/([\d.]+).*safari/))?t.safari=Number(e[1].match(/^\d*.\d*/)):(e=n.match(/trident\/([\d.]+)/))&&(t.ie=11),t},this.isSupportBeaconSend=function(){var n=!1;if("object"!==("undefined"==typeof navigator?"undefined":e(navigator))||"function"!=typeof navigator.sendBeacon)return n;var r=t.getUA(),i=navigator.userAgent.toLowerCase();if(/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent)){var o=(i.match(/os [\d._]*/gi)+"").replace(/[^0-9|_.]/gi,"").replace(/_/gi,".").split(".");void 0===r.safari&&(r.safari=Number(o[0])),o[0]&&+o[0]<13?(r.chrome>41||r.firefox>30||r.opera>25||r.safari>12)&&(n=!0):(r.chrome>41||r.firefox>30||r.opera>25||r.safari>11.3)&&(n=!0)}else(r.chrome>38||r.edge>13||r.firefox>30||r.opera>25||r.safari>11)&&(n=!0);return n},this.throttle=function(e,t){var n=null,r=0;return function(){for(var i=[],o=0;o<arguments.length;o++)i[o]=arguments[o];var a=Date.now(),s=t-(a-r);s<=0||s>t?(n&&(clearTimeout(n),n=null),r=a,e.apply(void 0,i)):n||(n=window.setTimeout((function(){r=Date.now(),n=null,e.apply(void 0,i)}),s))}},this.debounce=function(e,t){var n=null;return function(){for(var r=[],i=0;i<arguments.length;i++)r[i]=arguments[i];n&&clearTimeout(n),n=window.setTimeout((function(){e.apply(void 0,r)}),t)}},this.sendBeacon=function(e){if(!0===t.isSupportBeaconSend()){var n={type:e.contentType},r=new Blob([JSON.stringify(e.data)],n);return navigator.sendBeacon(e.url,r)?Promise.resolve({success:!0,message:"发送成功"}):Promise.reject({success:!1,message:"sendBeacon返回false"})}return Promise.reject({success:!1,message:"不支持sendBeacon,发送失败!"})},this.getDeviceId=function(){var e=t.getCookie("device_id")||t.getLocalStorage("device_id");if(e)return e;var n=t.collectFingerprint(),r=t.hashFingerprint(n);return t.setCookie("device_id",r,730),t.setLocalStorage("device_id",r),r},this.collectFingerprint=function(){var e={};return e.userAgent=navigator.userAgent,e.screenWidth=screen.width,e.screenHeight=screen.height,e.colorDepth=screen.colorDepth,e.pixelDepth=screen.pixelDepth,e.timezone=Intl.DateTimeFormat().resolvedOptions().timeZone,e.timezoneOffset=(new Date).getTimezoneOffset(),e.language=navigator.language,e.languages=Array.from(navigator.languages),e.platform=navigator.platform,e.webgl=t.getWebGLFingerprint(),e.canvas=t.getCanvasFingerprint(),e.audio=t.getAudioFingerprint(),e.fonts=t.getFontFingerprint(),e.plugins=t.getPluginsFingerprint(),e.localStorage=t.hasLocalStorage(),e.sessionStorage=t.hasSessionStorage(),e.indexedDB=t.hasIndexedDB(),e.hardwareConcurrency=navigator.hardwareConcurrency,e.deviceMemory=navigator.deviceMemory,e.maxTouchPoints=navigator.maxTouchPoints,e.connection=t.getConnectionFingerprint(),e},this.getWebGLFingerprint=function(){try{var e=document.createElement("canvas"),t=e.getContext("webgl")||e.getContext("experimental-webgl");if(!t)return"not-supported";var n=t.getExtension("WEBGL_debug_renderer_info");return(n?t.getParameter(n.UNMASKED_VENDOR_WEBGL):"unknown")+"|"+(n?t.getParameter(n.UNMASKED_RENDERER_WEBGL):"unknown")}catch(e){return"error"}},this.getCanvasFingerprint=function(){try{var e=document.createElement("canvas");e.width=200,e.height=50;var t=e.getContext("2d");return t?(t.textBaseline="top",t.font="14px Arial",t.fillStyle="#f60",t.fillRect(125,1,62,20),t.fillStyle="#069",t.fillText("Canvas fingerprint",2,15),t.fillStyle="rgba(102, 204, 0, 0.7)",t.fillText("Canvas fingerprint",4,17),e.toDataURL().slice(-50)):"not-supported"}catch(e){return"error"}},this.getAudioFingerprint=function(){try{var e=window.AudioContext||window.webkitAudioContext;if(!e)return"not-supported";var t=new e,n=String(t.sampleRate||0);return t.close(),n}catch(e){return"error"}},this.getFontFingerprint=function(){try{var e=["monospace","sans-serif","serif"],t="mmmmmmmmmmlli",n=document.createElement("canvas").getContext("2d");if(!n)return"not-supported";var r=[],i={};return e.forEach((function(e){n.font="72px "+e,i[e]=n.measureText(t).width})),["Arial","Arial Black","Comic Sans MS","Courier New","Georgia","Helvetica","Impact","Times New Roman","Trebuchet MS","Verdana"].forEach((function(o){var a=!1;e.forEach((function(e){n.font="72px '"+o+"', "+e,n.measureText(t).width!==i[e]&&(a=!0)})),a&&r.push(o)})),r.join(",")}catch(e){return"error"}},this.getPluginsFingerprint=function(){try{var e=[];if(navigator.plugins)for(var t=0;t<navigator.plugins.length;t++){var n=navigator.plugins[t];n&&e.push(n.name+"|"+n.description+"|"+n.filename)}return e.join(";")}catch(e){return"error"}},this.hasLocalStorage=function(){try{var e="__test__";return localStorage.setItem(e,e),localStorage.removeItem(e),!0}catch(e){return!1}},this.hasSessionStorage=function(){try{var e="__test__";return sessionStorage.setItem(e,e),sessionStorage.removeItem(e),!0}catch(e){return!1}},this.hasIndexedDB=function(){return"indexedDB"in window&&null!==indexedDB},this.getConnectionFingerprint=function(){try{var e=navigator.connection||navigator.mozConnection||navigator.webkitConnection;return e?e.effectiveType||"unknown":"not-supported"}catch(e){return"error"}},this.hashFingerprint=function(e){for(var t=JSON.stringify(e,Object.keys(e).sort()),n=5381,r=52711,i=0;i<t.length;i++){var o=t.charCodeAt(i);n=(n<<5)+n+o,r=(r<<5)+r+o}return"fp_"+(n>>>0).toString(16).padStart(8,"0")+(r>>>0).toString(16).padStart(8,"0")}}return t.prototype.printLog=function(){for(var t=[],n=0;n<arguments.length;n++)t[n]=arguments[n];if(this.isObject(t[0])&&(t[0]=this.formatJsonString(t[0])),"object"===("undefined"==typeof console?"undefined":e(console))&&console.log)try{return console.log.apply(console,t)}catch(e){console.log(t[0])}},t.prototype.isObject=function(e){return null!=e&&"[object Object]"==toString.call(e)},t.prototype.isUndefined=function(e){return void 0===e},t.prototype.isString=function(e){return"[object String]"==toString.call(e)},t.prototype.isDate=function(e){return"[object Date]"==toString.call(e)},t.prototype.isBoolean=function(e){return"[object Boolean]"==toString.call(e)},t.prototype.isNumber=function(e){return"[object Number]"==toString.call(e)&&/[\d\.]+/.test(String(e))},t.prototype.isElement=function(e){return!(!e||1!==e.nodeType)},t.prototype.isFunction=function(e){if(!e)return!1;var t=toString.call(e);return"[object Function]"==t||"[object AsyncFunction]"==t},t.prototype.isJSONString=function(e){if(!this.isString(e))return!1;try{JSON.parse(e)}catch(e){return!1}return!0},t.prototype._decodeURIComponent=function(e){var t=e;try{t=decodeURIComponent(e)}catch(n){t=e}return t},t.prototype.getMainHost=function(){var e="mh_"+Math.random(),t=new RegExp("(^|;)\\s*"+e+"=12345"),n=new Date(0),r=document.domain,i=r.split("."),o=[];for(o.unshift(i.pop());i.length;){o.unshift(i.pop());var a=o.join("."),s=e+"=12345;domain=."+a;if(document.cookie=s,t.test(document.cookie))return document.cookie=s+";expires="+n,a}return r},t}()))}));
@@ -1,27 +1,28 @@
1
1
  /**
2
2
  * web 数据埋点 SDK
3
3
  * @class WebTracking
4
- * @version 1.2.0
4
+ * @version 1.2.4
5
5
  * key由这几部分组成:appkey.pagekey.partkey 通过“.”来分割
6
6
  * appkey:应用唯一标识
7
7
  * pagekey:页面唯一标识,取当前路由 window.location.pathname.replace(/\//g, '_').substr(1)
8
8
  * partkey:控件/自定义事件唯一标识,可通过接口获取或自定义
9
9
  */
10
10
  import Tools from "./tools";
11
- import { EventParams, InitParams, SystemsInfoTypes, TrackParams, PresetParams, TrackingPostParams, JsonProps, EventTypes, GetParamsOptions, TrackingResponse } from "./type";
11
+ import { EventParams, InitParams, SystemsInfoTypes, TrackParams, PresetParams, TrackingPostParams, JsonProps, EventTypes, GetParamsOptions, TrackingResponse, TrackPageDurationOptions } from "./type";
12
12
  declare class WebTracking extends Tools {
13
13
  initConfig: InitParams;
14
14
  sdkVersion: string;
15
15
  systemsInfo: SystemsInfoTypes;
16
- private batchQueue;
17
16
  private batchTimer;
18
17
  private readonly BATCH_QUEUE_STORAGE_KEY;
19
18
  private useCustomPageKey;
20
- private pendingRequests;
21
19
  private isUnloadListenerSetup;
20
+ private pageDurationTimer;
22
21
  private readonly PENDING_REQUESTS_STORAGE_KEY;
23
22
  private readonly DEFAULT_PENDING_REQUESTS_MAX_SIZE;
24
23
  private readonly MAX_STORAGE_SIZE;
24
+ private exposureObserver;
25
+ private exposureElementsMap;
25
26
  constructor();
26
27
  protected userInfo?: JsonProps;
27
28
  protected currentUrl: string;
@@ -34,11 +35,17 @@ declare class WebTracking extends Tools {
34
35
  */
35
36
  init: (initParams: InitParams) => void;
36
37
  /**
37
- * TODO: 需要判断有哪些不能被预制的参数
38
38
  * @description 预置参数
39
39
  * @param {object} PresetParams [预置参数]
40
40
  */
41
41
  preset: (presetParams: PresetParams) => void;
42
+ /**
43
+ * @description 验证配置参数
44
+ * @param key 参数名
45
+ * @param value 参数值
46
+ * @returns 验证结果
47
+ */
48
+ private validateConfigParam;
42
49
  /**
43
50
  * 用户登录
44
51
  */
@@ -76,6 +83,26 @@ declare class WebTracking extends Tools {
76
83
  * @description 清空批量队列(包括 LocalStorage 中的数据)
77
84
  */
78
85
  clearBatchQueue: () => void;
86
+ /**
87
+ * @description 从 LocalStorage 获取批量队列
88
+ * @returns 批量队列数组
89
+ */
90
+ private getBatchQueueFromStorage;
91
+ /**
92
+ * @description 保存批量队列到 LocalStorage
93
+ * @param queue 批量队列数组
94
+ */
95
+ private saveBatchQueueToStorage;
96
+ /**
97
+ * @description 从 LocalStorage 获取待发送请求队列
98
+ * @returns 待发送请求队列数组
99
+ */
100
+ private getPendingRequestsFromStorage;
101
+ /**
102
+ * @description 保存待发送请求队列到 LocalStorage
103
+ * @param requests 待发送请求队列数组
104
+ */
105
+ private savePendingRequestsToStorage;
79
106
  /**
80
107
  * @description 设置自定义页面唯一标识
81
108
  * @param pageKey 页面唯一标识,如果传入 null 或空字符串,则恢复自动生成
@@ -87,7 +114,7 @@ declare class WebTracking extends Tools {
87
114
  * @returns 当前页面唯一标识
88
115
  */
89
116
  getPageKey: () => string;
90
- protected onClickCallback: (e: MouseEvent) => Promise<TrackingResponse>;
117
+ protected onClickCallback: (e: MouseEvent) => void;
91
118
  /**
92
119
  * @description 添加单页面监听事件
93
120
  * @param callback
@@ -112,6 +139,11 @@ declare class WebTracking extends Tools {
112
139
  * @param data 批量数据
113
140
  */
114
141
  private sendBatchData;
142
+ /**
143
+ * @description 批量数据重试逻辑
144
+ * @param data 批量数据
145
+ */
146
+ private retryBatchData;
115
147
  /**
116
148
  * 添加到批量队列
117
149
  * @param params 数据参数
@@ -145,17 +177,14 @@ declare class WebTracking extends Tools {
145
177
  private sendWithBeacon;
146
178
  /**
147
179
  * 刷新待发送的单个请求(正常情况下的发送)
148
- * 注意:这个方法会直接发送,不会再次添加到 pendingRequests,避免循环
180
+ * 注意:这个方法会直接使用 ajax 发送,避免通过 sendData 导致重复
149
181
  */
150
182
  private flushPendingRequests;
151
- /**
152
- * 保存批量队列到 LocalStorage
153
- */
154
- private saveBatchQueueToStorage;
155
183
  /**
156
184
  * 设置页面卸载监听器,确保数据发送
157
185
  */
158
186
  private setupBeforeUnloadListener;
187
+ private isFlushingPendingData;
159
188
  /**
160
189
  * 刷新待发送数据(在页面卸载/跳转时调用)
161
190
  */
@@ -164,17 +193,64 @@ declare class WebTracking extends Tools {
164
193
  * 发送数据通用函数
165
194
  */
166
195
  sendData: (params: TrackingPostParams, header?: JsonProps) => Promise<TrackingResponse>;
196
+ /**
197
+ * @description 判断是否应该使用 sendBeacon
198
+ * @param sendMethod 配置的发送方式
199
+ * @param header 自定义 header
200
+ * @param initHeader 初始化配置的 header
201
+ * @returns 是否使用 sendBeacon
202
+ */
203
+ private shouldUseBeacon;
167
204
  /**
168
205
  * @description 留存时长上报
169
206
  * @param type
170
207
  */
171
208
  sendRetained: (type: string) => void;
209
+ /**
210
+ * @description 用户主动上报页面停留时长
211
+ * @param duration 自定义停留时长(毫秒),如果不传则自动计算从页面加载(或上次调用)到当前的时长
212
+ * @param options 可选参数,包括自定义描述、业务参数等
213
+ * @param resetStartTime 是否重置起始时间,默认 true(手动上报后重置,定时上报不重置)
214
+ * @returns Promise<TrackingResponse> 上报结果
215
+ */
216
+ trackPageDuration: (duration?: number, options?: TrackPageDurationOptions, resetStartTime?: boolean) => Promise<TrackingResponse>;
217
+ /**
218
+ * @description 启动定时上报页面停留时长的定时器
219
+ */
220
+ private startPageDurationTimer;
221
+ /**
222
+ * @description 停止定时上报页面停留时长的定时器
223
+ */
224
+ private stopPageDurationTimer;
172
225
  /**
173
226
  * @description 获取 itemKey
174
227
  * @param {[string]} partkey [控件/自定义事件的唯一标识]
175
228
  * @return {[string]}
176
229
  */
177
230
  protected getItemKey: (partkey?: string | number, pageKey?: string | number) => string;
231
+ /**
232
+ * @description 从元素或其祖先节点提取 data-* 属性
233
+ * @param element 目标元素
234
+ * @returns 提取的业务参数对象
235
+ */
236
+ protected extractDataAttributes: (element: HTMLElement) => JsonProps;
237
+ /**
238
+ * @description 初始化曝光监听
239
+ */
240
+ private initExposureObserver;
241
+ /**
242
+ * @description 监听页面上的曝光元素
243
+ */
244
+ private observeExposureElements;
245
+ /**
246
+ * @description 上报曝光事件
247
+ * @param element 曝光元素
248
+ */
249
+ private reportExposure;
250
+ /**
251
+ * @description 停止曝光监听
252
+ */
253
+ private stopExposureObserver;
178
254
  }
179
255
  declare const _default: WebTracking;
180
256
  export default _default;
@@ -162,11 +162,13 @@ export default class WebTrackingTools {
162
162
  private getWebGLFingerprint;
163
163
  /**
164
164
  * 获取Canvas指纹
165
+ * 注意:使用固定的尺寸和绘制参数,确保在不同时间生成一致的指纹
165
166
  * @returns Canvas指纹字符串
166
167
  */
167
168
  private getCanvasFingerprint;
168
169
  /**
169
170
  * 获取音频上下文指纹
171
+ * 注意:只使用稳定的 sampleRate,不使用 currentTime(会随时间变化)
170
172
  * @returns 音频指纹字符串
171
173
  */
172
174
  private getAudioFingerprint;
@@ -33,7 +33,7 @@ export declare type JsonValue = string | number | boolean | null | undefined | J
33
33
  /**
34
34
  * @description 事件类型
35
35
  */
36
- export declare type EventTypes = "PageView" | "PageRetained" | "CustomTrack" | "WebClick";
36
+ export declare type EventTypes = "PageView" | "PageRetained" | "CustomTrack" | "WebClick" | "WebExposure";
37
37
  export interface PresetParams {
38
38
  /**
39
39
  * @description 应用唯一标识(由接口生成)
@@ -117,11 +117,46 @@ export interface PresetParams {
117
117
  * @default 50
118
118
  */
119
119
  pendingRequestsMaxSize?: number;
120
+ /**
121
+ * @description 数据发送方式:auto(自动选择)、xhr(XMLHttpRequest)、beacon(sendBeacon)
122
+ * @default "auto"
123
+ */
124
+ sendMethod?: "auto" | "xhr" | "beacon";
120
125
  /**
121
126
  * @description 自定义页面唯一标识,如果不传则自动从路由获取
122
127
  * @default 自动从 window.location.pathname 获取
123
128
  */
124
129
  pageKey?: string;
130
+ /**
131
+ * @description 是否定时上报页面停留时长
132
+ * @default false
133
+ */
134
+ autoTrackPageDurationInterval?: boolean;
135
+ /**
136
+ * @description 定时上报页面停留时长的间隔时间(毫秒)
137
+ * @default 30000 (30秒)
138
+ */
139
+ pageDurationInterval?: number;
140
+ /**
141
+ * @description 是否启用曝光埋点
142
+ * @default false
143
+ */
144
+ autoTrackExposure?: boolean;
145
+ /**
146
+ * @description 曝光进入可视区判定阈值(0-1之间)
147
+ * @default 0.5
148
+ */
149
+ exposureThreshold?: number;
150
+ /**
151
+ * @description 曝光可见停留时长阈值(毫秒)
152
+ * @default 500
153
+ */
154
+ exposureTime?: number;
155
+ /**
156
+ * @description 同一元素允许上报的最大曝光次数
157
+ * @default 不限制
158
+ */
159
+ exposureNum?: number;
125
160
  }
126
161
  export interface InitParams extends PresetParams {
127
162
  /**
@@ -179,6 +214,30 @@ export interface TrackParams {
179
214
  */
180
215
  header?: JsonProps;
181
216
  }
217
+ /**
218
+ * @description 页面停留时长上报参数
219
+ */
220
+ export interface TrackPageDurationOptions {
221
+ /**
222
+ * @description 自定义描述
223
+ * @default "Web 页面浏览时长"
224
+ */
225
+ desc?: string;
226
+ /**
227
+ * @description 自定义业务参数
228
+ * @default {}
229
+ */
230
+ business?: JsonProps;
231
+ /**
232
+ * @description 自定义页面唯一标识
233
+ */
234
+ pageKey?: string;
235
+ /**
236
+ * @description 请求头
237
+ * @default {}
238
+ */
239
+ header?: JsonProps;
240
+ }
182
241
  export interface TargetEleProps {
183
242
  /**
184
243
  * @description dom节点名称
@@ -287,6 +346,14 @@ export interface TrackingPostParams {
287
346
  * @description 私有参数
288
347
  */
289
348
  privateParamMap?: PrivateParamProps;
349
+ /**
350
+ * @description 重试次数(内部使用)
351
+ */
352
+ _retryCount?: number;
353
+ /**
354
+ * @description 下次重试时间戳(内部使用)
355
+ */
356
+ _nextRetryTime?: number;
290
357
  }
291
358
  /**
292
359
  * @description 获取参数选项接口
@@ -487,3 +554,28 @@ export interface DeviceFingerprint {
487
554
  */
488
555
  connection?: string | NetworkConnection;
489
556
  }
557
+ /**
558
+ * @description 曝光元素信息
559
+ */
560
+ export interface ExposureElementInfo {
561
+ /**
562
+ * @description 元素 DOM 节点
563
+ */
564
+ element: HTMLElement;
565
+ /**
566
+ * @description 元素可见开始时间戳
567
+ */
568
+ visibleStartTime: number;
569
+ /**
570
+ * @description 元素曝光次数
571
+ */
572
+ exposureCount: number;
573
+ /**
574
+ * @description 元素是否在可视区
575
+ */
576
+ isVisible: boolean;
577
+ /**
578
+ * @description 曝光定时器
579
+ */
580
+ exposureTimer: number | null;
581
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fle-sdk/event-tracking-web",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "event tracking in web",
5
5
  "author": "飞象前端团队",
6
6
  "license": "ISC",
@@ -37,10 +37,10 @@
37
37
  "@rollup/plugin-babel": "^5.3.0",
38
38
  "@rollup/plugin-commonjs": "^19.0.0",
39
39
  "@rollup/plugin-node-resolve": "^13.0.0",
40
+ "@rollup/plugin-typescript": "^11.1.6",
40
41
  "@snowpack/plugin-dotenv": "^2.1.0",
41
42
  "@snowpack/plugin-postcss": "^1.4.1",
42
43
  "@snowpack/plugin-react-refresh": "^2.5.0",
43
- "@snowpack/web-test-runner-plugin": "^0.2.2",
44
44
  "@types/react": "^17.0.0",
45
45
  "@types/react-dom": "^17.0.0",
46
46
  "@types/react-router-dom": "^5.3.3",
@@ -56,7 +56,6 @@
56
56
  "rollup-plugin-node-polyfills": "^0.2.1",
57
57
  "rollup-plugin-sourcemaps": "^0.6.3",
58
58
  "rollup-plugin-terser": "^7.0.2",
59
- "@rollup/plugin-typescript": "^11.1.6",
60
59
  "snowpack": "^3.3.7",
61
60
  "snowpack-plugin-less": "^1.0.7",
62
61
  "typescript": "^4.3.4"