@dcloudio/uni-stat 2.0.2-5000720260410001 → 2.0.2-5010520260709001

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.
@@ -1,9 +1,18 @@
1
1
  'use strict';
2
2
 
3
3
  /**
4
- * 获取系统信息
4
+ * 老版本兼容,系统信息
5
5
  */
6
- const sys = uni.getSystemInfoSync();
6
+ const sys = uni.getSystemInfoSync();
7
+ // /**
8
+ // * app基础信息
9
+ // */
10
+ // export const baseInfo = uni.getAppBaseInfo()
11
+
12
+ // /**
13
+ // * 设备相关
14
+ // */
15
+ // export const deviceInfo = uni.getDeviceInfo()
7
16
 
8
17
  // 访问开始即启动小程序,访问结束结分为:进入后台超过5min、在前台无任何操作超过30min、在新的来源打开小程序;
9
18
  const STAT_VERSION = process.env.UNI_COMPILER_VERSION;
@@ -14,6 +23,409 @@ const APP_PVER_TIME = 300; // 应用在后台结束访问时间 单位s
14
23
  const OPERATING_TIME = 10; // 数据上报时间 单位s
15
24
  const DIFF_TIME = 60 * 1000 * 60 * 24;
16
25
 
26
+ /**
27
+ * 事件类型与会话创建类型常量。
28
+ *
29
+ * 与私有版 / 文档 `uni统计上报参数.md` 的兼容关系:
30
+ * - 上行参数文档明确:`lt` 仅取 `1 / 3 / 11 / 21 / 31 / 41`,**没有** `lt=0`。
31
+ * - 历史架构文档(03-公有版架构设计.md §3.2)曾设计 `lt=0` 作为"客户端 session 边界"事件,
32
+ * 但与服务端入库口径不一致(会话日志 = lt=1),已**整体移除**:
33
+ * 新会话直接发一条 lt=1,会话字段(`sid / cst / fvts / lvts / tvc`)随 lt=1 上行。
34
+ * - 因此 `LT` 不再包含 `Session`;删除 lt=0 不影响老接收端。
35
+ */
36
+ /**
37
+ * Log Type(事件类型)。统一在此声明,禁止其他模块裸写字符串。
38
+ *
39
+ * 注:`lt=41`(uni-app x 原生崩溃日志)暂未在公有版实现,详见 `docs/暂未实现字段说明.md`。
40
+ */
41
+ const LT = {
42
+ Launch: '1',
43
+ Hide: '3',
44
+ Page: '11',
45
+ Event: '21',
46
+ Error: '31',
47
+ Push: '101',
48
+ };
49
+
50
+ /******************************************************************************
51
+ Copyright (c) Microsoft Corporation.
52
+
53
+ Permission to use, copy, modify, and/or distribute this software for any
54
+ purpose with or without fee is hereby granted.
55
+
56
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
57
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
58
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
59
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
60
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
61
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
62
+ PERFORMANCE OF THIS SOFTWARE.
63
+ ***************************************************************************** */
64
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
65
+
66
+
67
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
68
+ var e = new Error(message);
69
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
70
+ };
71
+
72
+ /**
73
+ * 安全工具集:序列化、try 包裹、指数退避重试。
74
+ *
75
+ * 修复缺陷:
76
+ * - #1 `_retry` 未初始化导致重试链路 NaN(公有版直接以参数显式传 `times`)。
77
+ * - #7 取值反向(私有版 `if (data.length > MAX_LENGTH)` 误判)。
78
+ * - #8 循环引用导致 `JSON.stringify` 抛错(用 WeakSet replacer 兜底)。
79
+ */
80
+ const DEFAULT_MAX_LENGTH = 4096;
81
+ const TRUNCATED_SUFFIX = '…[truncated]';
82
+ /**
83
+ * 序列化任意值为字符串:支持循环引用与最大长度截断。
84
+ *
85
+ * @param value 待序列化的值。`undefined` 返回 '';string 直接返回(仍参与截断)。
86
+ * @param max 字符串最大长度,默认 4096;超长会截断并附 `…[truncated]`。
87
+ */
88
+ function safeStringify(value, max = DEFAULT_MAX_LENGTH) {
89
+ var _a;
90
+ if (value === undefined)
91
+ return '';
92
+ let raw;
93
+ if (typeof value === 'string') {
94
+ raw = value;
95
+ }
96
+ else {
97
+ const seen = new WeakSet();
98
+ try {
99
+ raw =
100
+ (_a = JSON.stringify(value, (_key, val) => {
101
+ if (typeof val === 'object' && val !== null) {
102
+ if (seen.has(val))
103
+ return '[Circular]';
104
+ seen.add(val);
105
+ }
106
+ if (typeof val === 'bigint')
107
+ return val.toString();
108
+ if (typeof val === 'function')
109
+ return `[Function ${val.name || 'anonymous'}]`;
110
+ return val;
111
+ })) !== null && _a !== void 0 ? _a : '';
112
+ }
113
+ catch (e) {
114
+ raw = `[Unserializable: ${e.message}]`;
115
+ }
116
+ }
117
+ if (raw.length > max) {
118
+ return (raw.slice(0, Math.max(0, max - TRUNCATED_SUFFIX.length)) +
119
+ TRUNCATED_SUFFIX);
120
+ }
121
+ return raw;
122
+ }
123
+
124
+ /**
125
+ * 解析 uni-app 运行时根对象 `uni`。
126
+ *
127
+ * - H5 / App:常见为 `globalThis.uni`。
128
+ * - 微信小程序等:多为 Vite/rollup 向**当前模块**注入的标识符 `uni`,
129
+ * **未必**同步挂到 `globalThis`;仅读 `globalThis.uni` 会导致
130
+ * `bindLifecycle` / `uni.request` / storage 等全部静默失败。
131
+ * - 支付宝等旧版小程序:**无 `globalThis` 标识符**,须用 `getGlobalObject()` 兜底。
132
+ * - H5 发行摇树:`pages.json.js` 会先把 `window.uni = {}` 占位;若仍按「有 object 即用」
133
+ * 会误把空桩当真 uni。须用 `isUsableUniRuntime` 过滤后再择源。
134
+ *
135
+ * 第二路依赖宿主构建对 `uni` 的注入(与业务页面同一套解析规则),
136
+ * 类型兜底见 `packages/uni-stat/src/uni-global.d.ts`。
137
+ */
138
+ /**
139
+ * 判断候选 `uni` 是否具备统计 SDK 可用的最小 API 集合(排除 H5 摇树空桩 `{}`)。
140
+ *
141
+ * 任一核心 API 存在即视为可用;与具体平台无关,微信/QQ/抖音/支付宝/百度等
142
+ * 完整 runtime 均满足,仅「占位空对象」会被过滤。
143
+ */
144
+ /**
145
+ * H5 兜底:在 `globalThis` / `self` 不可用时尝试读取 `window`。
146
+ *
147
+ * 通过 `Function` 间接访问,避免 ESLint `no-restricted-globals` 对 `window` 标识符的限制;
148
+ * 小程序等环境执行失败时返回 `undefined`。
149
+ */
150
+ function getWindowObject() {
151
+ try {
152
+ const w = Function('return typeof window !== "undefined" ? window : undefined')();
153
+ return w != null ? w : undefined;
154
+ }
155
+ catch (_a) {
156
+ return undefined;
157
+ }
158
+ }
159
+ /**
160
+ * 安全获取全局对象。
161
+ *
162
+ * 支付宝 / 部分旧版小程序运行时未提供 `globalThis`,直接写 `globalThis` 会
163
+ * `ReferenceError: globalThis is not defined`,导致 install 阶段整包崩溃。
164
+ */
165
+ function getGlobalObject() {
166
+ if (typeof globalThis !== 'undefined' && globalThis != null) {
167
+ return globalThis;
168
+ }
169
+ if (typeof global !== 'undefined' && global != null) {
170
+ return global;
171
+ }
172
+ if (typeof self !== 'undefined' && self != null) {
173
+ return self;
174
+ }
175
+ const win = getWindowObject();
176
+ if (win)
177
+ return win;
178
+ return {};
179
+ }
180
+
181
+ /**
182
+ * 公有版统一日志出口。
183
+ *
184
+ * 修复的私有版缺陷:
185
+ * - #19 `!!process.env.UNI_STAT_DEBUG` 在构建时若被替换为字符串 `"false"` 仍是 truthy。
186
+ * 公有版严格使用 `=== 'true'` 判定,并允许在运行时通过 `setDebug()` 临时打开
187
+ * (供调试 / 灰度小流量验证)。
188
+ *
189
+ * 行为约定:
190
+ * - `debug` 受调试开关控制;其他 level 始终输出到对应的 `console.*`。
191
+ * - **Android / iOS 真机**:`TAG` 与正文拼成单条字符串,避免桥接丢弃第二参起。
192
+ * - **其它平台**:`console.*(TAG, ...args)`,对象保持原生传递。
193
+ *
194
+ * 兼容性:
195
+ * - 历史版本插件 define 误把 `process.env.UNI_STAT_DEBUG` 替换成布尔字面量
196
+ * (未 `JSON.stringify`),导致 dist 运行时该值为 `true`/`false` 而非 `'true'`/`'false'`。
197
+ * `isDebug()` 同时接受字符串 `'true'` 与布尔字面量 `true`,避免历史构建产物完全失效。
198
+ */
199
+ const TAG = '[uni统计 2.0]';
200
+ let runtimeDebug;
201
+ /**
202
+ * 是否屏蔽 info / warn / error。
203
+ * `undefined`:自动——`NODE_ENV === 'test'` 时默认屏蔽,避免 Jest 用例预期失败路径刷屏。
204
+ */
205
+ let muteNonDebug;
206
+ /**
207
+ * 是否将日志合并为单行(Android / iOS 真机侧)。
208
+ */
209
+ function preferSingleLineConsole() {
210
+ return isAndroidOrIosRuntime();
211
+ }
212
+ /**
213
+ * 是否为 App 或小程序运行在 **Android / iOS** 上(仅此类环境对对象参数做字符串化)。
214
+ */
215
+ function isAndroidOrIosRuntime() {
216
+ var _a, _b, _c, _d, _e, _f, _g, _h;
217
+ const raw = (_a = process.env.UNI_PLATFORM) !== null && _a !== void 0 ? _a : '';
218
+ const g = getGlobalObject();
219
+ if (raw === 'app' || raw === 'app-plus' || raw === 'app-harmony') {
220
+ const n = (_d = (_c = (_b = g.plus) === null || _b === void 0 ? void 0 : _b.os) === null || _c === void 0 ? void 0 : _c.name) === null || _d === void 0 ? void 0 : _d.toLowerCase();
221
+ if (!n)
222
+ return false;
223
+ if (n.includes('android'))
224
+ return true;
225
+ if (n === 'ios' || n.includes('iphone'))
226
+ return true;
227
+ return false;
228
+ }
229
+ if (raw.startsWith('mp-')) {
230
+ try {
231
+ const p = (_h = (_g = (_f = (_e = g.uni) === null || _e === void 0 ? void 0 : _e.getSystemInfoSync) === null || _f === void 0 ? void 0 : _f.call(_e)) === null || _g === void 0 ? void 0 : _g.platform) === null || _h === void 0 ? void 0 : _h.toLowerCase();
232
+ return p === 'android' || p === 'ios';
233
+ }
234
+ catch (_j) {
235
+ return false;
236
+ }
237
+ }
238
+ return false;
239
+ }
240
+ /**
241
+ * 在 Android/iOS 上将「对象类」参数转为可打印字符串;其余类型原样返回。
242
+ */
243
+ function stringifyObjectArgForNative(value) {
244
+ if (value === null || value === undefined)
245
+ return value;
246
+ if (typeof value !== 'object')
247
+ return value;
248
+ if (value instanceof Error)
249
+ return `${value.name}: ${value.message}`;
250
+ return safeStringify(value);
251
+ }
252
+ /**
253
+ * 将单段日志参数格式化为可拼进一行文本的片段(Android/iOS 单参输出用)。
254
+ */
255
+ function formatLogArgForNativeConsole(value) {
256
+ if (value === null)
257
+ return 'null';
258
+ if (value === undefined)
259
+ return 'undefined';
260
+ if (typeof value === 'string')
261
+ return value;
262
+ if (typeof value === 'number' || typeof value === 'boolean') {
263
+ return String(value);
264
+ }
265
+ if (typeof value === 'bigint')
266
+ return String(value);
267
+ if (typeof value === 'symbol') {
268
+ try {
269
+ return value.toString();
270
+ }
271
+ catch (_a) {
272
+ return '?';
273
+ }
274
+ }
275
+ if (typeof value === 'function') {
276
+ const fn = value;
277
+ return `[Function ${fn.name || 'anonymous'}]`;
278
+ }
279
+ if (typeof value === 'object') {
280
+ if (value instanceof Error)
281
+ return `${value.name}: ${value.message}`;
282
+ return safeStringify(value);
283
+ }
284
+ return String(value);
285
+ }
286
+ /**
287
+ * 当前是否应屏蔽 info / warn / error(debug 仍由 `isDebug()` 单独控制)。
288
+ */
289
+ function isNonDebugMuted() {
290
+ if (muteNonDebug !== undefined)
291
+ return muteNonDebug;
292
+ return process.env.NODE_ENV === 'test';
293
+ }
294
+ /**
295
+ * 测试 / CI 下临时恢复 warn 等输出(如断言 install 告警文案)。
296
+ *
297
+ * @param value `true` 屏蔽;`false` 允许;`undefined` 恢复为按 NODE_ENV 自动判定。
298
+ */
299
+ function setMuteNonDebug(value) {
300
+ muteNonDebug = value;
301
+ }
302
+ /**
303
+ * 输出到 console:Android/iOS 真机整行单参;其余平台 `TAG` + 多参。
304
+ */
305
+ function emitConsole(method, args) {
306
+ if (method !== 'log' && isNonDebugMuted())
307
+ return;
308
+ const fn = console[method];
309
+ if (!preferSingleLineConsole()) {
310
+ fn.call(console, TAG, ...args);
311
+ return;
312
+ }
313
+ const mapped = isAndroidOrIosRuntime()
314
+ ? args.map(stringifyObjectArgForNative)
315
+ : args;
316
+ if (mapped.length === 0) {
317
+ fn.call(console, TAG);
318
+ return;
319
+ }
320
+ const body = mapped.map(formatLogArgForNativeConsole).join(' ');
321
+ fn.call(console, `${TAG} ${body}`);
322
+ }
323
+ /**
324
+ * 当前是否启用 debug 输出。优先级:
325
+ * 1. `setDebug(value)` 显式设置过 → 直接返回。
326
+ * 2. `process.env.UNI_STAT_DEBUG === 'true'` 或被构建期替换为布尔字面量 `true`
327
+ * (历史插件兼容路径)。
328
+ */
329
+ function isDebug() {
330
+ if (runtimeDebug !== undefined)
331
+ return runtimeDebug;
332
+ const v = process.env.UNI_STAT_DEBUG;
333
+ return v === 'true' || v === true;
334
+ }
335
+ /**
336
+ * 运行时切换 debug 开关;传 `undefined` 恢复为「按 process.env 判断」。
337
+ */
338
+ function setDebug(value) {
339
+ runtimeDebug = value;
340
+ }
341
+ const logger = {
342
+ debug(...args) {
343
+ if (!isDebug())
344
+ return;
345
+ // eslint-disable-next-line no-console
346
+ emitConsole('log', args);
347
+ },
348
+ info(...args) {
349
+ // eslint-disable-next-line no-console
350
+ emitConsole('info', args);
351
+ },
352
+ warn(...args) {
353
+ // eslint-disable-next-line no-console
354
+ emitConsole('warn', args);
355
+ },
356
+ error(...args) {
357
+ // eslint-disable-next-line no-console
358
+ emitConsole('error', args);
359
+ },
360
+ setDebug,
361
+ isDebug,
362
+ setMuteNonDebug,
363
+ };
364
+
365
+ /**
366
+ * 公有版调试日志:面向业务方的"采集 / 上报"过程日志封装。
367
+ *
368
+ * 与 `logger.debug` 的差异:
369
+ * - `logger.debug` 是底层 console.log + 闸门;调用点散落,文案随意。
370
+ * - 本模块提供**统一文案 / 统一格式**的高层包装,覆盖:
371
+ * 1. 采集动作:每个 lt 都有中文动作名 +「采集 → 数据」标记。
372
+ * 2. 上报生命周期:开始 / 成功 / 失败 / 冷启续传。
373
+ * 3. 启动摘要:通道版本、上报间隔、ak 是否就位等。
374
+ * - 所有 helper 都内嵌 `logger.isDebug()` 判断;非 debug 模式下零开销,
375
+ * 调用方无需再写 `if (logger.isDebug()) ...`。
376
+ *
377
+ * 文案风格参考私有版 `utils/pageInfo.js#log`:直接面向业务调试,**中文**为主,
378
+ * 关键字段(lt / 通道 / 用时 / 错误原因)一目了然。
379
+ *
380
+ * 注意:不在此处吞错;任意 console.log 异常仍会冒泡。运行时调用方需要 `tryRun` 兜底
381
+ * 时自行处理(一般 console.log 不会抛错,故未做包装)。
382
+ */
383
+ /**
384
+ * `lt` → 用户友好的中文动作名映射。
385
+ *
386
+ * 与私有版 `pageInfo.js#log` 的 msg_type 对齐。
387
+ * 注:`lt=0` 已废弃(详见 `domain/eventTypes.ts` 头注释),新会话信息直接随 lt=1 上行。
388
+ *
389
+ * 未知 lt 走默认 "未知事件 (lt=X)",便于排查异常上行。
390
+ */
391
+ function getActionLabel(lt) {
392
+ switch (lt) {
393
+ case LT.Launch:
394
+ return '应用启动';
395
+ case LT.Hide:
396
+ return '应用进入后台';
397
+ case LT.Page:
398
+ return '页面切换';
399
+ case LT.Event:
400
+ return '事件触发';
401
+ case LT.Error:
402
+ return '应用错误';
403
+ case LT.Push:
404
+ return 'PUSH 设备标识';
405
+ default:
406
+ return `未知事件 (lt=${String(lt !== null && lt !== void 0 ? lt : '?')})`;
407
+ }
408
+ }
409
+ /**
410
+ * 单次事件采集日志。
411
+ *
412
+ * 文案示意:
413
+ * ```text
414
+ * [uni统计 2.0] === 统计数据采集:应用启动 (lt=1) ===
415
+ * [uni统计 2.0] {lt: '1', t: 1714123456, ut: 'h5', ...}
416
+ * [uni统计 2.0] === 采集结束 ===
417
+ * ```
418
+ */
419
+ function logCollect(data) {
420
+ if (!logger.isDebug())
421
+ return;
422
+ const lt = data.lt;
423
+ const label = getActionLabel(lt);
424
+ logger.debug(`=== 统计数据采集:${label} (lt=${String(lt !== null && lt !== void 0 ? lt : '?')}) ===`);
425
+ logger.debug(data);
426
+ logger.debug('=== 采集结束 ===');
427
+ }
428
+
17
429
  const appid = process.env.UNI_APP_ID; // 做应用隔离
