@dcloudio/uni-stat 2.0.1-alpha-34320220401001 → 2.0.1-alpha-34520220408001

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.
@@ -0,0 +1,1268 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * 获取系统信息
5
+ */
6
+ const sys = uni.getSystemInfoSync();
7
+
8
+ // 访问开始即启动小程序,访问结束结分为:进入后台超过5min、在前台无任何操作超过30min、在新的来源打开小程序;
9
+ const STAT_VERSION = '0.0.1';
10
+ const STAT_URL = 'https://tongji.dcloud.io/uni/stat';
11
+ const STAT_H5_URL = 'https://tongji.dcloud.io/uni/stat.gif';
12
+ const PAGE_PVER_TIME = 1800; // 页面在前台无操作结束访问时间 单位s
13
+ const APP_PVER_TIME = 300; // 应用在后台结束访问时间 单位s
14
+ const OPERATING_TIME = 10; // 数据上报时间 单位s
15
+ const DIFF_TIME = 60 * 1000 * 60 * 24;
16
+
17
+ let statConfig = {
18
+ appid: ''
19
+ };
20
+ let titleJsons = {};
21
+
22
+ // #ifdef VUE3
23
+ statConfig.appid = process.env.UNI_APP_ID;
24
+ titleJsons = process.env.UNI_STAT_TITLE_JSON;
25
+ // #endif
26
+ // #ifndef VUE3
27
+ statConfig = require('uni-stat-config').default || require('uni-stat-config');
28
+ const pagesTitle = require('uni-pages?{"type":"style"}').default;
29
+ let pagesData = pagesTitle.pages;
30
+ for (let i in pagesData) {
31
+ const style = pagesData[i];
32
+ const titleText =
33
+ // MP
34
+ style.navigationBarTitleText ||
35
+ // ali
36
+ style.defaultTitle||
37
+ // H5 || App
38
+ style.navigationBar?.titleText ||
39
+ '';
40
+ if (titleText) {
41
+ titleJsons[i] = titleText;
42
+ }
43
+ }
44
+ // #endif
45
+
46
+
47
+ const UUID_KEY = '__DC_STAT_UUID';
48
+ const UUID_VALUE = '__DC_UUID_VALUE';
49
+
50
+ function getUuid() {
51
+ let uuid = '';
52
+ if (get_platform_name() === 'n') {
53
+ try {
54
+ uuid = plus.runtime.getDCloudId();
55
+ } catch (e) {
56
+ uuid = '';
57
+ }
58
+ return uuid
59
+ }
60
+
61
+ try {
62
+ uuid = uni.getStorageSync(UUID_KEY);
63
+ } catch (e) {
64
+ uuid = UUID_VALUE;
65
+ }
66
+
67
+ if (!uuid) {
68
+ uuid = Date.now() + '' + Math.floor(Math.random() * 1e7);
69
+ try {
70
+ uni.setStorageSync(UUID_KEY, uuid);
71
+ } catch (e) {
72
+ uni.setStorageSync(UUID_KEY, UUID_VALUE);
73
+ }
74
+ }
75
+ return uuid
76
+ }
77
+ /**
78
+ * 获取配置信息 如 appid
79
+ */
80
+ const stat_config = statConfig;
81
+
82
+ const get_uuid = (statData) => {
83
+ // 有可能不存在 deviceId(一般不存在就是出bug了),就自己生成一个
84
+ return sys.deviceId || getUuid()
85
+ };
86
+
87
+ const get_sgin = (statData) => {
88
+ let arr = Object.keys(statData);
89
+ let sortArr = arr.sort();
90
+ let sgin = {};
91
+ let sginStr = '';
92
+ for (var i in sortArr) {
93
+ sgin[sortArr[i]] = statData[sortArr[i]];
94
+ sginStr += sortArr[i] + '=' + statData[sortArr[i]] + '&';
95
+ }
96
+
97
+ return {
98
+ sign: '',
99
+ options: sginStr.substr(0, sginStr.length - 1),
100
+ }
101
+ };
102
+
103
+ const get_encodeURIComponent_options = (statData) => {
104
+ let data = {};
105
+ for (let prop in statData) {
106
+ data[prop] = encodeURIComponent(statData[prop]);
107
+ }
108
+ return data
109
+ };
110
+
111
+ /**
112
+ * 获取当前平台
113
+ * 移动端 : 'n',
114
+ * h5 : 'h5',
115
+ * 微信 : 'wx',
116
+ * 阿里 : 'ali',
117
+ * 百度 : 'bd',
118
+ * 头条 : 'tt',
119
+ * qq : 'qq',
120
+ * 快应用 : 'qn',
121
+ * 快手 : 'ks',
122
+ * 飞书 : 'lark',
123
+ * 快应用 : 'qw',
124
+ * 钉钉 : 'dt'
125
+ */
126
+ const get_platform_name = () => {
127
+ // 苹果审核代码中禁止出现 alipay 字样 ,需要特殊处理一下
128
+ const aliArr = ['y', 'a', 'p', 'mp-ali'];
129
+ const platformList = {
130
+ 'app': 'n',
131
+ 'app-plus': 'n',
132
+ h5: 'h5',
133
+ 'mp-weixin': 'wx',
134
+ [aliArr.reverse().join('')]: 'ali',
135
+ 'mp-baidu': 'bd',
136
+ 'mp-toutiao': 'tt',
137
+ 'mp-qq': 'qq',
138
+ 'quickapp-native': 'qn',
139
+ 'mp-kuaishou': 'ks',
140
+ 'mp-lark': 'lark',
141
+ 'quickapp-webview':'qw'
142
+ };
143
+ if(platformList[process.env.VUE_APP_PLATFORM] === 'ali'){
144
+ if(my&&my.env){
145
+ const clientName = my.env.clientName;
146
+ if(clientName === 'ap') return 'ali'
147
+ if(clientName === 'dingtalk') return 'dt'
148
+ // TODO 缺少 ali 下的其他平台
149
+ }
150
+ }
151
+ return platformList[process.env.VUE_APP_PLATFORM]
152
+ };
153
+
154
+ /**
155
+ * 获取小程序 appid
156
+ */
157
+ const get_pack_name = () => {
158
+ let packName = '';
159
+ if (get_platform_name() === 'wx' || get_platform_name() === 'qq') {
160
+ // 兼容微信小程序低版本基础库
161
+ if (uni.canIUse('getAccountInfoSync')) {
162
+ packName = uni.getAccountInfoSync().miniProgram.appId || '';
163
+ }
164
+ }
165
+ if (get_platform_name() === 'n') ;
166
+ return packName
167
+ };
168
+
169
+ /**
170
+ * 应用版本
171
+ */
172
+ const get_version = () => {
173
+ return get_platform_name() === 'n' ? plus.runtime.version : ''
174
+ };
175
+
176
+ /**
177
+ * 获取渠道
178
+ */
179
+ const get_channel = () => {
180
+ const platformName = get_platform_name();
181
+ let channel = '';
182
+ if (platformName === 'n') {
183
+ channel = plus.runtime.channel;
184
+ }
185
+ return channel
186
+ };
187
+
188
+ /**
189
+ * 获取小程序场景值
190
+ * @param {Object} options 页面信息
191
+ */
192
+ const get_scene = (options) => {
193
+ const platformName = get_platform_name();
194
+ let scene = '';
195
+ if (options) {
196
+ return options
197
+ }
198
+ if (platformName === 'wx') {
199
+ scene = uni.getLaunchOptionsSync().scene;
200
+ }
201
+ return scene
202
+ };
203
+
204
+ /**
205
+ * 获取拼接参数
206
+ */
207
+ const get_splicing = (data) => {
208
+ let str = '';
209
+ for (var i in data) {
210
+ str += i + '=' + data[i] + '&';
211
+ }
212
+ return str.substr(0, str.length - 1)
213
+ };
214
+
215
+ /**
216
+ * 获取页面url,不包含参数
217
+ */
218
+ const get_route = (pageVm) => {
219
+ let _self = pageVm || get_page_vm();
220
+ if (get_platform_name() === 'bd') {
221
+ let mp_route = _self.$mp && _self.$mp.page && _self.$mp.page.is;
222
+ let scope_route = _self.$scope && _self.$scope.is;
223
+ return mp_route || scope_route || ''
224
+ } else {
225
+ return _self.route || (_self.$scope && _self.$scope.route) || (_self.$mp && _self.$mp.page.route)
226
+ }
227
+ };
228
+
229
+ /**
230
+ * 获取页面url, 包含参数
231
+ */
232
+ const get_page_route = (pageVm) => {
233
+ // 从 app 进入应用 ,没有 $page ,获取不到路由 ,需要获取页面 尝试从 getCurrentPages 获取也页面实例
234
+ // FIXME 尽量不使用 getCurrentPages ,大部分获取路由是从 onHide 获取 ,这时可以获取到,如果是 onload ,则可能获取不到,比如 百度
235
+
236
+ let page = pageVm.$page || (pageVm.$scope && pageVm.$scope.$page);
237
+ let lastPageRoute = uni.getStorageSync('_STAT_LAST_PAGE_ROUTE');
238
+ if (!page) return lastPageRoute || ''
239
+ // 如果找不到 fullPath 就取 route 的值
240
+ return page.fullPath === '/' ? page.route : (page.fullPath||page.route)
241
+ };
242
+
243
+ /**
244
+ * 获取页面实例
245
+ */
246
+ const get_page_vm = () => {
247
+ let pages = getCurrentPages();
248
+ let $page = pages[pages.length - 1];
249
+ if (!$page) return null
250
+ return $page.$vm
251
+ };
252
+
253
+ /**
254
+ * 获取页面类型
255
+ */
256
+ const get_page_types = (self) => {
257
+ // XXX 百度有问题 ,获取的都是 componet ,等待修复
258
+ if (self.mpType === 'page' || self.$mpType === 'page' || (self.$mp && self.$mp.mpType === 'page') || self
259
+ .$options.mpType === 'page') {
260
+ return 'page';
261
+ }
262
+ if (self.mpType === 'app' || self.$mpType === 'app' || (self.$mp && self.$mp.mpType === 'app') || self.$options
263
+ .mpType === 'app') {
264
+ return 'app'
265
+ }
266
+ return null;
267
+ };
268
+
269
+ /**
270
+ * 处理上报参数
271
+ * @param {Object} 需要处理的数据
272
+ */
273
+ const handle_data = (statData) => {
274
+ let firstArr = [];
275
+ let contentArr = [];
276
+ let lastArr = [];
277
+ for (let i in statData) {
278
+ const rd = statData[i];
279
+ rd.forEach((elm) => {
280
+ const newData = get_splicing(elm);
281
+ if (i === 0) {
282
+ firstArr.push(newData);
283
+ } else if (i === 3) {
284
+ lastArr.push(newData);
285
+ } else {
286
+ contentArr.push(newData);
287
+ }
288
+ });
289
+ }
290
+
291
+ firstArr.push(...contentArr, ...lastArr);
292
+ // 参数需要处理成字符串,方便上传
293
+ return JSON.stringify(firstArr)
294
+ };
295
+
296
+
297
+ /**
298
+ * 自定义事件参数校验
299
+ */
300
+ const calibration = (eventName, options) => {
301
+ // login 、 share 、pay_success 、pay_fail 、register 、title
302
+ if (!eventName) {
303
+ console.error(`uni.report Missing [eventName] parameter`);
304
+ return true
305
+ }
306
+ if (typeof eventName !== 'string') {
307
+ console.error(`uni.report [eventName] Parameter type error, it can only be of type String`);
308
+ return true
309
+ }
310
+ if (eventName.length > 255) {
311
+ console.error(`uni.report [eventName] Parameter length cannot be greater than 255`);
312
+ return true
313
+ }
314
+
315
+ if (typeof options !== 'string' && typeof options !== 'object') {
316
+ console.error('uni.report [options] Parameter type error, Only supports String or Object type');
317
+ return true
318
+ }
319
+
320
+ if (typeof options === 'string' && options.length > 255) {
321
+ console.error(`uni.report [options] Parameter length cannot be greater than 255`);
322
+ return true
323
+ }
324
+
325
+ if (eventName === 'title' && typeof options !== 'string') {
326
+ console.error(
327
+ `uni.report [eventName] When the parameter is title, the [options] parameter can only be of type String`
328
+ );
329
+ return true
330
+ }
331
+ };
332
+
333
+ const get_page_name = (routepath) => {
334
+ return (titleJsons && titleJsons[routepath]) || ''
335
+ };
336
+
337
+ const Report_Data_Time = 'Report_Data_Time';
338
+ const Report_Status = 'Report_Status';
339
+ const is_report_data = () => {
340
+ return new Promise((resolve, reject) => {
341
+ let start_time = '';
342
+ let end_time = new Date().getTime();
343
+ let diff_time = DIFF_TIME;
344
+ let report_status = 1;
345
+ try {
346
+ start_time = uni.getStorageSync(Report_Data_Time);
347
+ report_status = uni.getStorageSync(Report_Status);
348
+ } catch (e) {
349
+ start_time = '';
350
+ report_status = 1;
351
+ }
352
+
353
+ if (report_status === '') {
354
+ requestData(({ enable }) => {
355
+ uni.setStorageSync(Report_Data_Time, end_time);
356
+ uni.setStorageSync(Report_Status, enable);
357
+ if (enable === 1) {
358
+ resolve();
359
+ }
360
+ });
361
+ return
362
+ }
363
+
364
+ if (report_status === 1) {
365
+ resolve();
366
+ }
367
+
368
+ if (!start_time) {
369
+ uni.setStorageSync(Report_Data_Time, end_time);
370
+ start_time = end_time;
371
+ }
372
+
373
+ if (end_time - start_time > diff_time) {
374
+ requestData(({ enable }) => {
375
+ uni.setStorageSync(Report_Data_Time, end_time);
376
+ uni.setStorageSync(Report_Status, enable);
377
+ });
378
+ }
379
+ })
380
+ };
381
+
382
+ const requestData = (done) => {
383
+ const appid = process.env.UNI_APP_ID;
384
+ let formData = {
385
+ usv: STAT_VERSION,
386
+ conf: JSON.stringify({
387
+ ak: appid,
388
+ }),
389
+ };
390
+ uni.request({
391
+ url: STAT_URL,
392
+ method: 'GET',
393
+ data: formData,
394
+ success: (res) => {
395
+ const { data } = res;
396
+ if (data.ret === 0) {
397
+ typeof done === 'function' &&
398
+ done({
399
+ enable: data.enable,
400
+ });
401
+ }
402
+ },
403
+ fail: (e) => {
404
+ let report_status_code = 1;
405
+ try {
406
+ report_status_code = uni.getStorageSync(Report_Status);
407
+ } catch (e) {
408
+ report_status_code = 1;
409
+ }
410
+ if (report_status_code === '') {
411
+ report_status_code = 1;
412
+ }
413
+ typeof done === 'function' &&
414
+ done({
415
+ enable: report_status_code,
416
+ });
417
+ },
418
+ });
419
+ };
420
+
421
+ let data = uni.getStorageSync('$$STAT__DBDATA') || {};
422
+ const dbSet = (name, value) => {
423
+ if (!data) {
424
+ data = {};
425
+ }
426
+ data[name] = value;
427
+ uni.setStorageSync('$$STAT__DBDATA', data);
428
+ };
429
+
430
+ const dbGet = (name) => {
431
+ if (!data[name]) {
432
+ let dbdata = uni.getStorageSync('$$STAT__DBDATA');
433
+ if (!dbdata) {
434
+ dbdata = {};
435
+ }
436
+ if (!dbdata[name]) {
437
+ return undefined
438
+ }
439
+ data[name] = dbdata[name];
440
+ }
441
+ return data[name]
442
+ };
443
+
444
+ const dbRemove = (name) => {
445
+ if (data[name]) {
446
+ delete data[name];
447
+ uni.setStorageSync('$$STAT__DBDATA', data);
448
+ } else {
449
+ data = uni.getStorageSync('$$STAT__DBDATA');
450
+ if (data[name]) {
451
+ delete data[name];
452
+ uni.setStorageSync('$$STAT__DBDATA', data);
453
+ }
454
+ }
455
+ };
456
+
457
+ // 首次访问时间
458
+ const FIRST_VISIT_TIME_KEY = '__first__visit__time';
459
+ // 最后访问时间
460
+ const LAST_VISIT_TIME_KEY = '__last__visit__time';
461
+ /**
462
+ * 获取当前时间
463
+ */
464
+ const get_time = () => {
465
+ return parseInt(new Date().getTime() / 1000)
466
+ };
467
+
468
+ /**
469
+ * 获取首次访问时间
470
+ */
471
+ const get_first_visit_time = () => {
472
+ const timeStorge = dbGet(FIRST_VISIT_TIME_KEY);
473
+ let time = 0;
474
+ if (timeStorge) {
475
+ time = timeStorge;
476
+ } else {
477
+ time = get_time();
478
+ dbSet(FIRST_VISIT_TIME_KEY, time);
479
+ // 首次访问需要 将最后访问时间置 0
480
+ dbRemove(LAST_VISIT_TIME_KEY);
481
+ }
482
+ return time
483
+ };
484
+
485
+ /**
486
+ * 最后访问时间
487
+ */
488
+ const get_last_visit_time = () => {
489
+ const timeStorge = dbGet(LAST_VISIT_TIME_KEY);
490
+ let time = 0;
491
+ if (timeStorge) {
492
+ time = timeStorge;
493
+ }
494
+ dbSet(LAST_VISIT_TIME_KEY, get_time());
495
+ return time
496
+ };
497
+
498
+ // 页面停留时间记录key
499
+ const PAGE_RESIDENCE_TIME = '__page__residence__time';
500
+ let First_Page_Residence_Time = 0;
501
+ let Last_Page_Residence_Time = 0;
502
+
503
+ /**
504
+ * 设置页面停留时间
505
+ */
506
+ const set_page_residence_time = () => {
507
+ First_Page_Residence_Time = get_time();
508
+ dbSet(PAGE_RESIDENCE_TIME, First_Page_Residence_Time);
509
+ return First_Page_Residence_Time
510
+ };
511
+
512
+ /**
513
+ * 获取页面停留时间
514
+ */
515
+ const get_page_residence_time = () => {
516
+ Last_Page_Residence_Time = get_time();
517
+ First_Page_Residence_Time = dbGet(PAGE_RESIDENCE_TIME);
518
+ return Last_Page_Residence_Time - First_Page_Residence_Time
519
+ };
520
+
521
+ /**
522
+ * 获取总访问次数
523
+ */
524
+ const TOTAL_VISIT_COUNT = '__total__visit__count';
525
+ const get_total_visit_count = () => {
526
+ const timeStorge = dbGet(TOTAL_VISIT_COUNT);
527
+ let count = 1;
528
+ if (timeStorge) {
529
+ count = timeStorge;
530
+ count++;
531
+ }
532
+ dbSet(TOTAL_VISIT_COUNT, count);
533
+ return count
534
+ };
535
+
536
+ let Set__First__Time = 0;
537
+ let Set__Last__Time = 0;
538
+
539
+ /**
540
+ * 获取第一次时间
541
+ */
542
+ const get_first_time = () => {
543
+ let time = new Date().getTime();
544
+ Set__First__Time = time;
545
+ Set__Last__Time = 0;
546
+ return time
547
+ };
548
+
549
+ /**
550
+ * 获取最后一次时间
551
+ */
552
+ const get_last_time = () => {
553
+ let time = new Date().getTime();
554
+ Set__Last__Time = time;
555
+ return time
556
+ };
557
+
558
+ /**
559
+ * 获取页面 \ 应用停留时间
560
+ */
561
+ const get_residence_time = (type) => {
562
+ let residenceTime = 0;
563
+ if (Set__First__Time !== 0) {
564
+ residenceTime = Set__Last__Time - Set__First__Time;
565
+ }
566
+
567
+ residenceTime = parseInt(residenceTime / 1000);
568
+ residenceTime = residenceTime < 1 ? 1 : residenceTime;
569
+ if (type === 'app') {
570
+ let overtime = residenceTime > APP_PVER_TIME ? true : false;
571
+ return {
572
+ residenceTime,
573
+ overtime,
574
+ }
575
+ }
576
+ if (type === 'page') {
577
+ let overtime = residenceTime > PAGE_PVER_TIME ? true : false;
578
+ return {
579
+ residenceTime,
580
+ overtime,
581
+ }
582
+ }
583
+ return {
584
+ residenceTime,
585
+ }
586
+ };
587
+
588
+ // 统计数据默认值
589
+ let statData = {
590
+ uuid: get_uuid(), // 设备标识
591
+ ut: get_platform_name(), // 平台类型
592
+ mpn: get_pack_name(), // 原生平台包名、小程序 appid
593
+ ak: stat_config.appid, // uni-app 应用 Appid
594
+ usv: STAT_VERSION, // 统计 sdk 版本
595
+ v: get_version(), // 应用版本,仅app
596
+ ch: get_channel(), // 渠道信息
597
+ cn: '', // 国家
598
+ pn: '', // 省份
599
+ ct: '', // 城市
600
+ t: get_time(), // 上报数据时的时间戳
601
+ tt: '',
602
+ p: sys.platform === 'android' ? 'a' : 'i', // 手机系统
603
+ brand: sys.brand || '', // 手机品牌
604
+ md: sys.model, // 手机型号
605
+ sv: sys.system.replace(/(Android|iOS)\s/, ''), // 手机系统版本
606
+ mpsdk: sys.SDKVersion || '', // x程序 sdk version
607
+ mpv: sys.version || '', // 小程序平台版本 ,如微信、支付宝
608
+ lang: sys.language, // 语言
609
+ pr: sys.pixelRatio, // pixelRatio 设备像素比
610
+ ww: sys.windowWidth, // windowWidth 可使用窗口宽度
611
+ wh: sys.windowHeight, // windowHeight 可使用窗口高度
612
+ sw: sys.screenWidth, // screenWidth 屏幕宽度
613
+ sh: sys.screenHeight, // screenHeight 屏幕高度
614
+ };
615
+ class Report {
616
+ constructor() {
617
+ // 页面实例
618
+ this.self = '';
619
+ // 进入应用标识
620
+ this.__licationShow = false;
621
+ // 离开应用标识
622
+ this.__licationHide = false;
623
+ // 统计默认值
624
+ this.statData = statData;
625
+ // 标题默认值
626
+ this._navigationBarTitle = {
627
+ config: '',
628
+ page: '',
629
+ report: '',
630
+ lt: '',
631
+ };
632
+
633
+ // 页面参数
634
+ this._query = {};
635
+ // 页面最后停留页面的 url
636
+ // this._lastPageRoute = ''
637
+
638
+ // 注册拦截器
639
+ let registerInterceptor = typeof uni.addInterceptor === 'function';
640
+ if (registerInterceptor) {
641
+ this.addInterceptorInit();
642
+ this.interceptLogin();
643
+ this.interceptShare(true);
644
+ this.interceptRequestPayment();
645
+ }
646
+ }
647
+
648
+ addInterceptorInit() {
649
+ let self = this;
650
+ uni.addInterceptor('setNavigationBarTitle', {
651
+ invoke(args) {
652
+ self._navigationBarTitle.page = args.title;
653
+ },
654
+ });
655
+ }
656
+
657
+ interceptLogin() {
658
+ let self = this;
659
+ uni.addInterceptor('login', {
660
+ complete() {
661
+ self._login();
662
+ },
663
+ });
664
+ }
665
+
666
+ interceptShare(type) {
667
+ let self = this;
668
+ if (!type) {
669
+ self._share();
670
+ return
671
+ }
672
+ uni.addInterceptor('share', {
673
+ success() {
674
+ self._share();
675
+ },
676
+ fail() {
677
+ self._share();
678
+ },
679
+ });
680
+ }
681
+
682
+ interceptRequestPayment() {
683
+ let self = this;
684
+ uni.addInterceptor('requestPayment', {
685
+ success() {
686
+ self._payment('pay_success');
687
+ },
688
+ fail() {
689
+ self._payment('pay_fail');
690
+ },
691
+ });
692
+ }
693
+
694
+ _login() {
695
+ this.sendEventRequest({
696
+ key: 'login',
697
+ },
698
+ 0
699
+ );
700
+ }
701
+
702
+ _share() {
703
+ this.sendEventRequest({
704
+ key: 'share',
705
+ }, 0);
706
+ }
707
+ _payment(key) {
708
+ this.sendEventRequest({
709
+ key,
710
+ }, 0);
711
+ }
712
+
713
+ /**
714
+ * 进入应用触发
715
+ */
716
+ applicationShow() {
717
+ // 通过 __licationHide 判断保证是进入后台后在次进入应用,避免重复上报数据
718
+ if (this.__licationHide) {
719
+ get_last_time();
720
+ const time = get_residence_time('app');
721
+ // 需要判断进入后台是否超过时限 ,默认是 30min ,是的话需要执行进入应用的上报
722
+ if (time.overtime) {
723
+ let lastPageRoute = uni.getStorageSync('_STAT_LAST_PAGE_ROUTE');
724
+ let options = {
725
+ path: lastPageRoute,
726
+ scene: this.statData.sc,
727
+ };
728
+ this.sendReportRequest(options);
729
+ }
730
+ // 状态重置
731
+ this.__licationHide = false;
732
+ }
733
+ }
734
+
735
+ /**
736
+ * 离开应用触发
737
+ * @param {Object} self
738
+ * @param {Object} type
739
+ */
740
+ applicationHide(self, type) {
741
+ if(!self){
742
+ // 表示应用切换到后台 ,此时需要从页面栈获取页面实例
743
+ self = get_page_vm();
744
+ }
745
+ // 进入应用后台保存状态,方便进入前台后判断是否上报应用数据
746
+ this.__licationHide = true;
747
+ get_last_time();
748
+ const time = get_residence_time();
749
+ const route = get_page_route(self);
750
+ uni.setStorageSync('_STAT_LAST_PAGE_ROUTE', route);
751
+ this.sendHideRequest({
752
+ urlref: route,
753
+ urlref_ts: time.residenceTime,
754
+ },
755
+ type
756
+ );
757
+ // 重置时间
758
+ get_first_time();
759
+ }
760
+
761
+ /**
762
+ * 进入页面触发
763
+ */
764
+ pageShow(self) {
765
+ // 清空值 ,初始化 ,避免污染后面的上报数据
766
+ this._navigationBarTitle = {
767
+ config: '',
768
+ page: '',
769
+ report: '',
770
+ lt: '',
771
+ };
772
+
773
+ const route = get_page_route(self);
774
+ const routepath = get_route(self);
775
+
776
+ this._navigationBarTitle.config = get_page_name(routepath);
777
+ // 表示应用触发 ,页面切换不触发之后的逻辑
778
+ if (this.__licationShow) {
779
+ get_first_time();
780
+ // this._lastPageRoute = route
781
+ uni.setStorageSync('_STAT_LAST_PAGE_ROUTE', route);
782
+ this.__licationShow = false;
783
+ return
784
+ }
785
+
786
+ get_last_time();
787
+
788
+ const time = get_residence_time('page');
789
+ // 停留时间
790
+ if (time.overtime) {
791
+ let options = {
792
+ path: route,
793
+ scene: this.statData.sc,
794
+ };
795
+ this.sendReportRequest(options);
796
+ }
797
+ // 重置时间
798
+ get_first_time();
799
+ }
800
+
801
+ /**
802
+ * 离开页面触发
803
+ */
804
+ pageHide(self) {
805
+ if (!this.__licationHide) {
806
+ get_last_time();
807
+ const time = get_residence_time('page');
808
+ let route = get_page_route(self);
809
+ let lastPageRoute = uni.getStorageSync('_STAT_LAST_PAGE_ROUTE');
810
+ if (!lastPageRoute) {
811
+ lastPageRoute = route;
812
+ }
813
+ uni.setStorageSync('_STAT_LAST_PAGE_ROUTE', route);
814
+ this.sendPageRequest({
815
+ url: route,
816
+ urlref: lastPageRoute,
817
+ urlref_ts: time.residenceTime,
818
+ });
819
+ // this._lastPageRoute = route
820
+ return
821
+ }
822
+ }
823
+
824
+
825
+ /**
826
+ * 发送请求,应用维度上报
827
+ * @param {Object} options 页面信息
828
+ */
829
+ sendReportRequest(options) {
830
+ this._navigationBarTitle.lt = '1';
831
+ this._navigationBarTitle.config = get_page_name(options.path);
832
+ let is_opt = options.query && JSON.stringify(options.query) !== '{}';
833
+ let query = is_opt ? '?' + JSON.stringify(options.query) : '';
834
+ Object.assign(this.statData, {
835
+ lt: '1',
836
+ url: (options.path + query) || '',
837
+ t: get_time(),
838
+ sc: get_scene(options.scene),
839
+ fvts: get_first_visit_time(),
840
+ lvts: get_last_visit_time(),
841
+ tvc: get_total_visit_count()
842
+ });
843
+ if (get_platform_name() === 'n') {
844
+ this.getProperty();
845
+ } else {
846
+ this.getNetworkInfo();
847
+ }
848
+ }
849
+
850
+ /**
851
+ * 发送请求,页面维度上报
852
+ * @param {Object} opt
853
+ */
854
+ sendPageRequest(opt) {
855
+ let {
856
+ url,
857
+ urlref,
858
+ urlref_ts
859
+ } = opt;
860
+ this._navigationBarTitle.lt = '11';
861
+ let options = {
862
+ ak: this.statData.ak,
863
+ uuid: this.statData.uuid,
864
+ lt: '11',
865
+ ut: this.statData.ut,
866
+ url,
867
+ tt: this.statData.tt,
868
+ urlref,
869
+ urlref_ts,
870
+ ch: this.statData.ch,
871
+ usv: this.statData.usv,
872
+ t: get_time(),
873
+ p: this.statData.p,
874
+ };
875
+ this.request(options);
876
+ }
877
+
878
+ /**
879
+ * 进入后台上报数据
880
+ * @param {Object} opt
881
+ * @param {Object} type
882
+ */
883
+ sendHideRequest(opt, type) {
884
+ let {
885
+ urlref,
886
+ urlref_ts
887
+ } = opt;
888
+ let options = {
889
+ ak: this.statData.ak,
890
+ uuid: this.statData.uuid,
891
+ lt: '3',
892
+ ut: this.statData.ut,
893
+ urlref,
894
+ urlref_ts,
895
+ ch: this.statData.ch,
896
+ usv: this.statData.usv,
897
+ t: get_time(),
898
+ p: this.statData.p,
899
+ };
900
+ this.request(options, type);
901
+ }
902
+
903
+ /**
904
+ * 自定义事件上报
905
+ */
906
+ sendEventRequest({
907
+ key = '',
908
+ value = ''
909
+ } = {}) {
910
+ // const route = this._lastPageRoute
911
+ const routepath = get_route();
912
+ this._navigationBarTitle.config = get_page_name(routepath);
913
+ this._navigationBarTitle.lt = '21';
914
+ let options = {
915
+ ak: this.statData.ak,
916
+ uuid: this.statData.uuid,
917
+ lt: '21',
918
+ ut: this.statData.ut,
919
+ url: routepath,
920
+ ch: this.statData.ch,
921
+ e_n: key,
922
+ e_v: typeof value === 'object' ? JSON.stringify(value) : value.toString(),
923
+ usv: this.statData.usv,
924
+ t: get_time(),
925
+ p: this.statData.p,
926
+ };
927
+ this.request(options);
928
+ }
929
+
930
+ /**
931
+ * 获取wgt资源版本
932
+ */
933
+ getProperty() {
934
+ plus.runtime.getProperty(plus.runtime.appid, (wgtinfo) => {
935
+ this.statData.v = wgtinfo.version || '';
936
+ this.getNetworkInfo();
937
+ });
938
+ }
939
+
940
+ /**
941
+ * 获取网络信息
942
+ */
943
+ getNetworkInfo() {
944
+ uni.getNetworkType({
945
+ success: (result) => {
946
+ this.statData.net = result.networkType;
947
+ this.getLocation();
948
+ },
949
+ });
950
+ }
951
+
952
+ /**
953
+ * 获取位置信息
954
+ */
955
+ getLocation() {
956
+ if (stat_config.getLocation) {
957
+ uni.getLocation({
958
+ type: 'wgs84',
959
+ geocode: true,
960
+ success: (result) => {
961
+ if (result.address) {
962
+ this.statData.cn = result.address.country;
963
+ this.statData.pn = result.address.province;
964
+ this.statData.ct = result.address.city;
965
+ }
966
+
967
+ this.statData.lat = result.latitude;
968
+ this.statData.lng = result.longitude;
969
+ this.request(this.statData);
970
+ },
971
+ });
972
+ } else {
973
+ this.statData.lat = 0;
974
+ this.statData.lng = 0;
975
+ this.request(this.statData);
976
+ }
977
+ }
978
+
979
+ /**
980
+ * 发送请求
981
+ * @param {Object} data 上报数据
982
+ * @param {Object} type 类型
983
+ */
984
+ request(data, type) {
985
+ let time = get_time();
986
+ const title = this._navigationBarTitle;
987
+ Object.assign(data, {
988
+ ttn: title.page,
989
+ ttpj: title.config,
990
+ ttc: title.report
991
+ });
992
+
993
+ let uniStatData = dbGet('__UNI__STAT__DATA') || {};
994
+ if (!uniStatData[data.lt]) {
995
+ uniStatData[data.lt] = [];
996
+ }
997
+ // 加入队列
998
+ uniStatData[data.lt].push(data);
999
+ dbSet('__UNI__STAT__DATA', uniStatData);
1000
+
1001
+ let page_residence_time = get_page_residence_time();
1002
+ // 判断时候到达上报时间 ,默认 10 秒上报
1003
+ if (page_residence_time < OPERATING_TIME && !type) return
1004
+
1005
+ // 时间超过,重新获取时间戳
1006
+ set_page_residence_time();
1007
+ const stat_data = handle_data(uniStatData);
1008
+ let optionsData = {
1009
+ usv: STAT_VERSION, //统计 SDK 版本号
1010
+ t: time, //发送请求时的时间戮
1011
+ requests: stat_data,
1012
+ };
1013
+
1014
+ // 重置队列
1015
+ dbRemove('__UNI__STAT__DATA');
1016
+
1017
+ // XXX 安卓需要延迟上报 ,否则会有未知错误,需要验证处理
1018
+ if (get_platform_name() === 'n' && this.statData.p === 'a') {
1019
+ setTimeout(() => {
1020
+ this.sendRequest(optionsData);
1021
+ }, 200);
1022
+ return
1023
+ }
1024
+
1025
+ this.sendRequest(optionsData);
1026
+ }
1027
+
1028
+ getIsReportData(){
1029
+ return is_report_data()
1030
+ }
1031
+
1032
+ /**
1033
+ * 数据上报
1034
+ * @param {Object} optionsData 需要上报的数据
1035
+ */
1036
+ sendRequest(optionsData) {
1037
+ {
1038
+ if (!uniCloud.config) {
1039
+ console.error('当前尚未绑定服务空间.');
1040
+ return
1041
+ }
1042
+ uniCloud.callFunction({
1043
+ name: 'uni-stat-report',
1044
+ data: optionsData,
1045
+ success: (res) => {},
1046
+ fail: (err) => {}
1047
+ });
1048
+ }
1049
+ }
1050
+
1051
+ /**
1052
+ * h5 请求
1053
+ */
1054
+ imageRequest(data) {
1055
+ this.getIsReportData().then(() => {
1056
+ let image = new Image();
1057
+ let options = get_sgin(get_encodeURIComponent_options(data)).options;
1058
+ image.src = STAT_H5_URL + '?' + options;
1059
+ });
1060
+ }
1061
+
1062
+ sendEvent(key, value) {
1063
+ // 校验 type 参数
1064
+ if (calibration(key, value)) return
1065
+
1066
+ if (key === 'title') {
1067
+ this._navigationBarTitle.report = value;
1068
+ return
1069
+ }
1070
+ this.sendEventRequest({
1071
+ key,
1072
+ value: typeof value === 'object' ? JSON.stringify(value) : value,
1073
+ },
1074
+ 1
1075
+ );
1076
+ }
1077
+ }
1078
+
1079
+ class Stat extends Report {
1080
+ static getInstance() {
1081
+ if (!uni.__stat_instance) {
1082
+ uni.__stat_instance = new Stat();
1083
+ }
1084
+ return uni.__stat_instance
1085
+ }
1086
+ constructor() {
1087
+ super();
1088
+ }
1089
+
1090
+ /**
1091
+ * 进入应用
1092
+ * @param {Object} options 页面参数
1093
+ * @param {Object} self 当前页面实例
1094
+ */
1095
+ launch(options, self) {
1096
+ // 初始化页面停留时间 start
1097
+ set_page_residence_time();
1098
+ this.__licationShow = true;
1099
+ this.sendReportRequest(options, true);
1100
+ }
1101
+ load(options, self) {
1102
+ this.self = self;
1103
+ this._query = options;
1104
+ }
1105
+
1106
+ appHide(self){
1107
+ this.applicationHide(self, true);
1108
+ }
1109
+
1110
+ appShow(self){
1111
+ this.applicationShow(self);
1112
+ }
1113
+
1114
+ show(self) {
1115
+ this.self = self;
1116
+ if (get_page_types(self) === 'page') {
1117
+ this.pageShow(self);
1118
+ }
1119
+
1120
+ // #ifdef VUE3
1121
+ if (get_platform_name() !== 'h5' && get_platform_name() !== 'n') {
1122
+ if (get_page_types(self) === 'app') {
1123
+ this.appShow();
1124
+ }
1125
+ }
1126
+ // #endif
1127
+
1128
+ // #ifndef VUE3
1129
+ if (get_page_types(self) === 'app') {
1130
+ this.appShow();
1131
+ }
1132
+ // #endif
1133
+
1134
+ }
1135
+
1136
+ hide(self) {
1137
+ this.self = self;
1138
+ if (get_page_types(self) === 'page') {
1139
+ this.pageHide(self);
1140
+ }
1141
+
1142
+ // #ifdef VUE3
1143
+ if (get_platform_name() !== 'h5' && get_platform_name() !== 'n') {
1144
+ if (get_page_types(self) === 'app') {
1145
+ this.appHide();
1146
+ }
1147
+ }
1148
+ // #endif
1149
+
1150
+ // #ifndef VUE3
1151
+ if (get_page_types(self) === 'app') {
1152
+ this.appHide();
1153
+ }
1154
+ // #endif
1155
+
1156
+ }
1157
+
1158
+ error(em) {
1159
+ // 开发工具内不上报错误
1160
+ if (this._platform === 'devtools') {
1161
+ if (process.env.NODE_ENV === 'development') {
1162
+ console.info('当前运行环境为开发者工具,不上报数据。');
1163
+ return;
1164
+ }
1165
+ }
1166
+ let emVal = '';
1167
+ if (!em.message) {
1168
+ emVal = JSON.stringify(em);
1169
+ } else {
1170
+ emVal = em.stack;
1171
+ }
1172
+ let options = {
1173
+ ak: this.statData.ak,
1174
+ uuid: this.statData.uuid,
1175
+ lt: '31',
1176
+ ut: this.statData.ut,
1177
+ ch: this.statData.ch,
1178
+ mpsdk: this.statData.mpsdk,
1179
+ mpv: this.statData.mpv,
1180
+ v: this.statData.v,
1181
+ em: emVal,
1182
+ usv: this.statData.usv,
1183
+ t: parseInt(new Date().getTime() / 1000),
1184
+ p: this.statData.p,
1185
+ };
1186
+ this.request(options);
1187
+ }
1188
+ }
1189
+ var Stat$1 = Stat;
1190
+
1191
+ const stat = Stat$1.getInstance();
1192
+
1193
+ // 用于判断是隐藏页面还是卸载页面
1194
+ let isHide = false;
1195
+
1196
+ const lifecycle = {
1197
+ onLaunch(options) {
1198
+ // 进入应用上报数据
1199
+ stat.launch(options, this);
1200
+ },
1201
+ onLoad(options) {
1202
+ stat.load(options, this);
1203
+ // 重写分享,获取分享上报事件
1204
+ if (this.$scope && this.$scope.onShareAppMessage) {
1205
+ let oldShareAppMessage = this.$scope.onShareAppMessage;
1206
+ this.$scope.onShareAppMessage = function(options) {
1207
+ stat.interceptShare(false);
1208
+ return oldShareAppMessage.call(this, options)
1209
+ };
1210
+ }
1211
+ },
1212
+ onShow() {
1213
+ isHide = false;
1214
+ stat.show(this);
1215
+ },
1216
+ onHide() {
1217
+ isHide = true;
1218
+ stat.hide(this);
1219
+ },
1220
+ onUnload() {
1221
+ if (isHide) {
1222
+ isHide = false;
1223
+ return
1224
+ }
1225
+ stat.hide(this);
1226
+ },
1227
+ onError(e) {
1228
+ stat.error(e);
1229
+ }
1230
+ };
1231
+
1232
+
1233
+ function main() {
1234
+ {
1235
+ console.log('uni统计开启,version:2');
1236
+ }
1237
+ if (process.env.NODE_ENV === 'development') {
1238
+ uni.report = function(type, options) {};
1239
+ } else {
1240
+ // #ifdef VUE3
1241
+ uni.onCreateVueApp((app) => {
1242
+ app.mixin(lifecycle);
1243
+ uni.report = function(type, options) {
1244
+ stat.sendEvent(type, options);
1245
+ };
1246
+ });
1247
+
1248
+ if (get_platform_name() !== 'h5' && get_platform_name() !== 'n') {
1249
+ uni.onAppHide(() => {
1250
+ stat.appHide(get_page_vm());
1251
+ });
1252
+ uni.onAppShow(() => {
1253
+ stat.appShow(get_page_vm());
1254
+ });
1255
+ }
1256
+ // #endif
1257
+
1258
+ // #ifndef VUE3
1259
+ const Vue = require('vue');
1260
+ (Vue.default || Vue).mixin(lifecycle);
1261
+ uni.report = function(type, options) {
1262
+ stat.sendEvent(type, options);
1263
+ };
1264
+ // #endif
1265
+ }
1266
+ }
1267
+
1268
+ main();