From 993fd827d4f0371b39aca158eb7e51dfa6a701da Mon Sep 17 00:00:00 2001 From: mehaotian <490272692@qq.com> Date: Tue, 20 Aug 2019 13:49:42 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20uni=20=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/uni-stat/LICENSE | 202 +++++++++++ packages/uni-stat/package.json | 32 ++ packages/uni-stat/src/config.js | 10 + packages/uni-stat/src/index.js | 45 +++ packages/uni-stat/src/parameter.js | 295 +++++++++++++++++ packages/uni-stat/src/stat.js | 515 +++++++++++++++++++++++++++++ 6 files changed, 1099 insertions(+) create mode 100644 packages/uni-stat/LICENSE create mode 100644 packages/uni-stat/package.json create mode 100644 packages/uni-stat/src/config.js create mode 100644 packages/uni-stat/src/index.js create mode 100644 packages/uni-stat/src/parameter.js create mode 100644 packages/uni-stat/src/stat.js diff --git a/packages/uni-stat/LICENSE b/packages/uni-stat/LICENSE new file mode 100644 index 000000000..7a4a3ea24 --- /dev/null +++ b/packages/uni-stat/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/packages/uni-stat/package.json b/packages/uni-stat/package.json new file mode 100644 index 000000000..8033b635f --- /dev/null +++ b/packages/uni-stat/package.json @@ -0,0 +1,32 @@ +{ + "name": "@dcloudio/uni-stat", + "version": "0.0.105", + "description": "", + "main": "dist/index.js", + "scripts": { + "dev": "NODE_ENV=development rollup -w -c rollup.config.js", + "build": "NODE_ENV=production rollup -c rollup.config.js" + }, + "files": [ + "dist", + "package.json", + "LICENSE" + ], + "author": "", + "license": "Apache-2.0", + "devDependencies": { + "@babel/core": "^7.5.5", + "@babel/preset-env": "^7.5.5", + "eslint": "^6.1.0", + "rollup": "^1.19.3", + "rollup-plugin-babel": "^4.3.3", + "rollup-plugin-clear": "^2.0.7", + "rollup-plugin-commonjs": "^10.0.2", + "rollup-plugin-copy": "^3.1.0", + "rollup-plugin-eslint": "^7.0.0", + "rollup-plugin-json": "^4.0.0", + "rollup-plugin-node-resolve": "^5.2.0", + "rollup-plugin-replace": "^2.2.0", + "rollup-plugin-uglify": "^6.0.2" + } +} diff --git a/packages/uni-stat/src/config.js b/packages/uni-stat/src/config.js new file mode 100644 index 000000000..b3204423c --- /dev/null +++ b/packages/uni-stat/src/config.js @@ -0,0 +1,10 @@ +import { + version +} from '../package.json' +export const STAT_VERSION = version +export const STAT_URL = 'https://tongji.dcloud.net.cn/uni/stat' +export const STAT_H5_URL = 'https://tongji.dcloud.net.cn/uni/stat.gif' +export const STAT_KEY = 'qkTHEIegZGcL5iy3' +export const PAGE_PVER_TIME = 1800 +export const APP_PVER_TIME = 300 +export const OPERATING_TIME = 10 diff --git a/packages/uni-stat/src/index.js b/packages/uni-stat/src/index.js new file mode 100644 index 000000000..72e2100a6 --- /dev/null +++ b/packages/uni-stat/src/index.js @@ -0,0 +1,45 @@ +import Stat from './stat.js'; +const stat = Stat.getInstance(); +let isHide = false +const lifecycle = { + onLaunch(options) { + stat.report(options, this); + }, + onReady() { + stat.ready(this); + }, + onLoad(options) { + stat.load(options, this); + }, + onShow() { + isHide = false + stat.show(this); + }, + onHide() { + isHide = true + stat.hide(this); + }, + onUnload() { + if (isHide) { + isHide = false + return + } + stat.hide(this); + }, + onError(e) { + stat.error(e) + }, + onShareAppMessage() { + stat.interceptShare(false) + } +} + +function main() { + const Vue = require('vue'); + (Vue.default || Vue).mixin(lifecycle); + uni.report = function(type, options) { + stat.sendEvent(type, options); + }; +} + +main(); diff --git a/packages/uni-stat/src/parameter.js b/packages/uni-stat/src/parameter.js new file mode 100644 index 000000000..c443d2440 --- /dev/null +++ b/packages/uni-stat/src/parameter.js @@ -0,0 +1,295 @@ +import { + PAGE_PVER_TIME, + APP_PVER_TIME +} from './config'; + +const UUID_KEY = '__DC_STAT_UUID'; +const UUID_VALUE = '__DC_UUID_VALUE'; + +export function getUuid() { + let uuid = ''; + if (getPlatformName() === 'n') { + try { + uuid = plus.runtime.getDCloudId() + } catch (e) { + uuid = ''; + } + uni.setStorageSync(UUID_KEY, uuid); + return uuid + } + + try { + uuid = uni.getStorageSync(UUID_KEY); + } catch (e) { + uuid = UUID_VALUE; + } + + if (!uuid) { + uuid = Date.now() + '' + Math.floor(Math.random() * 1e7); + try { + uni.setStorageSync(UUID_KEY, uuid); + } catch (e) { + uni.setStorageSync(UUID_KEY, UUID_VALUE); + } + } + return uuid; +} + +export const getSgin = (statData) => { + let arr = Object.keys(statData) + let sortArr = arr.sort(); + let sgin = {}; + let sginStr = '' + for (var i in sortArr) { + sgin[sortArr[i]] = statData[sortArr[i]]; + sginStr += sortArr[i] + '=' + statData[sortArr[i]] + '&' + } + // const options = sginStr.substr(0, sginStr.length - 1) + // sginStr = sginStr.substr(0, sginStr.length - 1) + '&key=' + STAT_KEY; + // const si = crypto.createHash('md5').update(sginStr).digest('hex'); + return { + sign: '', + options: sginStr.substr(0, sginStr.length - 1) + }; +} + +export const getSplicing = (data) => { + let str = '' + for (var i in data) { + str += i + '=' + data[i] + '&' + } + return str.substr(0, str.length - 1) +} + +export const getTime = () => { + return parseInt(new Date().getTime() / 1000); +} + +export const getPlatformName = () => { + const platformList = { + 'app-plus': 'n', + 'h5': 'h5', + 'mp-weixin': 'wx', + 'mp-alipay': 'ali', + 'mp-baidu': 'bd', + 'mp-toutiao': 'tt', + 'mp-qq': 'qq' + } + return platformList[process.env.VUE_APP_PLATFORM]; +} + +export const getPackName = () => { + let packName = '' + if (getPlatformName() === 'wx' || getPlatformName() === 'qq') { + packName = uni.getAccountInfoSync().miniProgram.appId || '' + } + return packName +} + +export const getVersion = () => { + return getPlatformName() === 'n' ? plus.runtime.version : ''; +} + +export const getChannel = () => { + const platformName = getPlatformName(); + let channel = ''; + if (platformName === 'n') { + channel = plus.runtime.channel; + } + if (platformName === 'wx') { + // TODO; + } + return channel; +} + +export const getScene = (options) => { + const platformName = getPlatformName(); + let scene = ''; + if (options) { + return options; + } + if (platformName === 'wx') { + scene = uni.getLaunchOptionsSync().scene; + } + return scene; +} +const First__Visit__Time__KEY = 'First__Visit__Time' +const Last__Visit__Time__KEY = 'Last__Visit__Time' + +export const getFirstVisitTime = () => { + const timeStorge = uni.getStorageSync(First__Visit__Time__KEY); + let time = 0; + if (timeStorge) { + time = timeStorge; + } else { + time = getTime(); + uni.setStorageSync(First__Visit__Time__KEY, time); + uni.removeStorageSync(Last__Visit__Time__KEY); + } + return time; +} + +export const getLastVisitTime = () => { + const timeStorge = uni.getStorageSync(Last__Visit__Time__KEY); + let time = 0; + if (timeStorge) { + time = timeStorge; + } else { + time = ''; + } + uni.setStorageSync(Last__Visit__Time__KEY, getTime()); + return time; +} + + +const PAGE_RESIDENCE_TIME = '__page__residence__time' +let First_Page_residence_time = 0; +let Last_Page_residence_time = 0; + + +export const setPageResidenceTime = () => { + First_Page_residence_time = getTime() + if (getPlatformName() === 'n') { + uni.setStorageSync(PAGE_RESIDENCE_TIME, getTime()); + } + return First_Page_residence_time +} + +export const getPageResidenceTime = () => { + Last_Page_residence_time = getTime() + if (getPlatformName() === 'n') { + First_Page_residence_time = uni.getStorageSync(PAGE_RESIDENCE_TIME); + } + return Last_Page_residence_time - First_Page_residence_time +} +const TOTAL__VISIT__COUNT = 'Total__Visit__Count' +export const getTotalVisitCount = () => { + const timeStorge = uni.getStorageSync(TOTAL__VISIT__COUNT); + let count = 1; + if (timeStorge) { + count = timeStorge; + count++ + } + uni.setStorageSync(TOTAL__VISIT__COUNT, count); + return count; +} + +export const GetEncodeURIComponentOptions = (statData) => { + let data = {}; + for (let prop in statData) { + data[prop] = encodeURIComponent(statData[prop]); + } + return data; +} + +let Set__First__Time = 0; +let Set__Last__Time = 0; + +export const getFirstTime = () => { + let time = new Date().getTime(); + Set__First__Time = time; + Set__Last__Time = 0; + return time; +} + + +export const getLastTime = () => { + let time = new Date().getTime(); + Set__Last__Time = time; + return time; +} + + +export const getResidenceTime = (type) => { + let residenceTime = 0; + if (Set__First__Time !== 0) { + residenceTime = Set__Last__Time - Set__First__Time + } + + residenceTime = parseInt(residenceTime / 1000); + residenceTime = residenceTime < 1 ? 1 : residenceTime; + if (type === 'app') { + let overtime = residenceTime > APP_PVER_TIME ? true : false + return { + residenceTime, + overtime + }; + } + if (type === 'page') { + let overtime = residenceTime > PAGE_PVER_TIME ? true : false + return { + residenceTime, + overtime + }; + } + + return { + residenceTime + }; + +} + +export const getRoute = () => { + var pages = getCurrentPages(); + var page = pages[pages.length - 1]; + let _self = page.$vm + + if (getPlatformName() === 'bd') { + return _self.$mp && _self.$mp.page.is; + } else { + return _self.$scope && _self.$scope.route || _self.$mp && _self.$mp.page.route; + } +}; + +export const getPageRoute = (self) => { + var pages = getCurrentPages(); + var page = pages[pages.length - 1]; + let _self = page.$vm + let query = self._query; + let str = query && JSON.stringify(query) !== '{}' ? '?' + JSON.stringify(query) : ''; + // clear + self._query = ''; + if (getPlatformName() === 'bd') { + return _self.$mp && _self.$mp.page.is + str; + } else { + return _self.$scope && _self.$scope.route + str || _self.$mp && _self.$mp.page.route + str; + } +}; + +export const getPageTypes = (self) => { + if (self.mpType === 'page' || self.$mp && self.$mp.mpType === 'page') { + return true; + } + return false; +} + +export const calibration = (eventName, options) => { + // login 、 share 、pay_success 、pay_fail 、register 、title + if(!eventName){ + console.error(`uni.report 缺少 [eventName] 参数`); + return true + } + if (typeof eventName !== 'string') { + console.error(`uni.report [eventName] 参数类型错误,只能为 String 类型`); + return true + } + if (eventName.length > 255) { + console.error(`uni.report [eventName] 参数长度不能大于 255`); + return true + } + + if (typeof options !== 'string' && typeof options !== 'object') { + console.error(`uni.report [options] 参数类型错误,只能为 String 或 Object 类型`); + return true + } + + if (typeof options === 'string' && options.length > 255) { + console.error(`uni.report [options] 参数长度不能大于 255`); + return true + } + + if (eventName === 'title' && typeof options !== 'string') { + console.error('uni.report [eventName] 参数为 title 时,[options] 参数只能为 String 类型'); + return true + } +} diff --git a/packages/uni-stat/src/stat.js b/packages/uni-stat/src/stat.js new file mode 100644 index 000000000..26e7724d8 --- /dev/null +++ b/packages/uni-stat/src/stat.js @@ -0,0 +1,515 @@ +const PagesJson = require('uni-pages?{"type":"style"}').default +const statConfig = require('uni-stat-config').default || require('uni-stat-config'); +import { + getUuid, + getSgin, + getSplicing, + getPackName, + getPlatformName, + getVersion, + getChannel, + getScene, + getTime, + getFirstVisitTime, + getLastVisitTime, + setPageResidenceTime, + getPageResidenceTime, + getTotalVisitCount, + GetEncodeURIComponentOptions, + getFirstTime, + getLastTime, + getResidenceTime, + getPageRoute, + getRoute, + getPageTypes, + calibration +} from './parameter'; + +import { + STAT_URL, + STAT_VERSION, + STAT_H5_URL, + OPERATING_TIME +} from './config'; + +const resultOptions = uni.getSystemInfoSync(); + +class Util { + constructor() { + this.self = ''; + this._retry = 0; + this._platform = ''; + this._query = {}; + this._navigationBarTitle = { + config: '', + page: '', + report: '', + lt: '' + } + this._operatingTime = 0; + this._reportingRequestData = { + '1': [], + '11': [] + }; + this.__prevent_triggering = false + + this.__licationHide = false; + this.__licationShow = false; + this._lastPageRoute = ''; + this.statData = { + uuid: getUuid(), + ut: getPlatformName(), + mpn: getPackName(), + ak: statConfig.appid, + usv: STAT_VERSION, + v: getVersion(), + ch: getChannel(), + cn: '', + pn: '', + ct: '', + t: getTime(), + tt: '', + p: resultOptions.platform === 'android' ? 'a' : 'i', + brand: resultOptions.brand || '', + md: resultOptions.model, + sv: resultOptions.system.replace(/(Android|iOS)\s/, ''), + mpsdk: resultOptions.SDKVersion || '', + mpv: resultOptions.version || '', + lang: resultOptions.language, + pr: resultOptions.pixelRatio, + ww: resultOptions.windowWidth, + wh: resultOptions.windowHeight, + sw: resultOptions.screenWidth, + sh: resultOptions.screenHeight + } + + } + + _applicationShow() { + if (this.__licationHide) { + getLastTime(); + const time = getResidenceTime('app'); + if (time.overtime) { + let options = { + path: this._lastPageRoute, + scene: this.statData.sc + } + this._sendReportRequest(options); + } + this.__licationHide = false; + } + } + + _applicationHide(self, type) { + + this.__licationHide = true; + getLastTime(); + const time = getResidenceTime(); + getFirstTime(); + this._sendHideRequest({ + urlref: this._lastPageRoute, + urlref_ts: time.residenceTime + }, type) + } + + _pageShow() { + const route = getPageRoute(this); + const routepath = getRoute(this); + this._navigationBarTitle.config = PagesJson && + PagesJson.pages[routepath] && + PagesJson.pages[routepath].titleNView && + PagesJson.pages[routepath].titleNView.titleText || + PagesJson && + PagesJson.pages[routepath] && + PagesJson.pages[routepath].navigationBarTitleText || ''; + + if (this.__licationShow) { + getFirstTime(); + this.__licationShow = false; + // console.log('这是 onLauch 之后执行的第一次 pageShow ,为下次记录时间做准备'); + this._lastPageRoute = route; + return; + } + + getLastTime(); + this._lastPageRoute = route + const time = getResidenceTime('page'); + if (time.overtime) { + let options = { + path: this._lastPageRoute, + scene: this.statData.sc + }; + this._sendReportRequest(options); + } + getFirstTime(); + } + + _pageHide() { + if (!this.__licationHide) { + getLastTime(); + const time = getResidenceTime('page'); + this._sendPageRequest({ + url: this._lastPageRoute, + urlref: this._lastPageRoute, + urlref_ts: time.residenceTime + }); + this._navigationBarTitle = { + config: '', + page: '', + report: '', + lt: '' + }; + return; + } + } + + _login() { + this._sendEventRequest({ + key: 'login' + }, 0) + } + + _share() { + this._sendEventRequest({ + key: 'share' + }, 0) + } + _payment(key) { + this._sendEventRequest({ + key + }, 0) + } + _sendReportRequest(options) { + this._navigationBarTitle.lt = '1'; + let query = options.query && JSON.stringify(options.query) !== '{}' ? '?' + JSON.stringify(options.query) : ''; + this.statData.lt = '1'; + this.statData.url = options.path + query; + this.statData.t = getTime(); + this.statData.sc = getScene(options.scene); + this.statData.fvts = getFirstVisitTime(); + this.statData.lvts = getLastVisitTime(); + this.statData.tvc = getTotalVisitCount(); + this.getNetworkInfo(); + } + + _sendPageRequest(opt) { + let { + url, + urlref, + urlref_ts + } = opt; + this._navigationBarTitle.lt = '11'; + let options = { + ak: this.statData.ak, + uuid: this.statData.uuid, + lt: '11', + ut: this.statData.ut, + url, + tt: this.statData.tt, + urlref, + urlref_ts, + ch: this.statData.ch, + usv: this.statData.usv, + t: getTime(), + p: this.statData.p + } + this.request(options); + } + + _sendHideRequest(opt, type) { + let { + urlref, + urlref_ts + } = opt; + let options = { + ak: this.statData.ak, + uuid: this.statData.uuid, + lt: '3', + ut: this.statData.ut, + urlref, + urlref_ts, + ch: this.statData.ch, + usv: this.statData.usv, + t: getTime(), + p: this.statData.p + } + this.request(options, type) + } + _sendEventRequest({ + key = '', + value = "" + } = {}) { + const route = getPageRoute(this); + let options = { + ak: this.statData.ak, + uuid: this.statData.uuid, + lt: '21', + ut: this.statData.ut, + url: route, + ch: this.statData.ch, + e_n: key, + e_v: typeof(value) === 'object' ? JSON.stringify(value) : value.toString(), + usv: this.statData.usv, + t: getTime(), + p: this.statData.p + } + this.request(options); + } + + getNetworkInfo() { + uni.getNetworkType({ + success: (result) => { + this.statData.net = result.networkType; + this.getLocation(); + } + }); + } + + getLocation() { + if (statConfig.getLocation) { + uni.getLocation({ + type: 'wgs84', + geocode: true, + success: (result) => { + if (result.address) { + this.statData.cn = result.address.country; + this.statData.pn = result.address.province; + this.statData.ct = result.address.city; + } + + this.statData.lat = result.latitude; + this.statData.lng = result.longitude; + this.request(this.statData); + } + }); + } else { + this.statData.lat = 0; + this.statData.lng = 0; + this.request(this.statData); + } + } + + request(data, type) { + let time = getTime(); + const title = this._navigationBarTitle; + data.ttn = title.page; + data.ttpj = title.config; + data.ttc = title.report; + + let requestData = this._reportingRequestData; + if (!requestData[data.lt]) { + this._reportingRequestData[data.lt] = []; + } + this._reportingRequestData[data.lt].push(data); + if (getPageResidenceTime() < OPERATING_TIME && !type) { + return + } + // 时间超过,重新获取时间戳 + setPageResidenceTime(); + let firstArr = [] + let contentArr = [] + let lastArr = [] + for (let i in this._reportingRequestData) { + const rd = this._reportingRequestData[i] + rd.forEach((elm) => { + const newData = getSplicing(elm) + if (i === 0) { + firstArr.push(newData) + } else if (i === 3) { + lastArr.push(newData) + } else { + contentArr.push(newData) + } + }) + } + + firstArr.push(...contentArr, ...lastArr) + let optionsData = { + usv: STAT_VERSION, //统计 SDK 版本号 + t: time, //发送请求时的时间戮 + requests: JSON.stringify(firstArr), + } + this._reportingRequestData = {} + + if (data.ut === 'h5') { + this.imageRequest(optionsData) + return + } + uni.request({ + url: STAT_URL, + method: 'POST', + data: optionsData, + success: () => { + if (process.env.NODE_ENV === 'development') { + console.log('stat request success'); + } + }, + fail: (e) => { + if (process.env.NODE_ENV === 'development') { + console.log('stat request fail', e); + } + if (++this._retry < 3) { + setTimeout(() => { + this.request(data); + }, 1000); + } + } + }); + } + /** + * h5 请求 + */ + imageRequest(data) { + let image = new Image(); + let options = getSgin(GetEncodeURIComponentOptions(data)).options; + image.src = STAT_H5_URL + '?' + options + } + + sendEvent(key, value) { + // 校验 type 参数 + if (calibration(key, value)) return + + if (key === 'title') { + this._navigationBarTitle.report = value; + return + } + this._sendEventRequest({ + key, + value: typeof(value) === 'object' ? JSON.stringify(value) : value + }, 1); + } +} + + +class Stat extends Util { + static getInstance() { + if (!this.instance) { + this.instance = new Stat(); + } + return this.instance; + } + constructor() { + super() + this.instance = null; + // 注册拦截器 + if (typeof uni.addInterceptor === 'function') { + this.addInterceptorInit(); + this.interceptLogin(); + this.interceptShare(true); + this.interceptRequestPayment(); + } + } + + addInterceptorInit() { + let self = this; + uni.addInterceptor('setNavigationBarTitle', { + invoke(args) { + self._navigationBarTitle.page = args.title + } + }) + } + + interceptLogin() { + let self = this; + uni.addInterceptor('login', { + complete() { + self._login(); + } + }) + } + + interceptShare(type) { + let self = this; + if (!type) { + self._share(); + return + } + uni.addInterceptor('share', { + success() { + self._share(); + }, + fail() { + self._share(); + } + }) + } + + interceptRequestPayment() { + let self = this; + uni.addInterceptor('requestPayment', { + success() { + self._payment('pay_success'); + }, + fail() { + self._payment('pay_fail'); + } + }) + } + + report(options, self) { + this.self = self; + if (process.env.NODE_ENV === 'development') { + console.log('report init'); + } + setPageResidenceTime() + this.__licationShow = true; + this._sendReportRequest(options, true); + } + + load(options, self) { + this.self = self; + this._query = options; + } + + show(self) { + this.self = self; + if (!getPageTypes(self)) { + this._applicationShow(self); + } + } + + ready(self) { + this.self = self; + if (getPageTypes(self)) { + this._pageShow(self); + } + } + hide(self) { + this.self = self; + if (getPageTypes(self)) { + this._pageHide(self); + } else { + this._applicationHide(self, true); + } + } + error(em) { + if (this._platform === 'devtools') { + if (process.env.NODE_ENV === 'development') { + console.info('当前运行环境为开发者工具,不上报数据。'); + } + // return; + } + let emVal = '' + if (!em.message) { + emVal = JSON.stringify(em) + } else { + emVal = em.stack + } + let options = { + ak: this.statData.ak, + uuid: this.statData.uuid, + lt: '31', + ut: this.statData.ut, + ch: this.statData.ch, + mpsdk: this.statData.mpsdk, + mpv: this.statData.mpv, + v: this.statData.v, + em: emVal, + usv: this.statData.usv, + t: getTime(), + p: this.statData.p + } + this.request(options); + } +} +export default Stat -- GitLab