import { ENVIRONMENTS } from '@/common/js/BaseDictionary'; import sensors from '@/lib/Sensorsdata-UniPlugin-JS'; import Vue from 'vue'; import uni from '@/utils/uniHooks'; import store from '@/store/index' import { getPlatform } from '@/utils/index'; /** * 上传埋点数据至神策(第三方埋点平台) * param eventName string 埋点事件名 * param properites object 埋点数据 (包含action, current event duration) * param eventEnable boolean 是否允许上传埋点数据,默认为true * param owner string 埋点负责人,默认为undefined * */ const normalTrack = (eventName, properites, trackingEnable = true) => { if (trackingEnable) sensors.track(eventName, properites); } // 设置全埋点事件及埋点公共字段(仅在小程序中实现,H5另定) const trackingInit = () => { const platform = getPlatform(); if ( platform !== 'miniprogram') { return } // console.log(23, window.toWXSendMsg); // console.log(23, store.state.appId); // 微信小程序 if (getPlatform() === 'miniprogram') { // window.toWXSendMsg({ // type: 'scanQRCode', // }); // window.subscribe('scanQRCodeOver', (options) => { // console.log('微信扫码结束之后的返回参数', options); // runScanFn(options); // }); } if (store.state.appId === '') { // window.toWXSendMsg = } return const project = 'kerryplus'; const defaultLbs = uni.getStorageSync("DEFAULT_LBS"); const lbsId = defaultLbs.lbs?.id; const lbsName = defaultLbs.lbs?.name; const brandId = defaultLbs.lbs?.brand.id; const brandName = defaultLbs.lbs?.brand.name; const openId = uni.getStorageSync("OPENID"); const profileId = uni.getStorageSync("PROFILE_ID"); //设置全埋点事件和其他参数 sensors.setPara({ name: 'sensors', server_url: `${environment.trackingBaseUrl}?project=${project}&remark=${environment.trackingRemarkPre}_${lbsId}`, //全埋点控制开关 autoTrack: { // $MPClick小程序元素点击,当 Page 中定义的事件处理函数被触发时采集。 // 目前只支持 tap、longtap、longpress 三类事件 mpClick: true, // $MPLaunch小程序初始化完成时触发或者小程序进入后台一定时间后被微信杀死进程后再次启动小程序时触发 appLaunch: true, // $MPShow小程序显示,小程序启动时触发或者从后台切换到前台时触发 appShow: true, // $MPHide小程序从前台进入后台 appHide: true, // $MPViewScreen小程序页面浏览,打开一个小程序页面时触发 pageShow: true, // $MPShare小程序分享,设置 Page.onShareAppMessage 这个函数后,点击小程序右上角三个点, // 然后点击”发送给朋友“触发上报 pageShare: true, // $MPPageLeave 预置事件中会采集 event_duration 预置属性来记录页面浏览时长,单位为秒 pageLeave: true, // $MPAddFavorites小程序收藏,在微信中,仅 Android 手机有”收藏“功能,所以只有 Android 手机支持此事件 // page.onAddToFavorites mpFavorite: true, //默认为true }, //自定义渠道追踪参数,如source_channel:['custom_param'] source_channel: ['tpName'], //这里增加一个tpName。用来给tpName走UTM逻辑 //是否允许控制台打印查看埋点数据(建议打开) show_log: false, //是否允许修改onShareAppMessage里return的path,用来增加(登录ID,分享层级,当前的path), //在app onShow中自动获取这些参数来查看具体分享来源、层级等 allow_amend_share_path: true, //是否允许批量发送 batch_send: false, app_flush_interval: 15000, //设置两次数据发送的最小时间间隔 @Platform Android&iOS app_flush_bulkSize: 100, //设置本地缓存日志的最大条目数,最小 50 条 @Platform Android&iOS app_flush_network_policy: 30, //设置 flush 时网络发送策略,默认 3G、4G、WI-FI 环境下都会尝试 flush @Platform Android&iOS app_session_interval_time: 30000, //Session 时长,若 App 在后台超过设定事件,则认为当前 Session 结束,发送 $AppEnd 事件,单位毫秒 @Platform Andorid app_data_collect: true }); //对于所有事件都需要添加的属性,可在初始化 SDK 前,调用 registerApp() 将属性注册为公共属性 sensors.register({ saglobal_product_name: project + '_c', saglobal_digital_brand_id: brandId, saglobal_digital_brand_name: brandName, saglobal_lbs_id: lbsId, saglobal_lbs_name: lbsName, saglobal_open_id: openId, saglobal_profile_id: profileId }); sensors.registerApp({ saglobal_product_name: project, //小程序的brand saglobal_digital_brand_id: uni.getStorageSync('groupId') || '', //小程序的LBS ID saglobal_lbs_id: uni.getStorageSync('mallid') || '', // 小程序的LBS Name saglobal_lbs_name: _this.globalData.marketName || '', }) //埋点初始化 sensors.init(); } class TrackFactory { /** * 埋点数据初始化 * param eventName string 埋点事件名 * param eventData object 埋点数据 * param isUpload boolean 是否允许上传埋点数据,默认为true * param owner string 埋点负责人,默认为undefined * */ constructor(eventName, eventData, isUpload = true, owner = 'undefined') { this.eventData = {}; this.isUpload = true; this.eventName = ''; this.timeStart = new Date().getTime(); this.apiTimeStart = new Date().getTime(); this.instanceRecorder = {}; eventData = eventData || {}; eventData['owner'] = owner; this.isUpload = isUpload; this.eventName = eventName; this.eventData = eventData; // 记录页面展示action this.track(1); } /** * 获取埋点事件实例 * param eventName string 埋点事件名 * param eventData object 埋点数据 * param isForce boolean 是否强制实例化 * param isUpload boolean 是否允许上传埋点数据,默认为true * param owner string 埋点负责人,默认为undefined * * return object * */ static getInstance(eventName, eventData, isForce, isUpload, owner) { // 判断埋点事件名是否被注册,利用instanceRecorder记录被注册埋点事件实例 // 如果已经实例化过,就直接返回实例,无需再new // 如果要强制实例化,可以把forceInit设为true if (!this.instanceRecorder.hasOwnProperty(eventName) || isForce) { eventData = eventData || {}; this.instanceRecorder[eventName] = new TrackFactory(eventName, eventData, isUpload, owner); } return this.instanceRecorder[eventName]; } /** * 销毁埋点事件实例 * param eventName string 埋点事件名 * */ static destory(eventName) { delete this.instanceRecorder[eventName]; } /** * 记录埋点的action * param action number action code * param onceData object 针对指定action的埋点数据,具体见埋点需求 * */ track(action, onceData = {}) { if (action == 100 || action == 600) { this.apiTimeStart = new Date().getTime(); this.eventData['user_mainstory_timecost'] = new Date().getTime() - this.timeStart; } const trackData = { ...this.eventData, ...onceData }; trackData['action'] = action; trackData['current_event_duration'] = new Date().getTime() - this.timeStart; if (action == 200 || action == 400 || action == 700 || action == 800) trackData['api_timecost'] = new Date().getTime() - this.apiTimeStart; if (this.isUpload) { normalTrack(this.eventName, trackData); } } } /** * 创建并返回一个 IntersectionObserver 对象实例。 * 该实例会观测 option.selector 节点。 * 当节点在 viewport 的观测区域停留 option.delayInSecond 秒, * 就认为该节点已曝光,会触发 visibilityCb。 * * 注意: * 1. 节点多次曝光会触发多次 visibilityCb * 2. 待观测的 option.selector 节点必须有唯一的 id * 3. 调用该方法时,待观测的节点必须在已经在页面上渲染完成。一般在 onReady / mounted 方法中调用。 * 4. 在 onUnload / beforeDestroy 需要执行 observer.disconnect() 来释放资源。 * 5. observer 不能作为 vue 实例的响应式数据。 * * https://uniapp.dcloud.net.cn/api/ui/intersection-observer.html#createintersectionobserver * * @param elContainer 自定义组件实例,一般传入 this * @param visibilityCb 回调函数 * @param option * @returns IntersectionObserver 对象实例。 */ const getVisibilityObserver = ( elContainer, visibilityCb, option) => { const opt = Object.assign({}, { selector: '.watch-me', threshold: 0.5, delayInSecond: 1, margin: { bottom: 0, } }, option ? option : {}); let timer = 0; const inMap = {}; const outMap = {}; const delay = opt.delayInSecond * 1000; const observer = uni.createIntersectionObserver(elContainer, { observeAll: true, thresholds: [opt.threshold], initialRatio: opt.threshold }); observer.relativeToViewport(opt.margin).observe(opt.selector, (res) => { // eslint-disable-next-line no-console // console.log(res); // res 身上除了 UniApp.ObserveResult 中列明的属性外 // 还有两个属性: // - id:string,节点的 id // - dataset:object,存放节点上面的 data-* 数据 // 所以我们可以用 id 来做 inMap 和 outMap 的 key。 const key = res.id; // 进入 viewpoint if (res.intersectionRatio > opt.threshold) { inMap[key] = res; if (outMap[key]) { delete outMap[key]; } } else { // 离开 viewpoint outMap[key] = res; if (inMap[key]) { // 计算停留时间 if (outMap[key].time - inMap[key].time >= delay) { visibilityCb(key, outMap[key]); delete outMap[key]; } delete inMap[key]; } } // 处理那些一直停留在 viewpoint 内的节点 if (timer) { clearTimeout(timer); } timer = setTimeout(() => { Object.keys(inMap).forEach(id => { visibilityCb(id, inMap[id]); delete inMap[id]; }) }, delay); }); return observer; } // export { // trackingInit, // TrackFactory, // getVisibilityObserver // } export default () => { // console.log('ENVIRONMENTS', ENVIRONMENTS[window.env]); // console.log('ENVIRONMENTS', sensors); // 埋点参数设置及公共字段初始化 trackingInit(); Vue.prototype.$trackFactory = TrackFactory; }