提交 d299f87a 编写于 作者: M mehaotian

fix(stat): 修复 nvue 下 uni.preloadPage 页面报错的bug ,新增 uniCloud 统计

上级 ddfedb8f
module.exports = {
input: 'packages/uni-cloud-stat/src/index.js',
output: {
file: 'packages/uni-cloud-stat/dist/index.js',
format: 'es'
},
external: ['vue', '../package.json'],
plugins: []
}
module.exports = {
input: 'packages/uni-stat/src/index.js',
output: {
file: 'packages/uni-stat/dist/index.js',
format: 'es'
},
external: ['vue', '../package.json'],
plugins: []
}
module.exports = [
{
input: 'packages/uni-stat/src/index.js',
output: {
file: 'packages/uni-stat/dist/index.js',
format: 'es'
},
external: ['vue', '../package.json'],
plugins: []
},
{
input: 'packages/uni-cloud-stat/src/index.js',
output: {
file: 'packages/uni-cloud-stat/dist/index.js',
format: 'es'
},
external: ['vue', '../package.json'],
plugins: []
}
]
......@@ -26,7 +26,7 @@
"build:mp-weixin:wxs": "rollup -c build/rollup.config.wxs.js",
"build:quickapp-native": "cross-env NODE_ENV=development node build/build.qa.js && cross-env NODE_ENV=production node build/build.qa.js",
"build:runtime": "npm run lint && npm run build:mp-weixin && npm run build:mp-qq && npm run build:mp-alipay && npm run build:mp-baidu && npm run build:mp-toutiao && npm run build:mp-jd && npm run build:app-plus && npm run build:quickapp-webview && npm run build:quickapp-native && npm run build:mp-kuaishou && npm run build:mp-lark && npm run build:mp-jd",
"build:stat": "npm run lint && rollup -c build/rollup.config.stat.js",
"build:stat": "npm run lint && rollup -c build/rollup.config.stat.js",
"build:web-view": "rollup -c build/rollup.config.web-view.js",
"test:cli": "cross-env NODE_ENV=test jest",
"test:unit": "cross-env NODE_ENV=test UNI_PLATFORM=h5 mocha-webpack --require tests/unit/setup.js --webpack-config build/webpack.config.test.js tests/unit/**/*.spec.js",
......
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
此差异已折叠。
{
"name": "@dcloudio/uni-cloud-stat",
"version": "2.0.0-32920211029001",
"description": "",
"main": "dist/index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/dcloudio/uni-app.git",
"directory": "packages/uni-cloud-stat"
},
"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"
},
"gitHead": "9e2d0f8e244724fcd64880316c57d837d1778cf8"
}
// 访问开始即启动小程序,访问结束结分为:进入后台超过5min、在前台无任何操作超过30min、在新的来源打开小程序;
export const STAT_VERSION = '0.0.1'
export const STAT_URL = 'https://tongji.dcloud.io/uni/stat'
export const STAT_H5_URL = 'https://tongji.dcloud.io/uni/stat.gif'
export const STAT_KEY = 'qkTHEIegZGcL5iy3'
export const PAGE_PVER_TIME = 1800 // 页面在前台无操作结束访问时间 单位s
export const APP_PVER_TIME = 300 // 应用在后台结束访问时间 单位s
export const OPERATING_TIME = 10 // 数据上报时间 单位s
export const DIFF_TIME = 60 * 1000 * 60 * 24
export const DEBUG = true
let statConfig = require('uni-stat-config').default || require('uni-stat-config');
import {
get_time,
set_page_residence_time,
get_first_visit_time,
get_last_visit_time,
get_total_visit_count,
get_page_residence_time,
get_first_time,
get_last_time,
get_residence_time
} from '../utils/pageTime.js'
import {
get_uuid,
get_platform_name,
get_pack_name,
get_scene,
get_version,
get_channel,
get_splicing,
get_page_route,
get_route,
handle_data,
calibration,
get_page_name,
get_sgin,
get_encodeURIComponent_options
} from '../utils/pageInfo.js'
import {
sys
} from '../utils/util.js'
import {
STAT_VERSION,
OPERATING_TIME,
STAT_URL,
STAT_H5_URL,
DEBUG
} from '../config.js';
import {
dbSet,
dbGet,
dbRemove
} from '../utils/db.js'
// 统计数据默认值
let statData = {
uuid: get_uuid(), // 设备标识
ut: get_platform_name(), // 平台类型
mpn: get_pack_name(), // 原生平台包名、小程序 appid
ak: statConfig.appid, // uni-app 应用 Appid
usv: STAT_VERSION, // 统计 sdk 版本
v: get_version(), // 应用版本,仅app
ch: get_channel(), // 渠道信息
cn: '', // 国家
pn: '', // 省份
ct: '', // 城市
t: get_time(), // 上报数据时的时间戳
tt: '',
p: sys.platform === 'android' ? 'a' : 'i', // 手机系统
brand: sys.brand || '', // 手机品牌
md: sys.model, // 手机型号
sv: sys.system.replace(/(Android|iOS)\s/, ''), // 手机系统版本
mpsdk: sys.SDKVersion || '', // x程序 sdk version
mpv: sys.version || '', // 小程序平台版本 ,如微信、支付宝
lang: sys.language, // 语言
pr: sys.pixelRatio, // pixelRatio 设备像素比
ww: sys.windowWidth, // windowWidth 可使用窗口宽度
wh: sys.windowHeight, // windowHeight 可使用窗口高度
sw: sys.screenWidth, // screenWidth 屏幕宽度
sh: sys.screenHeight, // screenHeight 屏幕高度
}
export default class Report {
constructor() {
// 页面实例
this.self = ''
// 进入应用标识
this.__licationShow = false
// 离开应用标识
this.__licationHide = false
// 统计默认值
this.statData = statData
// 标题默认值
this._navigationBarTitle = {
config: '',
page: '',
report: '',
lt: '',
}
// 页面参数
this._query = {}
// 页面最后停留页面的 url
// this._lastPageRoute = ''
// 注册拦截器
let registerInterceptor = typeof uni.addInterceptor === 'function'
if (registerInterceptor) {
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')
},
})
}
_login() {
this.sendEventRequest({
key: 'login',
},
0
)
}
_share() {
this.sendEventRequest({
key: 'share',
}, 0)
}
_payment(key) {
this.sendEventRequest({
key,
}, 0)
}
/**
* 进入应用触发
*/
applicationShow() {
// 通过 __licationHide 判断保证是进入后台后在次进入应用,避免重复上报数据
if (this.__licationHide) {
get_last_time()
const time = get_residence_time('app')
// 需要判断进入后台是否超过时限 ,默认是 30min ,是的话需要执行进入应用的上报
if (time.overtime) {
let lastPageRoute = uni.getStorageSync('_STAT_LAST_PAGE_ROUTE')
let options = {
path: lastPageRoute,
scene: this.statData.sc,
}
this.sendReportRequest(options)
}
// 状态重置
this.__licationHide = false
}
}
/**
* 离开应用触发
* @param {Object} self
* @param {Object} type
*/
applicationHide(self, type) {
// 进入应用后台保存状态,方便进入前台后判断是否上报应用数据
this.__licationHide = true
get_last_time()
const time = get_residence_time()
const route = get_page_route(self)
// this._lastPageRoute = route
uni.setStorageSync('_STAT_LAST_PAGE_ROUTE', route)
this.sendHideRequest({
urlref: route,
urlref_ts: time.residenceTime,
},
type
)
// 重置时间
get_first_time()
}
/**
* 进入页面触发
*/
pageShow(self) {
// 清空值 ,初始化 ,避免污染后面的上报数据
this._navigationBarTitle = {
config: '',
page: '',
report: '',
lt: '',
}
const route = get_page_route(self)
const routepath = get_route(self)
this._navigationBarTitle.config = get_page_name(routepath)
// 表示应用触发 ,页面切换不触发之后的逻辑
if (this.__licationShow) {
get_first_time()
// this._lastPageRoute = route
uni.setStorageSync('_STAT_LAST_PAGE_ROUTE', route)
this.__licationShow = false
return
}
get_last_time()
const time = get_residence_time('page')
// 停留时间
if (time.overtime) {
let options = {
path: route,
scene: this.statData.sc,
}
this.sendReportRequest(options)
}
// 重置时间
get_first_time()
}
/**
* 离开页面触发
*/
pageHide(self) {
if (!this.__licationHide) {
get_last_time()
const time = get_residence_time('page')
let route = get_page_route(self)
let lastPageRoute = uni.getStorageSync('_STAT_LAST_PAGE_ROUTE')
if (!lastPageRoute) {
lastPageRoute = route
}
uni.setStorageSync('_STAT_LAST_PAGE_ROUTE', route)
this.sendPageRequest({
url: route,
urlref: lastPageRoute,
urlref_ts: time.residenceTime,
})
// this._lastPageRoute = route
return
}
}
/**
* 发送请求,应用维度上报
* @param {Object} options 页面信息
*/
sendReportRequest(options) {
this._navigationBarTitle.lt = '1'
this._navigationBarTitle.config = get_page_name(options.path)
let is_opt = options.query && JSON.stringify(options.query) !== '{}'
let query = is_opt ? '?' + JSON.stringify(options.query) : ''
Object.assign(this.statData, {
lt: '1',
url: (options.path + query) || '',
t: get_time(),
sc: get_scene(options.scene),
fvts: get_first_visit_time(),
lvts: get_last_visit_time(),
tvc: get_total_visit_count()
})
if (get_platform_name() === 'n') {
this.getProperty()
} else {
this.getNetworkInfo()
}
}
/**
* 发送请求,页面维度上报
* @param {Object} opt
*/
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: get_time(),
p: this.statData.p,
}
this.request(options)
}
/**
* 进入后台上报数据
* @param {Object} opt
* @param {Object} type
*/
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: get_time(),
p: this.statData.p,
}
this.request(options, type)
}
/**
* 自定义事件上报
*/
sendEventRequest({
key = '',
value = ''
} = {}) {
// const route = this._lastPageRoute
const routepath = get_route()
this._navigationBarTitle.config = get_page_name(routepath)
this._navigationBarTitle.lt = '21'
let options = {
ak: this.statData.ak,
uuid: this.statData.uuid,
lt: '21',
ut: this.statData.ut,
url: routepath,
ch: this.statData.ch,
e_n: key,
e_v: typeof value === 'object' ? JSON.stringify(value) : value.toString(),
usv: this.statData.usv,
t: get_time(),
p: this.statData.p,
}
this.request(options)
}
/**
* 获取wgt资源版本
*/
getProperty() {
plus.runtime.getProperty(plus.runtime.appid, (wgtinfo) => {
this.statData.v = wgtinfo.version || ''
this.getNetworkInfo()
})
}
/**
* 获取网络信息
*/
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)
}
}
/**
* 发送请求
* @param {Object} data 上报数据
* @param {Object} type 类型
*/
request(data, type) {
let time = get_time()
const title = this._navigationBarTitle
Object.assign(data, {
ttn: title.page,
ttpj: title.config,
ttc: title.report
})
let uniStatData = dbGet('__UNI__STAT__DATA') || {}
if (!uniStatData[data.lt]) {
uniStatData[data.lt] = []
}
// 加入队列
uniStatData[data.lt].push(data)
dbSet('__UNI__STAT__DATA', uniStatData)
let page_residence_time = get_page_residence_time()
// 判断时候到达上报时间 ,默认 10 秒上报
if (page_residence_time < OPERATING_TIME && !type) return
// 时间超过,重新获取时间戳
set_page_residence_time()
const stat_data = handle_data(uniStatData)
let optionsData = {
usv: STAT_VERSION, //统计 SDK 版本号
t: time, //发送请求时的时间戮
requests: stat_data,
}
// 重置队列
dbRemove('__UNI__STAT__DATA')
// XXX 安卓需要延迟上报 ,否则会有未知错误,需要验证处理
if (get_platform_name() === 'n' && this.statData.p === 'a') {
setTimeout(() => {
this.sendRequest(optionsData)
}, 200)
return
}
this.sendRequest(optionsData)
}
/**
* 数据上报
* @param {Object} optionsData 需要上报的数据
*/
sendRequest(optionsData) {
if (!uniCloud.config) {
console.error('当前尚未绑定服务空间.')
return
}
uniCloud.callFunction({
name: 'uni-stat-report',
data: optionsData,
success: (res) => {},
fail: (err) => {
console.log(err);
}
})
}
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
)
}
}
import Report from './report.js'
import Vue from 'vue'
let vue = (Vue.default || Vue)
import {
set_page_residence_time
} from '../utils/pageTime.js'
import {
get_page_types,
get_platform_name
} from '../utils/pageInfo.js'
class Stat extends Report {
static getInstance() {
if (!vue.instance) {
vue.instance = new Stat()
}
return vue.instance
}
constructor() {
super()
this.instance = null
}
/**
* 进入应用
* @param {Object} options 页面参数
* @param {Object} self 当前页面实例
*/
launch(options, self) {
// 初始化页面停留时间 start
let residence_time = set_page_residence_time()
this.__licationShow = true
this.sendReportRequest(options, true)
}
load(options, self) {
this.self = self
this._query = options
}
appHide(self){
this.applicationHide(self, true)
}
appShow(self){
this.applicationShow(self)
}
show(self) {
this.self = self
if (get_page_types(self) === 'page') {
this.pageShow(self)
}
if (get_page_types(self) === 'app') {
this.appShow(self)
}
}
hide(self) {
this.self = self
if (get_page_types(self) === 'page') {
this.pageHide(self)
}
if (get_page_types(self) === 'app') {
this.appHide(self)
}
}
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: parseInt(new Date().getTime() / 1000),
p: this.statData.p,
}
this.request(options)
}
}
export default Stat
import {
get_platform_name,
get_page_vm
} from './utils/pageInfo.js'
import Stat from './core/stat.js'
const stat = Stat.getInstance()
// 用于判断是隐藏页面还是卸载页面
let isHide = false
const lifecycle = {
onLaunch(options) {
// 进入应用上报数据
stat.launch(options, this);
},
onLoad(options) {
stat.load(options, this);
// 重写分享,获取分享上报事件
if (this.$scope && this.$scope.onShareAppMessage) {
let oldShareAppMessage = this.$scope.onShareAppMessage;
this.$scope.onShareAppMessage = function(options) {
stat.interceptShare(false);
return oldShareAppMessage.call(this, options)
}
}
},
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)
}
}
function main() {
if (process.env.NODE_ENV === 'development') {
uni.report = function(type, options) {};
} else {
console.log('uniCloud统计已开启');
const Vue = require('vue');
(Vue.default || Vue).mixin(lifecycle);
uni.report = function(type, options) {
stat.sendEvent(type, options);
};
}
}
main()
// 访问开始即启动小程序,访问结束结分为:进入后台超过5min、在前台无任何操作超过30min、在新的来源打开小程序;
export const STAT_VERSION = '0.0.1'
export const PAGE_PVER_TIME = 1800 // 页面在前台无操作结束访问时间 单位s
// export const PAGE_PVER_TIME = 0
export const APP_PVER_TIME = 300 // 应用在后台结束访问时间 单位s
// export const APP_PVER_TIME = 0
// export const OPERATING_TIME = 10 // 数据上报时间 单位s
export const OPERATING_TIME = 10 // 数据上报时间 单位s
export const DEBUG = true
export const dbSet = (name, value) => {
let data = uni.getStorageSync('$$STAT__DBDATA') || {}
if (!data) {
data = {}
}
data[name] = value
uni.setStorageSync('$$STAT__DBDATA', data)
}
export const dbGet = (name) => {
let data = uni.getStorageSync('$$STAT__DBDATA') || {}
if (!data) {
data = {}
}
if (!data[name]) {
return undefined
}
return data[name]
}
export const dbRemove = (name) => {
let data = uni.getStorageSync('$$STAT__DBDATA') || {}
if (data[name]) {
delete data[name]
uni.setStorageSync('$$STAT__DBDATA', data)
} else {
data = uni.getStorageSync('$$STAT__DBDATA')
if (data[name]) {
delete data[name]
uni.setStorageSync('$$STAT__DBDATA', data)
}
}
}
// 判断arr是否为一个数组,返回一个bool值
function isArray (arr) {
return Object.prototype.toString.call(arr) === '[object Array]';
}
// 深度克隆
export const deepClone = (obj)=> {
// 对常见的“非”值,直接返回原来值
if([null, undefined, NaN, false].includes(obj)) return obj;
if(typeof obj !== "object" && typeof obj !== 'function') {
//原始类型直接返回
return obj;
}
var o = isArray(obj) ? [] : {};
for(let i in obj) {
if(obj.hasOwnProperty(i)){
o[i] = typeof obj[i] === "object" ? deepClone(obj[i]) : obj[i];
}
}
return o;
}
import {deepClone} from './deepClone.js'
// JS对象深度合并
export const deepMerge = (target = {}, source = {})=> {
target = deepClone(target);
if (typeof target !== 'object' || typeof source !== 'object') return false;
for (var prop in source) {
if (!source.hasOwnProperty(prop)) continue;
if (prop in target) {
if (typeof target[prop] !== 'object') {
target[prop] = source[prop];
} else {
if (typeof source[prop] !== 'object') {
target[prop] = source[prop];
} else {
if (target[prop].concat && source[prop].concat) {
target[prop] = target[prop].concat(source[prop]);
} else {
target[prop] = deepMerge(target[prop], source[prop]);
}
}
}
} else {
target[prop] = source[prop];
}
}
return target;
}
// 批量导出文件
const requireApi = require.context('.', false, /.js$/)
let module = {}
let noAllowPaht = ['./index.js']
requireApi.keys().forEach((key, index) => {
if ( noAllowPaht.indexOf(key) !== -1 ) return
Object.assign(module, requireApi(key))
})
export default module
import pagesTitle from 'uni-pages?{"type":"style"}'
let pagesData = pagesTitle.pages
let titleJsons = {}
for (let i in pagesData) {
titleJsons[i] = pagesData[i].navigationBarTitleText || ''
}
import {
sys
} from './util.js'
import {
STAT_URL,
STAT_VERSION,
DIFF_TIME
} from '../config.js';
const UUID_KEY = '__DC_STAT_UUID'
const UUID_VALUE = '__DC_UUID_VALUE'
function getUuid() {
let uuid = ''
if (get_platform_name() === 'n') {
try {
uuid = plus.runtime.getDCloudId()
} catch (e) {
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 get_uuid = (statData) => {
// 有可能不存在 deviceId(一般不存在就是出bug了),就自己生成一个
return sys.deviceId || getUuid()
}
export const get_sgin = (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]] + '&'
}
return {
sign: '',
options: sginStr.substr(0, sginStr.length - 1),
}
}
export const get_encodeURIComponent_options = (statData) => {
let data = {}
for (let prop in statData) {
data[prop] = encodeURIComponent(statData[prop])
}
return data
}
/**
* 获取当前平台
* 移动端 : 'n',
* h5 : 'h5',
* 微信 : 'wx',
* 阿里 : 'ali',
* 百度 : 'bd',
* 头条 : 'tt',
* qq : 'qq',
* 快应用 : 'qn',
* 快手 : 'ks',
* 飞书 : 'lark',
* 快应用 : 'qw',
* 钉钉 : 'dt'
*/
export const get_platform_name = () => {
// 苹果审核代码中禁止出现 alipay 字样 ,需要特殊处理一下
const aliArr = ['y', 'a', 'p', 'mp-ali']
const platformList = {
'app': 'n',
'app-plus': 'n',
h5: 'h5',
'mp-weixin': 'wx',
[aliArr.reverse().join('')]: 'ali',
'mp-baidu': 'bd',
'mp-toutiao': 'tt',
'mp-qq': 'qq',
'quickapp-native': 'qn',
'mp-kuaishou': 'ks',
'mp-lark': 'lark',
'quickapp-webview': 'qw'
}
if (platformList[process.env.VUE_APP_PLATFORM] === 'ali') {
if (my && my.env) {
const clientName = my.env.clientName
if (clientName === 'ap') return 'ali'
if (clientName === 'dingtalk') return 'dt'
// TODO 缺少 ali 下的其他平台
}
}
return platformList[process.env.VUE_APP_PLATFORM]
}
/**
* 获取小程序 appid
*/
export const get_pack_name = () => {
let packName = ''
if (get_platform_name() === 'wx' || get_platform_name() === 'qq') {
// 兼容微信小程序低版本基础库
if (uni.canIUse('getAccountInfoSync')) {
packName = uni.getAccountInfoSync().miniProgram.appId || ''
}
}
if (get_platform_name() === 'n') {
// TODO APP 获取包名
}
return packName
}
/**
* 应用版本
*/
export const get_version = () => {
return get_platform_name() === 'n' ? plus.runtime.version : ''
}
/**
* 获取渠道
*/
export const get_channel = () => {
const platformName = get_platform_name()
let channel = ''
if (platformName === 'n') {
channel = plus.runtime.channel
}
if (platformName === 'wx') {
// TODO 需要调研小程序二维码渠道如何获取;
}
return channel
}
/**
* 获取小程序场景值
* @param {Object} options 页面信息
*/
export const get_scene = (options) => {
const platformName = get_platform_name()
let scene = ''
if (options) {
return options
}
if (platformName === 'wx') {
scene = uni.getLaunchOptionsSync().scene
}
return scene
}
/**
* 获取拼接参数
*/
export const get_splicing = (data) => {
let str = ''
for (var i in data) {
str += i + '=' + data[i] + '&'
}
return str.substr(0, str.length - 1)
}
/**
* 获取页面url,不包含参数
*/
export const get_route = (pageVm) => {
let _self = pageVm || get_page_vm();
if (get_platform_name() === 'bd') {
let mp_route = _self.$mp && _self.$mp.page && _self.$mp.page.is;
let scope_route = _self.$scope && _self.$scope.is;
return mp_route || scope_route || ''
} else {
return _self.route || (_self.$scope && _self.$scope.route) || (_self.$mp && _self.$mp.page.route)
}
};
/**
* 获取页面url, 包含参数
*/
export const get_page_route = (pageVm) => {
// 从 app 进入应用 ,没有 $page ,获取不到路由 ,需要获取页面 尝试从 getCurrentPages 获取也页面实例
// FIXME 尽量不使用 getCurrentPages ,大部分获取路由是从 onHide 获取 ,这时可以获取到,如果是 onload ,则可能获取不到,比如 百度
let page = pageVm.$page || (pageVm.$scope && pageVm.$scope.$page)
let lastPageRoute = uni.getStorageSync('_STAT_LAST_PAGE_ROUTE');
if (!page) return lastPageRoute || ''
return page.fullPath === '/' ? page.route : page.fullPath
};
/**
* 获取页面实例
*/
export const get_page_vm = () => {
let pages = getCurrentPages()
let $page = pages[pages.length - 1]
if (!$page) return null
return $page.$vm
}
/**
* 获取页面类型
*/
export const get_page_types = (self) => {
// XXX 百度有问题 ,获取的都是 componet ,等待修复
if (self.mpType === 'page' || self.$mpType === 'page' || (self.$mp && self.$mp.mpType === 'page') || self
.$options.mpType === 'page') {
return 'page';
}
if (self.mpType === 'app' || self.$mpType === 'app' || (self.$mp && self.$mp.mpType === 'app') || self.$options
.mpType === 'app') {
return 'app'
}
return null;
}
/**
* 处理上报参数
* @param {Object} 需要处理的数据
*/
export const handle_data = (statData) => {
let firstArr = []
let contentArr = []
let lastArr = []
for (let i in statData) {
const rd = statData[i]
rd.forEach((elm) => {
const newData = get_splicing(elm)
if (i === 0) {
firstArr.push(newData)
} else if (i === 3) {
lastArr.push(newData)
} else {
contentArr.push(newData)
}
})
}
firstArr.push(...contentArr, ...lastArr)
// 参数需要处理成字符串,方便上传
return JSON.stringify(firstArr)
}
/**
* 自定义事件参数校验
*/
export const calibration = (eventName, options) => {
// login 、 share 、pay_success 、pay_fail 、register 、title
if (!eventName) {
console.error(`uni.report Missing [eventName] parameter`);
return true
}
if (typeof eventName !== 'string') {
console.error(`uni.report [eventName] Parameter type error, it can only be of type String`);
return true
}
if (eventName.length > 255) {
console.error(`uni.report [eventName] Parameter length cannot be greater than 255`);
return true
}
if (typeof options !== 'string' && typeof options !== 'object') {
console.error('uni.report [options] Parameter type error, Only supports String or Object type');
return true
}
if (typeof options === 'string' && options.length > 255) {
console.error(`uni.report [options] Parameter length cannot be greater than 255`);
return true
}
if (eventName === 'title' && typeof options !== 'string') {
console.error(
`uni.report [eventName] When the parameter is title, the [options] parameter can only be of type String`
);
return true
}
}
export const get_page_name = (routepath) => {
return (titleJsons && titleJsons[routepath]) || ''
}
import {
get_platform_name
} from './pageInfo.js'
import {
dbSet,
dbGet,
dbRemove
} from './db.js'
import {
PAGE_PVER_TIME,
APP_PVER_TIME
} from '../config.js';
// 首次访问时间
const FIRST_VISIT_TIME_KEY = '__first__visit__time'
// 最后访问时间
const LAST_VISIT_TIME_KEY = '__last__visit__time'
/**
* 获取当前时间
*/
export const get_time = () => {
return parseInt(new Date().getTime() / 1000)
}
/**
* 获取首次访问时间
*/
export const get_first_visit_time = () => {
const timeStorge = dbGet(FIRST_VISIT_TIME_KEY)
let time = 0
if (timeStorge) {
time = timeStorge
} else {
time = get_time()
dbSet(FIRST_VISIT_TIME_KEY, time)
// 首次访问需要 将最后访问时间置 0
dbRemove(LAST_VISIT_TIME_KEY)
}
return time
}
/**
* 最后访问时间
*/
export const get_last_visit_time = () => {
const timeStorge = dbGet(LAST_VISIT_TIME_KEY)
let time = 0
if (timeStorge) {
time = timeStorge
}
dbSet(LAST_VISIT_TIME_KEY, get_time())
return time
}
// 页面停留时间记录key
const PAGE_RESIDENCE_TIME = '__page__residence__time'
/**
* 设置页面停留时间
*/
export const set_page_residence_time = () => {
let First_Page_Residence_Time = get_time()
dbSet(PAGE_RESIDENCE_TIME, First_Page_Residence_Time)
return First_Page_Residence_Time
}
/**
* 获取页面停留时间
*/
export const get_page_residence_time = () => {
let Last_Page_Residence_Time = get_time()
let First_Page_Residence_Time = dbGet(PAGE_RESIDENCE_TIME)
return Last_Page_Residence_Time - First_Page_Residence_Time
}
/**
* 获取总访问次数
*/
const TOTAL_VISIT_COUNT = '__total__visit__count'
export const get_total_visit_count = () => {
const timeStorge = dbGet(TOTAL_VISIT_COUNT)
let count = 1
if (timeStorge) {
count = timeStorge
count++
}
dbSet(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 get_first_time = () => {
let time = new Date().getTime()
Set__First__Time = time
Set__Last__Time = 0
return time
}
/**
* 获取最后一次时间
*/
export const get_last_time = () => {
let time = new Date().getTime()
Set__Last__Time = time
return time
}
/**
* 获取页面 \ 应用停留时间
*/
export const get_residence_time = (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 sys = uni.getSystemInfoSync()
此差异已折叠。
import {
version
} from '../package.json'
export const STAT_VERSION = version
export const STAT_URL = 'https://tongji.dcloud.io/uni/stat'
export const STAT_H5_URL = 'https://tongji.dcloud.io/uni/stat.gif'
// 访问开始即启动小程序,访问结束结分为:进入后台超过5min、在前台无任何操作超过30min、在新的来源打开小程序;
export const STAT_VERSION = '0.0.1'
export const STAT_URL = 'https://tongji.dcloud.io/uni/stat'
export const STAT_H5_URL = 'https://tongji.dcloud.io/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
export const PAGE_PVER_TIME = 1800 // 页面在前台无操作结束访问时间 单位s
export const APP_PVER_TIME = 300 // 应用在后台结束访问时间 单位s
export const OPERATING_TIME = 10 // 数据上报时间 单位s
export const DIFF_TIME = 60 * 1000 * 60 * 24
export const DEBUG = true
此差异已折叠。
import Report from './report.js'
import Vue from 'vue'
let vue = (Vue.default || Vue)
import {
set_page_residence_time
} from '../utils/pageTime.js'
import {
get_page_types,
get_platform_name
} from '../utils/pageInfo.js'
class Stat extends Report {
static getInstance() {
if (!vue.instance) {
vue.instance = new Stat()
}
return vue.instance
}
constructor() {
super()
this.instance = null
}
/**
* 进入应用
* @param {Object} options 页面参数
* @param {Object} self 当前页面实例
*/
launch(options, self) {
// 初始化页面停留时间 start
let residence_time = set_page_residence_time()
this.__licationShow = true
this.sendReportRequest(options, true)
}
load(options, self) {
this.self = self
this._query = options
}
appHide(self){
this.applicationHide(self, true)
}
appShow(self){
this.applicationShow(self)
}
show(self) {
this.self = self
if (get_page_types(self) === 'page') {
this.pageShow(self)
}
if (get_page_types(self) === 'app') {
this.appShow(self)
}
}
hide(self) {
this.self = self
if (get_page_types(self) === 'page') {
this.pageHide(self)
}
if (get_page_types(self) === 'app') {
this.appHide(self)
}
}
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: parseInt(new Date().getTime() / 1000),
p: this.statData.p,
}
this.request(options)
}
}
export default Stat
import Stat from './stat.js';
const stat = Stat.getInstance();
import {
get_platform_name,
get_page_vm
} from './utils/pageInfo.js'
import Stat from './core/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);
// 重写分享,获取分享上报事件
if (this.$scope && this.$scope.onShareAppMessage) {
let oldShareAppMessage = this.$scope.onShareAppMessage;
this.$scope.onShareAppMessage = function(options) {
stat.interceptShare(false);
return oldShareAppMessage.call(this, options)
}
}
},
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)
}
onLaunch(options) {
// 进入应用上报数据
stat.launch(options, this);
},
onLoad(options) {
stat.load(options, this);
// 重写分享,获取分享上报事件
if (this.$scope && this.$scope.onShareAppMessage) {
let oldShareAppMessage = this.$scope.onShareAppMessage;
this.$scope.onShareAppMessage = function(options) {
stat.interceptShare(false);
return oldShareAppMessage.call(this, options)
}
}
},
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)
}
}
function main() {
if (process.env.NODE_ENV === 'development') {
uni.report = function(type, options) {};
} else {
const Vue = require('vue');
(Vue.default || Vue).mixin(lifecycle);
uni.report = function(type, options) {
stat.sendEvent(type, options);
};
}
function main() {
if (process.env.NODE_ENV === 'development') {
uni.report = function(type, options) {};
} else {
console.log('统计已开启');
const Vue = require('vue');
(Vue.default || Vue).mixin(lifecycle);
uni.report = function(type, options) {
stat.sendEvent(type, options);
};
}
}
main();
main()
此差异已折叠。
// 访问开始即启动小程序,访问结束结分为:进入后台超过5min、在前台无任何操作超过30min、在新的来源打开小程序;
export const STAT_VERSION = '0.0.1'
export const PAGE_PVER_TIME = 1800 // 页面在前台无操作结束访问时间 单位s
// export const PAGE_PVER_TIME = 0
export const APP_PVER_TIME = 300 // 应用在后台结束访问时间 单位s
// export const APP_PVER_TIME = 0
// export const OPERATING_TIME = 10 // 数据上报时间 单位s
export const OPERATING_TIME = 10 // 数据上报时间 单位s
export const DEBUG = true
export const dbSet = (name, value) => {
let data = uni.getStorageSync('$$STAT__DBDATA') || {}
if (!data) {
data = {}
}
data[name] = value
uni.setStorageSync('$$STAT__DBDATA', data)
}
export const dbGet = (name) => {
let data = uni.getStorageSync('$$STAT__DBDATA') || {}
if (!data) {
data = {}
}
if (!data[name]) {
return undefined
}
return data[name]
}
export const dbRemove = (name) => {
let data = uni.getStorageSync('$$STAT__DBDATA') || {}
if (data[name]) {
delete data[name]
uni.setStorageSync('$$STAT__DBDATA', data)
} else {
data = uni.getStorageSync('$$STAT__DBDATA')
if (data[name]) {
delete data[name]
uni.setStorageSync('$$STAT__DBDATA', data)
}
}
}
// 判断arr是否为一个数组,返回一个bool值
function isArray (arr) {
return Object.prototype.toString.call(arr) === '[object Array]';
}
// 深度克隆
export const deepClone = (obj)=> {
// 对常见的“非”值,直接返回原来值
if([null, undefined, NaN, false].includes(obj)) return obj;
if(typeof obj !== "object" && typeof obj !== 'function') {
//原始类型直接返回
return obj;
}
var o = isArray(obj) ? [] : {};
for(let i in obj) {
if(obj.hasOwnProperty(i)){
o[i] = typeof obj[i] === "object" ? deepClone(obj[i]) : obj[i];
}
}
return o;
}
import {deepClone} from './deepClone.js'
// JS对象深度合并
export const deepMerge = (target = {}, source = {})=> {
target = deepClone(target);
if (typeof target !== 'object' || typeof source !== 'object') return false;
for (var prop in source) {
if (!source.hasOwnProperty(prop)) continue;
if (prop in target) {
if (typeof target[prop] !== 'object') {
target[prop] = source[prop];
} else {
if (typeof source[prop] !== 'object') {
target[prop] = source[prop];
} else {
if (target[prop].concat && source[prop].concat) {
target[prop] = target[prop].concat(source[prop]);
} else {
target[prop] = deepMerge(target[prop], source[prop]);
}
}
}
} else {
target[prop] = source[prop];
}
}
return target;
}
// 批量导出文件
const requireApi = require.context('.', false, /.js$/)
let module = {}
let noAllowPaht = ['./index.js']
requireApi.keys().forEach((key, index) => {
if ( noAllowPaht.indexOf(key) !== -1 ) return
Object.assign(module, requireApi(key))
})
export default module
import {
get_platform_name
} from './pageInfo.js'
import {
dbSet,
dbGet,
dbRemove
} from './db.js'
import {
PAGE_PVER_TIME,
APP_PVER_TIME
} from '../config.js';
// 首次访问时间
const FIRST_VISIT_TIME_KEY = '__first__visit__time'
// 最后访问时间
const LAST_VISIT_TIME_KEY = '__last__visit__time'
/**
* 获取当前时间
*/
export const get_time = () => {
return parseInt(new Date().getTime() / 1000)
}
/**
* 获取首次访问时间
*/
export const get_first_visit_time = () => {
const timeStorge = dbGet(FIRST_VISIT_TIME_KEY)
let time = 0
if (timeStorge) {
time = timeStorge
} else {
time = get_time()
dbSet(FIRST_VISIT_TIME_KEY, time)
// 首次访问需要 将最后访问时间置 0
dbRemove(LAST_VISIT_TIME_KEY)
}
return time
}
/**
* 最后访问时间
*/
export const get_last_visit_time = () => {
const timeStorge = dbGet(LAST_VISIT_TIME_KEY)
let time = 0
if (timeStorge) {
time = timeStorge
}
dbSet(LAST_VISIT_TIME_KEY, get_time())
return time
}
// 页面停留时间记录key
const PAGE_RESIDENCE_TIME = '__page__residence__time'
/**
* 设置页面停留时间
*/
export const set_page_residence_time = () => {
let First_Page_Residence_Time = get_time()
dbSet(PAGE_RESIDENCE_TIME, First_Page_Residence_Time)
return First_Page_Residence_Time
}
/**
* 获取页面停留时间
*/
export const get_page_residence_time = () => {
let Last_Page_Residence_Time = get_time()
let First_Page_Residence_Time = dbGet(PAGE_RESIDENCE_TIME)
return Last_Page_Residence_Time - First_Page_Residence_Time
}
/**
* 获取总访问次数
*/
const TOTAL_VISIT_COUNT = '__total__visit__count'
export const get_total_visit_count = () => {
const timeStorge = dbGet(TOTAL_VISIT_COUNT)
let count = 1
if (timeStorge) {
count = timeStorge
count++
}
dbSet(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 get_first_time = () => {
let time = new Date().getTime()
Set__First__Time = time
Set__Last__Time = 0
return time
}
/**
* 获取最后一次时间
*/
export const get_last_time = () => {
let time = new Date().getTime()
Set__Last__Time = time
return time
}
/**
* 获取页面 \ 应用停留时间
*/
export const get_residence_time = (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 sys = uni.getSystemInfoSync()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册