@tmsfe/tms-core 0.0.32 → 0.0.35
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/package.json +2 -2
- package/src/index-proxy.js +1 -17
- package/src/index.js +3 -19
- package/src/report/formatV1.ts +92 -0
- package/src/report/formatV2.ts +101 -0
- package/src/report/helper.ts +223 -0
- package/src/report/index.ts +64 -0
- package/src/report/sender.ts +98 -0
- package/src/report/types.ts +44 -0
- package/src/cloudReport.ts +0 -199
- package/src/fastreport.js +0 -51
- package/src/report.js +0 -433
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tmsfe/tms-core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.35",
|
|
4
4
|
"description": "tms运行时框架",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"dev": "rimraf dist && rollup -wc --environment TARGET:tms-core,INTER_ENV:public",
|
|
11
11
|
"build": "rimraf dist && rollup -c --environment TARGET:tms-core,INTER_ENV:public"
|
|
12
12
|
},
|
|
13
|
-
"main": "
|
|
13
|
+
"main": "src/index",
|
|
14
14
|
"miniprogram": "src",
|
|
15
15
|
"buildOptions": {
|
|
16
16
|
"formats": [
|
package/src/index-proxy.js
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
import syncApi from './syncfnmanager';
|
|
9
9
|
import md5 from './md5';
|
|
10
|
-
import CloudReport from './cloudReport';
|
|
11
10
|
import { rpxToPx } from './rpx';
|
|
12
11
|
import { serialize } from './objUtils';
|
|
13
12
|
import * as stringUtils from './stringUtils';
|
|
@@ -40,7 +39,6 @@ function invoke(obj, funcName, args) {
|
|
|
40
39
|
function initProxy(appObj, options) {
|
|
41
40
|
app = appObj;
|
|
42
41
|
initOptions = options;
|
|
43
|
-
CloudReport.init(options);
|
|
44
42
|
}
|
|
45
43
|
|
|
46
44
|
function awaitTMS() {
|
|
@@ -75,8 +73,7 @@ asyncFuncNames.forEach((funcName) => {
|
|
|
75
73
|
// 返回对象的函数,并且对象的所有接口都可以以promise的形式返回
|
|
76
74
|
const objFuncs = {};
|
|
77
75
|
const objFuncNames = [
|
|
78
|
-
'getLogManager', 'getRealtimeLogManager', 'getReporter',
|
|
79
|
-
'getFastReporter', 'getEventDispatcher',
|
|
76
|
+
'getLogManager', 'getRealtimeLogManager', 'getReporter', 'getEventDispatcher',
|
|
80
77
|
];
|
|
81
78
|
objFuncNames.forEach((funcName) => {
|
|
82
79
|
objFuncs[funcName] = function (...args1) {
|
|
@@ -203,23 +200,10 @@ function getHomePage() {
|
|
|
203
200
|
return initOptions.homePage;
|
|
204
201
|
}
|
|
205
202
|
|
|
206
|
-
function getCloudReport() {
|
|
207
|
-
if (tms) {
|
|
208
|
-
return tms.getCloudReport();
|
|
209
|
-
}
|
|
210
|
-
return CloudReport;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
wx.onAppShow((options) => {
|
|
214
|
-
// 避免vendor分包加载太慢而错过onAppShow
|
|
215
|
-
wx.tmsAppShowOptions = options;
|
|
216
|
-
});
|
|
217
|
-
|
|
218
203
|
const api = {
|
|
219
204
|
isProxy: true, // 方便定位问题时判断是否proxy
|
|
220
205
|
initProxy,
|
|
221
206
|
md5,
|
|
222
|
-
getCloudReport,
|
|
223
207
|
getCarManager,
|
|
224
208
|
getLocationManager,
|
|
225
209
|
rpxToPx,
|
package/src/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import Request from './request';
|
|
2
|
-
import
|
|
3
|
-
import CloudReport from './cloudReport';
|
|
2
|
+
import Reporter from './report/index';
|
|
4
3
|
import { getConfig } from './config';
|
|
5
4
|
import syncApi from './syncfnmanager';
|
|
6
5
|
import nav from './navigator';
|
|
@@ -8,7 +7,6 @@ import { getLogManager, getRealtimeLogManager } from './log';
|
|
|
8
7
|
import { setEnvInfo, getEnvInfo, setAuthInfo, setAppPagePaths, isAppPageExist, getHomePage } from './env';
|
|
9
8
|
import md5 from './md5';
|
|
10
9
|
import { callCloudFunc } from './cloudService';
|
|
11
|
-
import { cache as report, startListenApp } from './report';
|
|
12
10
|
import EventDispatcher from './eventDispatcher';
|
|
13
11
|
import { serialize } from './objUtils';
|
|
14
12
|
import { rpxToPx } from './rpx';
|
|
@@ -66,18 +64,7 @@ const createRequest = (config = {}) => new Request(config);
|
|
|
66
64
|
* @example
|
|
67
65
|
* getReporter().report(reportData, reportNow);
|
|
68
66
|
*/
|
|
69
|
-
const getReporter = () =>
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* @description 埋点上报(快速上报,不依赖用户userId标识)
|
|
73
|
-
* @returns {Class} [FastReporter类](#class-fastreport)
|
|
74
|
-
*/
|
|
75
|
-
const getFastReporter = () => FastReport;
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* @description 云函数埋点上报
|
|
79
|
-
*/
|
|
80
|
-
const getCloudReport = () => CloudReport;
|
|
67
|
+
const getReporter = () => Reporter;
|
|
81
68
|
|
|
82
69
|
/**
|
|
83
70
|
* @description 自定义事件机制
|
|
@@ -103,7 +90,6 @@ const getLocationBaseClass = () => LocationBase;
|
|
|
103
90
|
* @returns {undefined} 无返回值.
|
|
104
91
|
*/
|
|
105
92
|
const init = (options = {}) => {
|
|
106
|
-
startListenApp();
|
|
107
93
|
const { appVersion, wxAppId, client, defaultHost, cloudEnvId, appEnv, appPagePaths, homePage } = options;
|
|
108
94
|
const envInfo = {
|
|
109
95
|
wxAppId,
|
|
@@ -114,7 +100,7 @@ const init = (options = {}) => {
|
|
|
114
100
|
};
|
|
115
101
|
setEnvInfo(envInfo);
|
|
116
102
|
setAppPagePaths(appPagePaths, homePage);
|
|
117
|
-
|
|
103
|
+
Reporter.init(envInfo);
|
|
118
104
|
Request.defaultHost = defaultHost;
|
|
119
105
|
// 初始化云环境
|
|
120
106
|
wx.cloud.init({ env: cloudEnvId });
|
|
@@ -140,8 +126,6 @@ const api = {
|
|
|
140
126
|
getRealtimeLogManager,
|
|
141
127
|
md5,
|
|
142
128
|
getReporter,
|
|
143
|
-
getCloudReport,
|
|
144
|
-
getFastReporter,
|
|
145
129
|
getLocationManager,
|
|
146
130
|
getLocationBaseClass,
|
|
147
131
|
getEventDispatcher,
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 格式化旧埋点
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// / <reference path='./types.ts'/>
|
|
6
|
+
import helper from './helper';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 获取埋点的基础字段
|
|
10
|
+
*/
|
|
11
|
+
function getBaseData(deviceData: IDeviceData): DataItem[] {
|
|
12
|
+
const arr = new Array<string>(helper.dataArrLen);
|
|
13
|
+
const { networkType, location } = deviceData;
|
|
14
|
+
const { appVersion, client } = helper.getInitOptions();
|
|
15
|
+
// todo: 如何区分新旧埋点?新:f20不为空,旧:f20为空
|
|
16
|
+
// ++++++++++++++++++++++++++字段列表++++++++++++++++++++++++++
|
|
17
|
+
// 0: log_time,日志入库时间
|
|
18
|
+
// 1: access_time,用户点击时间,服务端统一处理
|
|
19
|
+
// 2: user_ip,前端无需赋值
|
|
20
|
+
// 3: qimei,灯塔中的用户ID
|
|
21
|
+
// 4: imei,Android手机的imei IOS系统中的idfv 车联网中的wecarid
|
|
22
|
+
// 5: user_id,用户ID
|
|
23
|
+
// 6: qq_no,登录QQ的openid,
|
|
24
|
+
// 7: wechat_id,登录微信的openid
|
|
25
|
+
// 8: phone_no,手机号
|
|
26
|
+
// 9: platform,客户端请求来源,小程序是2
|
|
27
|
+
arr[9] = '2';
|
|
28
|
+
// 10: app_version,客户端|小程序版本号
|
|
29
|
+
arr[10] = appVersion;
|
|
30
|
+
// 11: channel,外部推广渠道或车辆所属渠道
|
|
31
|
+
// 12: net_type,wifi、3G、4G等
|
|
32
|
+
arr[12] = networkType;
|
|
33
|
+
// 13: product_id,手图APP、车联网等
|
|
34
|
+
arr[13] = '2';
|
|
35
|
+
// 14: busi_type,1: 定位、2: 检索、3: 导航、4: 车主服务、5: 小程序
|
|
36
|
+
arr[14] = '5';
|
|
37
|
+
// 15: request_id,请求ID,由接入层填充
|
|
38
|
+
// 16: session_id,这里表示渠道公共参数
|
|
39
|
+
arr[16] = helper.getLaunchFrom();
|
|
40
|
+
// 17: f17,province - 省份
|
|
41
|
+
arr[17] = location.province;
|
|
42
|
+
// 18: f18,city - 城市
|
|
43
|
+
arr[18] = location.cityName;
|
|
44
|
+
// 19: f19,当前小程序运行的宿主环境
|
|
45
|
+
arr[19] = helper.getSystemInfo().host;
|
|
46
|
+
// 28: f28,sinan、mycar等
|
|
47
|
+
arr[28] = client;
|
|
48
|
+
// 29: f29,小程序场景值
|
|
49
|
+
arr[29] = helper.getAppScene();
|
|
50
|
+
// 33: f33,系统信息
|
|
51
|
+
arr[33] = helper.getSystemInfoString();
|
|
52
|
+
// 36: f36,小程序启动时的参数
|
|
53
|
+
arr[36] = helper.getLaunchOptionsString();
|
|
54
|
+
// --------------------------字段列表--------------------------
|
|
55
|
+
return arr;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 拼接埋点数组
|
|
60
|
+
*/
|
|
61
|
+
function jointData(data: IOldParams, deviceData: IDeviceData): DataItem[] {
|
|
62
|
+
const arr = getBaseData(deviceData);
|
|
63
|
+
const keys = Object.keys(data) as any as number[];
|
|
64
|
+
for (const key of keys) {
|
|
65
|
+
arr[key] = helper.convert2String(data[key]);
|
|
66
|
+
}
|
|
67
|
+
return arr;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 格式化普通埋点数据
|
|
72
|
+
*/
|
|
73
|
+
function formatData(data: IOldParams): Promise<DataItem[]> {
|
|
74
|
+
return new Promise<DataItem[]>((resolve) => {
|
|
75
|
+
helper.getDeviceData().then((deviceData: IDeviceData) => {
|
|
76
|
+
const arr = jointData(data, deviceData);
|
|
77
|
+
resolve(arr);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 格式化快速上报埋点数据,不依赖用户位置
|
|
84
|
+
*/
|
|
85
|
+
function formatFastData(data: IOldParams): DataItem[] {
|
|
86
|
+
return jointData(data, helper.defaultDevice);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export default {
|
|
90
|
+
formatData,
|
|
91
|
+
formatFastData,
|
|
92
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 格式化新埋点
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// / <reference path='./types.ts'/>
|
|
6
|
+
import helper from './helper';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 获取埋点的基础字段
|
|
10
|
+
*/
|
|
11
|
+
function getBaseData(deviceData: IDeviceData): { arr: DataItem[], nextIndex: number } {
|
|
12
|
+
const page = helper.getPageInfo() as IPage;
|
|
13
|
+
const { networkType, location } = deviceData;
|
|
14
|
+
const { appVersion, client } = helper.getInitOptions();
|
|
15
|
+
const arr = new Array<string>(helper.dataArrLen);
|
|
16
|
+
// todo: 如何区分新旧埋点?新:f20不为空,旧:f20为空
|
|
17
|
+
// ++++++++++++++++++++++++++字段列表++++++++++++++++++++++++++
|
|
18
|
+
// 0: log_time,日志入库时间
|
|
19
|
+
// 1: access_time,用户点击时间,服务端统一处理
|
|
20
|
+
// 2: user_ip,前端无需赋值
|
|
21
|
+
// 3: qimei,灯塔中的用户ID
|
|
22
|
+
// 4: imei,Android手机的imei IOS系统中的idfv 车联网中的wecarid
|
|
23
|
+
// 5: user_id,用户ID
|
|
24
|
+
// 6: qq_no,登录QQ的openid,
|
|
25
|
+
// 7: wechat_id,登录微信的openid
|
|
26
|
+
// 8: phone_no,手机号
|
|
27
|
+
// 9: platform,客户端请求来源,小程序是2
|
|
28
|
+
arr[9] = '2';
|
|
29
|
+
// 10: app_version,客户端|小程序版本号
|
|
30
|
+
arr[10] = appVersion;
|
|
31
|
+
// 11: channel,外部推广渠道或车辆所属渠道
|
|
32
|
+
// 12: net_type,wifi、3G、4G等
|
|
33
|
+
arr[12] = networkType;
|
|
34
|
+
// 13: product_id,手图APP、车联网等
|
|
35
|
+
arr[13] = '2';
|
|
36
|
+
// 14: busi_type,1: 定位、2: 检索、3: 导航、4: 车主服务、5: 小程序
|
|
37
|
+
arr[14] = '5';
|
|
38
|
+
// 15: request_id,请求ID,由接入层填充
|
|
39
|
+
// 16: session_id,标识用户一次访问过程的ID
|
|
40
|
+
// 17: f17,province - 省份
|
|
41
|
+
arr[17] = location.province;
|
|
42
|
+
// 18: f18,city - 城市
|
|
43
|
+
arr[18] = location.cityName;
|
|
44
|
+
// 19: f19,系统信息
|
|
45
|
+
arr[19] = helper.getSystemInfoString();
|
|
46
|
+
// 20: f20,sinan、mycar等
|
|
47
|
+
arr[20] = client;
|
|
48
|
+
// 21: f21,小程序场景值
|
|
49
|
+
arr[21] = helper.getAppScene();
|
|
50
|
+
// 22: f22,小程序启动时的参数
|
|
51
|
+
arr[22] = helper.getLaunchOptionsString();
|
|
52
|
+
// 23: f23,当前页面的url
|
|
53
|
+
arr[23] = page.route;
|
|
54
|
+
// 24: f24,当前页面的query
|
|
55
|
+
arr[24] = JSON.stringify(page.options);
|
|
56
|
+
// 25 ~ 30: 预留字段给后续扩展使用
|
|
57
|
+
// 31 ~ 40: 提供给开发自定义
|
|
58
|
+
// --------------------------字段列表--------------------------
|
|
59
|
+
return { arr, nextIndex: 31 };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 拼接埋点数组
|
|
64
|
+
*/
|
|
65
|
+
function jointData(data: any[], deviceData: IDeviceData): DataItem[] {
|
|
66
|
+
const { arr, nextIndex } = getBaseData(deviceData);
|
|
67
|
+
let index = nextIndex;
|
|
68
|
+
for (const item of data) {
|
|
69
|
+
if (index >= arr.length) {
|
|
70
|
+
console.error('埋点参数个数超出上限而被截断', data);
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
arr[index] = helper.convert2String(item);
|
|
74
|
+
index += 1;
|
|
75
|
+
}
|
|
76
|
+
return arr;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 格式化上报埋点数据
|
|
81
|
+
*/
|
|
82
|
+
function formatData(data: any[]): Promise<DataItem[]> {
|
|
83
|
+
return new Promise<DataItem[]>((resolve) => {
|
|
84
|
+
helper.getDeviceData().then((deviceData: IDeviceData) => {
|
|
85
|
+
const arr = jointData(data, deviceData);
|
|
86
|
+
resolve(arr);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 格式化快速上报埋点数据,不依赖用户位置
|
|
93
|
+
*/
|
|
94
|
+
function formatFastData(data: any[]): DataItem[] {
|
|
95
|
+
return jointData(data, helper.defaultDevice);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export default {
|
|
99
|
+
formatData,
|
|
100
|
+
formatFastData,
|
|
101
|
+
};
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 埋点辅助函数
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// / <reference path='./types.ts'/>
|
|
6
|
+
import syncApi from '../syncfnmanager';
|
|
7
|
+
|
|
8
|
+
function getTms(): any {
|
|
9
|
+
// 如果是在app.js的onLaunch中调用,则没有getApp().tms为空
|
|
10
|
+
return getApp()?.tms || wx.tms;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let initOptions: IInitOptions;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 初始化
|
|
17
|
+
*/
|
|
18
|
+
function init(options: IInitOptions): void {
|
|
19
|
+
if (!initOptions) {
|
|
20
|
+
initOptions = options;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 获取初始化时的参数
|
|
26
|
+
*/
|
|
27
|
+
function getInitOptions(): IInitOptions {
|
|
28
|
+
return initOptions;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let systemInfo: ISystemInfo | null = null;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 获取系统信息
|
|
35
|
+
*/
|
|
36
|
+
function getSystemInfo(): ISystemInfo {
|
|
37
|
+
if (systemInfo === null) {
|
|
38
|
+
const system = syncApi.getSystemInfoSync() as any;
|
|
39
|
+
// eslint-disable-next-line
|
|
40
|
+
const { model = '', version: wxVersion = '', platform = '', SDKVersion = '', host = '' } = system;
|
|
41
|
+
systemInfo = { model, wxVersion, platform, SDKVersion, host };
|
|
42
|
+
}
|
|
43
|
+
return systemInfo;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let systemString: string | null = null;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 获取系统信息并格式化成字符串
|
|
50
|
+
*/
|
|
51
|
+
function getSystemInfoString(): string {
|
|
52
|
+
if (systemString === null) {
|
|
53
|
+
systemString = JSON.stringify(getSystemInfo());
|
|
54
|
+
}
|
|
55
|
+
return systemString;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 把值/对象转成字符串
|
|
60
|
+
* @param value
|
|
61
|
+
*/
|
|
62
|
+
function convert2String(value: any): string {
|
|
63
|
+
const type = typeof value;
|
|
64
|
+
if (type === 'string') {
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
if (type === 'object') {
|
|
68
|
+
return JSON.stringify(value);
|
|
69
|
+
}
|
|
70
|
+
return String(value);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 获取当前页面信息
|
|
75
|
+
*/
|
|
76
|
+
function getPageInfo(): IPage | null {
|
|
77
|
+
const pages = getCurrentPages();
|
|
78
|
+
// 首页未渲染
|
|
79
|
+
if (pages.length === 0) {
|
|
80
|
+
const launch = syncApi.getLaunchOptionsSync() as any;
|
|
81
|
+
return { route: launch.path, options: launch.query };
|
|
82
|
+
}
|
|
83
|
+
const page = pages.pop();
|
|
84
|
+
// 插件页
|
|
85
|
+
if (!page) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
return page;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
let launchOptions: string | null = null;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* 获取小程序启动参数
|
|
95
|
+
*/
|
|
96
|
+
function getLaunchOptionsString(): string {
|
|
97
|
+
if (launchOptions === null) {
|
|
98
|
+
const obj = syncApi.getLaunchOptionsSync() as any;
|
|
99
|
+
launchOptions = obj.query ? JSON.stringify(obj.query) : '';
|
|
100
|
+
}
|
|
101
|
+
return launchOptions;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* 获取小程序启动时的from参数
|
|
106
|
+
*/
|
|
107
|
+
function getLaunchFrom(): string {
|
|
108
|
+
const obj = syncApi.getLaunchOptionsSync() as any;
|
|
109
|
+
return obj.query?.from as string || '';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 获取小程序启动场景值
|
|
114
|
+
*/
|
|
115
|
+
function getAppScene(): string {
|
|
116
|
+
const { scene = -1 } = syncApi.getLaunchOptionsSync() as any;
|
|
117
|
+
return scene.toString();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// 给非空字段都encodeURIComponent一下
|
|
121
|
+
function encodeItems(arr: DataItem[]): DataItem[] {
|
|
122
|
+
return arr.map(t => t ? encodeURIComponent(t) : t);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 是否爬虫
|
|
126
|
+
let isCrawler: boolean | null = null;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* 判断当前是否需要发埋点(爬虫和插件页不发)
|
|
130
|
+
*/
|
|
131
|
+
function canReport(): boolean {
|
|
132
|
+
if (isCrawler === null) {
|
|
133
|
+
const scene = getAppScene();
|
|
134
|
+
isCrawler = scene === '1129' || scene === '1030';
|
|
135
|
+
}
|
|
136
|
+
// 小程序爬虫,不上报
|
|
137
|
+
if (isCrawler) {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
// 插件页不上报埋点
|
|
141
|
+
return getPageInfo() !== null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* 埋点数组的长度
|
|
146
|
+
*/
|
|
147
|
+
const dataArrLen = 41;
|
|
148
|
+
|
|
149
|
+
const defaultDevice = {
|
|
150
|
+
networkType: null,
|
|
151
|
+
location: {
|
|
152
|
+
province: null,
|
|
153
|
+
cityName: null,
|
|
154
|
+
},
|
|
155
|
+
} as any as IDeviceData;
|
|
156
|
+
|
|
157
|
+
let networkPromise: Promise<string> | null = null;
|
|
158
|
+
|
|
159
|
+
function getNetworkType(): Promise<string> {
|
|
160
|
+
if (networkPromise === null) {
|
|
161
|
+
networkPromise = new Promise((resolve) => {
|
|
162
|
+
wx.getNetworkType({
|
|
163
|
+
success: (res: any) => resolve(res.networkType),
|
|
164
|
+
fail: () => resolve('unknown'),
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
return networkPromise;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
let locPromise: Promise<ILocation> | null = null;
|
|
172
|
+
|
|
173
|
+
function getLocation(): Promise<ILocation> {
|
|
174
|
+
if (locPromise === null) {
|
|
175
|
+
locPromise = new Promise<ILocation>((resolve) => {
|
|
176
|
+
const LOC = getTms().getLocationManager();
|
|
177
|
+
LOC.getIpLocation()
|
|
178
|
+
.then((res: any) => {
|
|
179
|
+
const ad = res.ad_info;
|
|
180
|
+
resolve({ province: ad.province, cityName: ad.city });
|
|
181
|
+
})
|
|
182
|
+
.catch(() => {
|
|
183
|
+
resolve({ province: '', cityName: '' });
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
return locPromise;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
let devicePromise: Promise<IDeviceData> | null = null;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* 获取设备信息(网络状况,位置信息)
|
|
194
|
+
*/
|
|
195
|
+
function getDeviceData(): Promise<IDeviceData> {
|
|
196
|
+
if (devicePromise === null) {
|
|
197
|
+
devicePromise = new Promise<IDeviceData>((resolve) => {
|
|
198
|
+
Promise.all([getNetworkType(), getLocation()]).then((res) => {
|
|
199
|
+
const [networkType, location] = res;
|
|
200
|
+
resolve({ networkType, location });
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
return devicePromise;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export default {
|
|
208
|
+
init,
|
|
209
|
+
getTms,
|
|
210
|
+
encodeItems,
|
|
211
|
+
getInitOptions,
|
|
212
|
+
getSystemInfo,
|
|
213
|
+
getSystemInfoString,
|
|
214
|
+
convert2String,
|
|
215
|
+
getPageInfo,
|
|
216
|
+
getLaunchOptionsString,
|
|
217
|
+
getLaunchFrom,
|
|
218
|
+
getAppScene,
|
|
219
|
+
canReport,
|
|
220
|
+
dataArrLen,
|
|
221
|
+
defaultDevice,
|
|
222
|
+
getDeviceData,
|
|
223
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 埋点
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// / <reference path='./types.ts'/>
|
|
6
|
+
import helper from './helper';
|
|
7
|
+
import sender from './sender';
|
|
8
|
+
import formatV1 from './formatV1';
|
|
9
|
+
import formatV2 from './formatV2';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 初始化
|
|
13
|
+
*/
|
|
14
|
+
function init(options: IInitOptions): void {
|
|
15
|
+
helper.init(options);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 旧埋点
|
|
20
|
+
* @param data { 27: xxxx, 34: xxx }
|
|
21
|
+
*/
|
|
22
|
+
function report(data: IOldParams = {}): void {
|
|
23
|
+
if (helper.canReport()) {
|
|
24
|
+
formatV1.formatData(data).then(arr => sender.queue(arr));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 旧埋点,快速上报,不依赖用户位置
|
|
30
|
+
* @param data { 27: xxxx, 34: xxx }
|
|
31
|
+
*/
|
|
32
|
+
function fastReport(data: IOldParams = {}): void {
|
|
33
|
+
if (helper.canReport()) {
|
|
34
|
+
const arr = formatV1.formatFastData(data);
|
|
35
|
+
sender.send(arr);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 新埋点
|
|
41
|
+
*/
|
|
42
|
+
function report2(...data: any[]): void {
|
|
43
|
+
if (helper.canReport()) {
|
|
44
|
+
formatV2.formatData(data).then(arr => sender.queue(arr));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 新埋点,快速上报,不依赖用户位置
|
|
50
|
+
*/
|
|
51
|
+
function fastReport2(...data: any[]): void {
|
|
52
|
+
if (helper.canReport()) {
|
|
53
|
+
const arr = formatV2.formatFastData(data);
|
|
54
|
+
sender.send(arr);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export default {
|
|
59
|
+
init,
|
|
60
|
+
report,
|
|
61
|
+
fastReport,
|
|
62
|
+
report2,
|
|
63
|
+
fastReport2,
|
|
64
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 负责发送埋点
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// / <reference path='./types.ts'/>
|
|
6
|
+
import helper from './helper';
|
|
7
|
+
|
|
8
|
+
// 缓存队列
|
|
9
|
+
const cacheArr = new Array<DataItem[]>();
|
|
10
|
+
const max = 50; // 超过最大限制就马上发送
|
|
11
|
+
const delay = 3000; // 延迟N毫秒再聚合发送
|
|
12
|
+
let timer = 0; // 计时器
|
|
13
|
+
|
|
14
|
+
// 检查队列埋点,是否超过上限需要马上发送或者启动计时器
|
|
15
|
+
function checkQueue(isSendFail: boolean): void {
|
|
16
|
+
if (!isSendFail && cacheArr.length >= max) {
|
|
17
|
+
batchSendData();
|
|
18
|
+
} else {
|
|
19
|
+
startTimer();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// 启动计时器
|
|
24
|
+
function startTimer(): void {
|
|
25
|
+
if (timer !== 0 || cacheArr.length === 0) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
timer = setTimeout(() => {
|
|
29
|
+
timer = 0;
|
|
30
|
+
batchSendData();
|
|
31
|
+
}, delay);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 停止计时器
|
|
35
|
+
function stopTimer(): void {
|
|
36
|
+
if (timer !== 0) {
|
|
37
|
+
clearTimeout(timer);
|
|
38
|
+
timer = 0;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 批量发送埋点
|
|
43
|
+
function batchSendData(): void {
|
|
44
|
+
if (cacheArr.length === 0) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const batch = cacheArr.splice(0, max);
|
|
49
|
+
const request = helper.getTms().createRequest();
|
|
50
|
+
request.post('basic/event/upload', { batch })
|
|
51
|
+
.then((res: any) => {
|
|
52
|
+
if (res.errCode !== 0) {
|
|
53
|
+
requestFail(batch);
|
|
54
|
+
} else {
|
|
55
|
+
startTimer();
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
.catch((e: any) => {
|
|
59
|
+
console.error(e);
|
|
60
|
+
requestFail(batch);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 发送失败就再加回队列
|
|
65
|
+
function requestFail(batch: DataItem[][]): void {
|
|
66
|
+
batch.forEach(item => cacheArr.push(item));
|
|
67
|
+
checkQueue(true);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 立刻发送埋点
|
|
72
|
+
* @param arr
|
|
73
|
+
*/
|
|
74
|
+
function send(arr: DataItem[]): void {
|
|
75
|
+
stopTimer();
|
|
76
|
+
cacheArr.unshift(helper.encodeItems(arr)); // 如果队列中很多,排前面比较稳妥
|
|
77
|
+
batchSendData();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* 添加埋点到队列中,等待聚合发送
|
|
82
|
+
* @param arr
|
|
83
|
+
*/
|
|
84
|
+
function queue(arr: DataItem[]): void {
|
|
85
|
+
cacheArr.push(helper.encodeItems(arr));
|
|
86
|
+
checkQueue(false);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// 小程序关闭时马上发送所有埋点
|
|
90
|
+
wx.onAppHide(() => {
|
|
91
|
+
stopTimer();
|
|
92
|
+
batchSendData();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
export default {
|
|
96
|
+
send,
|
|
97
|
+
queue,
|
|
98
|
+
};
|