18
430
  const dbSet = (name, value) => {
19
431
  let data = uni.getStorageSync('$$STAT__DBDATA:'+appid) || {};
@@ -60,7 +472,9 @@ let statConfig = {
60
472
  appid: process.env.UNI_APP_ID,
61
473
  };
62
474
  let titleJsons = {};
63
- let debug = !!process.env.UNI_STAT_DEBUG || false;
475
+ let debug =
476
+ process.env.UNI_STAT_DEBUG === 'true' ||
477
+ process.env.UNI_STAT_DEBUG === true;
64
478
  // #ifdef VUE3
65
479
  titleJsons = process.env.UNI_STAT_TITLE_JSON;
66
480
  // #endif
@@ -190,6 +604,8 @@ const get_platform_name = () => {
190
604
  const platformList = {
191
605
  app: 'n',
192
606
  'app-plus': 'n',
607
+ 'app-harmony':'n',
608
+ 'mp-harmony':'mhm',
193
609
  h5: 'h5',
194
610
  'mp-weixin': 'wx',
195
611
  [aliArr.reverse().join('')]: 'ali',
@@ -200,6 +616,7 @@ const get_platform_name = () => {
200
616
  'mp-kuaishou': 'ks',
201
617
  'mp-lark': 'lark',
202
618
  'quickapp-webview': 'qw',
619
+ 'mp-xhs': 'xhs'
203
620
  };
204
621
  if (platformList[process.env.VUE_APP_PLATFORM] === 'ali') {
205
622
  if (my && my.env) {
@@ -209,7 +626,7 @@ const get_platform_name = () => {
209
626
  // TODO 缺少 ali 下的其他平台
210
627
  }
211
628
  }
212
- return platformList[process.env.VUE_APP_PLATFORM]
629
+ return platformList[process.env.VUE_APP_PLATFORM] || process.env.VUE_APP_PLATFORM
213
630
  };
214
631
 
215
632
  /**
@@ -265,7 +682,7 @@ const get_scene = (options) => {
265
682
  /**
266
683
  * 获取页面url,不包含参数
267
684
  */
268
- const get_route$1 = (pageVm) => {
685
+ const get_route = (pageVm) => {
269
686
  let _self = pageVm || get_page_vm();
270
687
  if (get_platform_name() === 'bd') {
271
688
  let mp_route = _self.$mp && _self.$mp.page && _self.$mp.page.is;
@@ -506,13 +923,16 @@ const uni_cloud_config = () => {
506
923
  const get_space = (config) => {
507
924
  const uniCloudConfig = uni_cloud_config();
508
925
  const { spaceId, provider, clientSecret ,secretKey,secretId} = uniCloudConfig;
509
- const space_type = ['tcb', 'tencent', 'aliyun','alipay'];
926
+ const space_type = ['tcb', 'tencent', 'aliyun','alipay','private','dcloud'];
510
927
  const is_provider = space_type.indexOf(provider) !== -1;
511
928
  const is_aliyun = provider === 'aliyun' && spaceId && clientSecret;
512
929
  const is_tcb = (provider === 'tcb' || provider === 'tencent') && spaceId;
513
930
  const is_alipay = provider === 'alipay' && spaceId && secretKey && secretId;
514
931
 
515
- if (is_provider && (is_aliyun || is_tcb || is_alipay)) {
932
+ const is_private = provider === 'private' && spaceId && clientSecret;
933
+ const is_dcloud = provider === 'dcloud' && spaceId && clientSecret;
934
+
935
+ if (is_provider && (is_aliyun || is_tcb || is_alipay || is_private || is_dcloud)) {
516
936
  return uniCloudConfig
517
937
  } else {
518
938
  if (config && config.spaceId) {
@@ -529,52 +949,18 @@ const get_space = (config) => {
529
949
  const is_debug = debug;
530
950
 
531
951
  /**
532
- * 日志输出
533
- * @param {*} data
952
+ * 日志输出(采集 / 上报过程日志,文案与公有版 `debugLog` 对齐)。
953
+ * @param {*} data 采集事件或上报 payload
954
+ * @param {*} type 为真时表示上报阶段
534
955
  */
535
956
  const log = (data, type) => {
536
- let msg_type = '';
537
- switch (data.lt) {
538
- case '1':
539
- msg_type = '应用启动';
540
- break
541
- case '3':
542
- msg_type = '应用进入后台';
543
- break
544
-
545
- case '11':
546
- msg_type = '页面切换';
547
- break
548
- case '21':
549
- msg_type = '事件触发';
550
- break
551
- case '31':
552
- msg_type = '应用错误';
553
- break
554
- case '101':
555
- msg_type = 'PUSH';
556
- break
557
- }
558
-
559
- // #ifdef APP
560
- // 在 app 中,日志转为 字符串
561
- if (typeof data === 'object') {
562
- data = JSON.stringify(data);
563
- }
564
- // #endif
565
-
957
+ if (!logger.isDebug()) return
566
958
  if (type) {
567
- console.log(`=== 统计队列数据上报 ===`);
568
- console.log(data);
569
- console.log(`=== 上报结束 ===`);
959
+ logger.debug('=== 准备上报 ===');
960
+ logger.debug(data);
570
961
  return
571
962
  }
572
-
573
- if (msg_type) {
574
- console.log(`=== 统计数据采集:${msg_type} ===`);
575
- console.log(data);
576
- console.log(`=== 采集结束 ===`);
577
- }
963
+ logCollect(data);
578
964
  };
579
965
 
580
966
  /**
@@ -762,11 +1148,12 @@ const get_residence_time = (type) => {
762
1148
  };
763
1149
 
764
1150
  const eport_Interval = get_report_Interval(OPERATING_TIME);
1151
+
765
1152
  // 统计数据默认值
766
1153
  let statData = {
767
1154
  uuid: get_uuid(), // 设备标识
768
1155
  ak: stat_config.appid, // uni-app 应用 Appid
769
- p: sys.platform === 'android' ? 'a' : 'i', // 手机系统
1156
+ p: '', // 手机系统,客户端平台
770
1157
  ut: get_platform_name(), // 平台类型
771
1158
  mpn: get_pack_name(), // 原生平台包名、小程序 appid
772
1159
  usv: STAT_VERSION, // 统计 sdk 版本
@@ -779,7 +1166,7 @@ let statData = {
779
1166
  tt: '',
780
1167
  brand: sys.brand || '', // 手机品牌
781
1168
  md: sys.model, // 手机型号
782
- sv: sys.system?.replace(/(Android|iOS)\s/, '') ?? '', // 手机系统版本
1169
+ sv: '', // 手机系统版本
783
1170
  mpsdk: sys.SDKVersion || '', // x程序 sdk version
784
1171
  mpv: sys.version || '', // 小程序平台版本 ,如微信、支付宝
785
1172
  lang: sys.language, // 语言
@@ -789,6 +1176,26 @@ let statData = {
789
1176
  sw: sys.screenWidth, // screenWidth 屏幕宽度
790
1177
  sh: sys.screenHeight, // screenHeight 屏幕高度
791
1178
  };
1179
+
1180
+ // 客户端平台,只有app平台平台可以用到
1181
+ if(sys.platform){
1182
+ switch (sys.platform) {
1183
+ case 'android':
1184
+ statData.p = 'a';
1185
+ break
1186
+ case 'ios':
1187
+ statData.p = 'i';
1188
+ break
1189
+ case 'harmonyos':
1190
+ statData.p = 'h';
1191
+ break
1192
+ }
1193
+ }
1194
+
1195
+ // 获取手机版本
1196
+ if (sys.system){
1197
+ statData.sv = sys.system.replace(/(Android|iOS)\s/, '');
1198
+ }
792
1199
  class Report {
793
1200
  constructor() {
794
1201
  // 页面实例
@@ -910,6 +1317,19 @@ class Report {
910
1317
  cst: 2,
911
1318
  };
912
1319
  this.sendReportRequest(options);
1320
+ } else {
1321
+ // 在没有超过时限的时候 ,判断场景值 ,如果是场景值发生了变化,则需要上报应用启动数据
1322
+ // 目前只有微信小程序生效
1323
+ const scene = get_scene();
1324
+ if (scene !== this.statData.sc) {
1325
+ let lastPageRoute = uni.getStorageSync('_STAT_LAST_PAGE_ROUTE');
1326
+ let options = {
1327
+ path: lastPageRoute,
1328
+ scene: scene,
1329
+ cst: 2,
1330
+ };
1331
+ this.sendReportRequest(options);
1332
+ }
913
1333
  }
914
1334
  // 状态重置
915
1335
  this.__licationHide = false;
@@ -955,7 +1375,7 @@ class Report {
955
1375
  };
956
1376
 
957
1377
  const route = get_page_route(self);
958
- const routepath = get_route$1(self);
1378
+ const routepath = get_route(self);
959
1379
 
960
1380
  this._navigationBarTitle.config = get_page_name(routepath);
961
1381
  // 表示应用触发 ,页面切换不触发之后的逻辑
@@ -1016,14 +1436,14 @@ class Report {
1016
1436
  let query = is_opt ? '?' + JSON.stringify(options.query) : '';
1017
1437
  const last_time = get_last_visit_time();
1018
1438
  // 非老用户
1019
- if(last_time !== 0 || !last_time){
1439
+ if (last_time !== 0 || !last_time) {
1020
1440
  const odid = get_odid();
1021
1441
 
1022
1442
  // 2.0 处理规则
1023
1443
  {
1024
1444
  const have_device = is_handle_device();
1025
1445
  // 如果没有上报过设备信息 ,则需要上报设备信息
1026
- if(!have_device) {
1446
+ if (!have_device) {
1027
1447
  this.statData.odid = odid;
1028
1448
  }
1029
1449
  }
@@ -1100,7 +1520,7 @@ class Report {
1100
1520
  let routepath = '';
1101
1521
 
1102
1522
  try {
1103
- routepath = get_route$1();
1523
+ routepath = get_route();
1104
1524
  } catch (error) {
1105
1525
  const launch_options = dbGet('__launch_options');
1106
1526
  routepath = launch_options.path;
@@ -1511,9 +1931,8 @@ class Stat extends Report {
1511
1931
  this.request(options);
1512
1932
  }
1513
1933
  }
1514
- var Stat$1 = Stat;
1515
1934
 
1516
- const stat = Stat$1.getInstance();
1935
+ const stat = Stat.getInstance();
1517
1936
 
1518
1937
  // 用于判断是隐藏页面还是卸载页面
1519
1938
  let isHide = false;
@@ -1552,7 +1971,12 @@ const lifecycle = {
1552
1971
  stat.hide(this);
1553
1972
  },
1554
1973
  onError(e) {
1555
- stat.error(e);
1974
+ // fix by haotian 避免统计内部错误导致堆栈溢出,造成死循环
1975
+ try {
1976
+ stat.error(e);
1977
+ } catch (error) {
1978
+ console.error('uni-stat error:', error);
1979
+ }
1556
1980
  },
1557
1981
  };
1558
1982
 
@@ -1590,7 +2014,7 @@ function main() {
1590
2014
  if (is_debug) {
1591
2015
  {
1592
2016
  // #ifndef APP-NVUE
1593
- console.log('=== uni统计开启,version:2.0 ===');
2017
+ logger.debug('=== uni统计 2.0(私有版)已启用 ===');
1594
2018
  // #endif
1595
2019
  }
1596
2020
  load_stat();