@fle-sdk/event-tracking-web 1.2.0 → 1.2.2

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/lib/index.js CHANGED
@@ -1252,7 +1252,19 @@
1252
1252
 
1253
1253
  _this.batchTimer = null; // LocalStorage 存储 key
1254
1254
 
1255
- _this.BATCH_QUEUE_STORAGE_KEY = 'web_tracking_batch_queue'; // 用户信息
1255
+ _this.BATCH_QUEUE_STORAGE_KEY = "web_tracking_batch_queue"; // 是否使用自定义 pageKey(如果为 true,路由变化时不会自动更新 pageKey)
1256
+
1257
+ _this.useCustomPageKey = false; // 待发送的单个请求队列(用于页面跳转时发送)
1258
+
1259
+ _this.pendingRequests = []; // 页面卸载监听器是否已设置
1260
+
1261
+ _this.isUnloadListenerSetup = false; // LocalStorage 存储 key(待发送请求)
1262
+
1263
+ _this.PENDING_REQUESTS_STORAGE_KEY = "web_tracking_pending_requests"; // 待发送请求队列最大大小(默认值,可通过配置覆盖)
1264
+
1265
+ _this.DEFAULT_PENDING_REQUESTS_MAX_SIZE = 50; // LocalStorage 最大大小限制(4MB)
1266
+
1267
+ _this.MAX_STORAGE_SIZE = 4 * 1024 * 1024; // 用户信息
1256
1268
 
1257
1269
  _this.userInfo = null; // 当前路由
1258
1270
 
@@ -1277,21 +1289,36 @@
1277
1289
  _this.preset(initParams);
1278
1290
 
1279
1291
  var pathname = window.location.pathname;
1280
- _this.currentUrl = window.location.href;
1281
- _this.pageKey = pathname.replace(/\//g, "_").substring(1);
1292
+ _this.currentUrl = window.location.href; // 如果传入了自定义 pageKey,使用自定义值,否则自动生成
1293
+
1294
+ if (initParams.pageKey) {
1295
+ _this.pageKey = initParams.pageKey;
1296
+ _this.useCustomPageKey = true;
1297
+ } else {
1298
+ _this.pageKey = pathname.replace(/\//g, "_").substring(1);
1299
+ _this.useCustomPageKey = false;
1300
+ }
1301
+
1282
1302
  _this.systemsInfo = _this.getSystemsInfo(initParams.platform); // 获取设备ID
1283
1303
 
1284
- _this.deviceId = _this.getDeviceId();
1304
+ _this.deviceId = _this.getDeviceId(); // 如果传入了 userInfo,设置用户信息
1305
+
1306
+ if (initParams.userInfo && _this.isObject(initParams.userInfo)) {
1307
+ _this.userInfo = initParams.userInfo;
1308
+ }
1285
1309
 
1286
1310
  _this.setCookie("retainedStartTime", _this.getTimeStamp()); // 如果启用了批量发送,从 LocalStorage 恢复队列
1287
1311
 
1288
1312
 
1289
1313
  if (_this.initConfig.batchSend) {
1290
- _this.restoreBatchQueueFromStorage(); // 监听页面卸载事件,保存队列
1314
+ _this.restoreBatchQueueFromStorage();
1315
+ } // 恢复待发送的单个请求
1291
1316
 
1292
1317
 
1293
- _this.setupBeforeUnloadListener();
1294
- }
1318
+ _this.restorePendingRequestsFromStorage(); // 无论是否启用批量发送,都需要监听页面卸载事件,确保数据发送
1319
+
1320
+
1321
+ _this.setupBeforeUnloadListener();
1295
1322
  };
1296
1323
  /**
1297
1324
  * TODO: 需要判断有哪些不能被预制的参数
@@ -1302,7 +1329,23 @@
1302
1329
 
1303
1330
  _this.preset = function (presetParams) {
1304
1331
  if (presetParams instanceof Object) {
1332
+ // 处理 pageKey 特殊逻辑
1333
+ if (presetParams.pageKey !== undefined) {
1334
+ if (presetParams.pageKey === null || presetParams.pageKey === '') {
1335
+ // 恢复自动生成
1336
+ _this.useCustomPageKey = false;
1337
+ var pathname = window.location.pathname;
1338
+ _this.pageKey = pathname.replace(/\//g, "_").substring(1);
1339
+ } else {
1340
+ _this.pageKey = presetParams.pageKey;
1341
+ _this.useCustomPageKey = true;
1342
+ }
1343
+ }
1344
+
1305
1345
  _this.each(presetParams, function (val, key) {
1346
+ // 跳过 pageKey,因为已经单独处理
1347
+ if (key === 'pageKey') return;
1348
+
1306
1349
  if (_this.initConfig.hasOwnProperty(key)) {
1307
1350
  // TODO:后面加一些校验
1308
1351
  _this.initConfig[key] = val;
@@ -1314,10 +1357,10 @@
1314
1357
  _this.printLog("当前 server_url 为空或不正确,只在控制台打印日志,network 中不会发数据,请配置正确的 server_url!");
1315
1358
 
1316
1359
  _this.initConfig["showLog"] = true;
1317
- } // 如果启用了全埋点
1360
+ } // 如果启用了全埋点或启用了 data-part-key 点击追踪
1318
1361
 
1319
1362
 
1320
- if (!!_this.initConfig["autoTrack"]) {
1363
+ if (!!_this.initConfig["autoTrack"] || !!_this.initConfig["trackPartKeyClick"]) {
1321
1364
  // 启用监听
1322
1365
  _this.listener();
1323
1366
  } else {
@@ -1346,7 +1389,7 @@
1346
1389
  } // 获取已存储的设备ID
1347
1390
 
1348
1391
 
1349
- var storedDeviceId = _this.getCookie('device_id') || _this.getLocalStorage('device_id');
1392
+ var storedDeviceId = _this.getCookie("device_id") || _this.getLocalStorage("device_id");
1350
1393
 
1351
1394
  if (storedDeviceId) {
1352
1395
  _this.deviceId = storedDeviceId;
@@ -1360,10 +1403,10 @@
1360
1403
  var deviceId = _this.hashFingerprint(fingerprint); // 存储设备ID(统一使用2年过期时间,与tools.ts保持一致)
1361
1404
 
1362
1405
 
1363
- _this.setCookie('device_id', deviceId, 365 * 2); // 存储2年
1406
+ _this.setCookie("device_id", deviceId, 365 * 2); // 存储2年
1364
1407
 
1365
1408
 
1366
- _this.setLocalStorage('device_id', deviceId);
1409
+ _this.setLocalStorage("device_id", deviceId);
1367
1410
 
1368
1411
  _this.deviceId = deviceId;
1369
1412
  return _this.deviceId;
@@ -1377,10 +1420,10 @@
1377
1420
 
1378
1421
  _this.resetDeviceId = function () {
1379
1422
  // 清除cookie和localStorage中的设备ID
1380
- document.cookie = 'device_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
1381
- localStorage.removeItem('device_id'); // 清除内存中的设备ID
1423
+ document.cookie = "device_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
1424
+ localStorage.removeItem("device_id"); // 清除内存中的设备ID
1382
1425
 
1383
- _this.deviceId = ''; // 重新生成设备ID
1426
+ _this.deviceId = ""; // 重新生成设备ID
1384
1427
 
1385
1428
  var newDeviceId = _this.getDeviceId();
1386
1429
 
@@ -1395,6 +1438,7 @@
1395
1438
 
1396
1439
  _this.track = function (_a) {
1397
1440
  var desc = _a.desc,
1441
+ pageKey = _a.pageKey,
1398
1442
  partkey = _a.partkey,
1399
1443
  business = _a.business,
1400
1444
  header = _a.header;
@@ -1402,7 +1446,7 @@
1402
1446
  var params = _this.getParams({
1403
1447
  desc: desc,
1404
1448
  event: "CustomTrack",
1405
- itemKey: _this.getItemKey(partkey),
1449
+ itemKey: _this.getItemKey(partkey, pageKey),
1406
1450
  privateParamMap: {
1407
1451
  business: business
1408
1452
  }
@@ -1416,17 +1460,23 @@
1416
1460
 
1417
1461
 
1418
1462
  _this.listener = function () {
1419
- if (!!_this.initConfig.isTrackSinglePage) {
1420
- _this.rewriteHistory();
1463
+ // 如果启用了全埋点,监听页面浏览事件
1464
+ if (!!_this.initConfig.autoTrack) {
1465
+ if (!!_this.initConfig.isTrackSinglePage) {
1466
+ _this.rewriteHistory();
1421
1467
 
1422
- _this.addSinglePageEvent(_this.onPageViewCallback);
1423
- }
1468
+ _this.addSinglePageEvent(_this.onPageViewCallback);
1469
+ }
1470
+
1471
+ _this.each(["load", "beforeunload"], function (historyType) {
1472
+ _this.addEventListener(window, historyType, _this.onPageViewCallback);
1473
+ });
1474
+ } // 如果启用了全埋点或启用了 data-part-key 点击追踪,监听点击事件
1424
1475
 
1425
- _this.each(["load", "beforeunload"], function (historyType) {
1426
- _this.addEventListener(window, historyType, _this.onPageViewCallback);
1427
- });
1428
1476
 
1429
- _this.addEventListener(window, "click", _this.onClickCallback);
1477
+ if (!!_this.initConfig.autoTrack || !!_this.initConfig.trackPartKeyClick) {
1478
+ _this.addEventListener(window, "click", _this.onClickCallback);
1479
+ }
1430
1480
  };
1431
1481
  /**
1432
1482
  * @description 取消全埋点事件
@@ -1471,12 +1521,51 @@
1471
1521
  _this.clearBatchQueue = function () {
1472
1522
  _this.batchQueue = [];
1473
1523
 
1474
- _this.setLocalStorage(_this.BATCH_QUEUE_STORAGE_KEY, '[]');
1524
+ _this.setLocalStorage(_this.BATCH_QUEUE_STORAGE_KEY, "[]");
1475
1525
 
1476
1526
  if (_this.initConfig.showLog) {
1477
- _this.printLog('批量队列已清空');
1527
+ _this.printLog("批量队列已清空");
1528
+ }
1529
+ };
1530
+ /**
1531
+ * @description 设置自定义页面唯一标识
1532
+ * @param pageKey 页面唯一标识,如果传入 null 或空字符串,则恢复自动生成
1533
+ * @param autoUpdate 路由变化时是否自动更新(默认:false,使用自定义值后不再自动更新)
1534
+ */
1535
+
1536
+
1537
+ _this.setPageKey = function (pageKey, autoUpdate) {
1538
+ if (autoUpdate === void 0) {
1539
+ autoUpdate = false;
1540
+ }
1541
+
1542
+ if (pageKey === null || pageKey === '') {
1543
+ // 恢复自动生成
1544
+ _this.useCustomPageKey = false;
1545
+ var pathname = window.location.pathname;
1546
+ _this.pageKey = pathname.replace(/\//g, "_").substring(1);
1547
+
1548
+ if (_this.initConfig.showLog) {
1549
+ _this.printLog("\u9875\u9762\u6807\u8BC6\u5DF2\u6062\u590D\u81EA\u52A8\u751F\u6210: " + _this.pageKey);
1550
+ }
1551
+ } else {
1552
+ _this.pageKey = pageKey;
1553
+ _this.useCustomPageKey = !autoUpdate;
1554
+
1555
+ if (_this.initConfig.showLog) {
1556
+ _this.printLog("\u9875\u9762\u6807\u8BC6\u5DF2\u8BBE\u7F6E\u4E3A: " + pageKey + ", \u81EA\u52A8\u66F4\u65B0: " + autoUpdate);
1557
+ }
1478
1558
  }
1479
1559
  };
1560
+ /**
1561
+ * @description 获取当前页面唯一标识
1562
+ * @returns 当前页面唯一标识
1563
+ */
1564
+
1565
+
1566
+ _this.getPageKey = function () {
1567
+ return _this.pageKey;
1568
+ };
1480
1569
 
1481
1570
  _this.onClickCallback = function (e) {
1482
1571
  var _a;
@@ -1502,7 +1591,7 @@
1502
1591
  targetEle: targetEle,
1503
1592
  pointerType: e.pointerType,
1504
1593
  currentUrl: _this.currentUrl,
1505
- elementSelector: _this.getDomSelector(target) || ''
1594
+ elementSelector: _this.getDomSelector(target) || ""
1506
1595
  }
1507
1596
  });
1508
1597
 
@@ -1514,7 +1603,12 @@
1514
1603
 
1515
1604
 
1516
1605
  _this.onPageViewCallback = function (e) {
1517
- var _a, _b;
1606
+ var _a, _b; // 在路由变化前,先发送待发送的数据(避免被取消)
1607
+
1608
+
1609
+ if (_this.pendingRequests.length > 0 || _this.initConfig.batchSend && _this.batchQueue.length > 0) {
1610
+ _this.flushPendingData();
1611
+ }
1518
1612
 
1519
1613
  var ORGIN = window.location.origin;
1520
1614
 
@@ -1527,8 +1621,11 @@
1527
1621
  }
1528
1622
  });
1529
1623
 
1530
- _this.currentUrl = window.location.href;
1531
- _this.pageKey = window.location.pathname.replace(/\//g, "_").substring(1);
1624
+ _this.currentUrl = window.location.href; // 如果使用自定义 pageKey,路由变化时不自动更新
1625
+
1626
+ if (!_this.useCustomPageKey) {
1627
+ _this.pageKey = window.location.pathname.replace(/\//g, "_").substring(1);
1628
+ }
1532
1629
 
1533
1630
  _this.sendRetained(e.type);
1534
1631
 
@@ -1759,9 +1856,121 @@
1759
1856
  _this.printLog("\u6062\u590D\u6279\u91CF\u961F\u5217\u5931\u8D25: " + e); // 如果解析失败,清除损坏的数据
1760
1857
 
1761
1858
 
1762
- _this.setLocalStorage(_this.BATCH_QUEUE_STORAGE_KEY, '[]');
1859
+ _this.setLocalStorage(_this.BATCH_QUEUE_STORAGE_KEY, "[]");
1860
+ }
1861
+ };
1862
+ /**
1863
+ * 添加到待发送请求队列
1864
+ * @param params 数据参数
1865
+ */
1866
+
1867
+
1868
+ _this.addToPendingRequests = function (params) {
1869
+ _this.pendingRequests.push(params); // 限制队列大小,防止内存溢出
1870
+
1871
+
1872
+ var maxSize = _this.initConfig.pendingRequestsMaxSize || _this.DEFAULT_PENDING_REQUESTS_MAX_SIZE;
1873
+
1874
+ if (_this.pendingRequests.length > maxSize) {
1875
+ _this.pendingRequests = _this.pendingRequests.slice(-maxSize);
1876
+
1877
+ if (_this.initConfig.showLog) {
1878
+ _this.printLog("\u5F85\u53D1\u9001\u8BF7\u6C42\u961F\u5217\u5DF2\u6EE1\uFF0C\u5DF2\u79FB\u9664\u6700\u65E7\u7684\u6570\u636E\uFF08\u6700\u5927\u9650\u5236: " + maxSize + "\uFF09");
1879
+ }
1763
1880
  }
1764
1881
  };
1882
+ /**
1883
+ * 从 LocalStorage 恢复待发送请求
1884
+ */
1885
+
1886
+
1887
+ _this.restorePendingRequestsFromStorage = function () {
1888
+ try {
1889
+ var storedRequests = _this.getLocalStorage(_this.PENDING_REQUESTS_STORAGE_KEY);
1890
+
1891
+ if (storedRequests) {
1892
+ var parsedRequests = JSON.parse(storedRequests);
1893
+
1894
+ if (Array.isArray(parsedRequests) && parsedRequests.length > 0) {
1895
+ _this.pendingRequests = parsedRequests;
1896
+
1897
+ if (_this.initConfig.showLog) {
1898
+ _this.printLog("\u4ECE LocalStorage \u6062\u590D " + parsedRequests.length + " \u6761\u5F85\u53D1\u9001\u8BF7\u6C42");
1899
+ } // 恢复后立即尝试发送
1900
+
1901
+
1902
+ if (_this.pendingRequests.length > 0) {
1903
+ _this.flushPendingRequests();
1904
+ }
1905
+ }
1906
+ }
1907
+ } catch (e) {
1908
+ _this.printLog("\u6062\u590D\u5F85\u53D1\u9001\u8BF7\u6C42\u5931\u8D25: " + e); // 如果解析失败,清除损坏的数据
1909
+
1910
+
1911
+ _this.setLocalStorage(_this.PENDING_REQUESTS_STORAGE_KEY, "[]");
1912
+ }
1913
+ };
1914
+ /**
1915
+ * 检查页面是否即将卸载
1916
+ * @returns 如果页面即将卸载返回 true,否则返回 false
1917
+ */
1918
+
1919
+
1920
+ _this.isPageUnloading = function () {
1921
+ return document.visibilityState === "hidden";
1922
+ };
1923
+ /**
1924
+ * 使用 sendBeacon 发送数据(页面卸载时的备用方案)
1925
+ * @param params 数据参数
1926
+ * @param serverUrl 服务器地址
1927
+ * @param contentType 内容类型
1928
+ * @returns 是否发送成功
1929
+ */
1930
+
1931
+
1932
+ _this.sendWithBeacon = function (params, serverUrl, contentType) {
1933
+ try {
1934
+ var blob = new Blob([JSON.stringify(params)], {
1935
+ type: contentType || "application/json"
1936
+ });
1937
+ return navigator.sendBeacon(serverUrl, blob);
1938
+ } catch (e) {
1939
+ if (_this.initConfig.showLog) {
1940
+ _this.printLog("sendBeacon \u53D1\u9001\u5931\u8D25: " + e);
1941
+ }
1942
+
1943
+ return false;
1944
+ }
1945
+ };
1946
+ /**
1947
+ * 刷新待发送的单个请求(正常情况下的发送)
1948
+ * 注意:这个方法会直接发送,不会再次添加到 pendingRequests,避免循环
1949
+ */
1950
+
1951
+
1952
+ _this.flushPendingRequests = function () {
1953
+ if (_this.pendingRequests.length === 0) {
1954
+ return;
1955
+ }
1956
+
1957
+ var requestsToSend = __spreadArray([], _this.pendingRequests);
1958
+
1959
+ _this.pendingRequests = []; // 清除 LocalStorage 中的待发送请求
1960
+
1961
+ _this.setLocalStorage(_this.PENDING_REQUESTS_STORAGE_KEY, "[]"); // 尝试发送每个请求(使用 sendData,但如果失败不再添加到 pendingRequests,避免循环)
1962
+
1963
+
1964
+ requestsToSend.forEach(function (params) {
1965
+ // 直接调用 sendData,但不处理失败情况(避免循环)
1966
+ // 如果失败,数据会丢失,但这是可接受的,因为我们已经尝试过了
1967
+ _this.sendData(params).catch(function (err) {
1968
+ if (_this.initConfig.showLog) {
1969
+ _this.printLog("\u5F85\u53D1\u9001\u8BF7\u6C42\u53D1\u9001\u5931\u8D25\uFF08\u4E0D\u518D\u91CD\u8BD5\uFF09: " + err);
1970
+ }
1971
+ });
1972
+ });
1973
+ };
1765
1974
  /**
1766
1975
  * 保存批量队列到 LocalStorage
1767
1976
  */
@@ -1772,13 +1981,12 @@
1772
1981
  var queueString = JSON.stringify(_this.batchQueue); // 检查存储大小,避免超出 LocalStorage 限制(通常 5-10MB)
1773
1982
  // 如果队列过大,只保留最新的数据
1774
1983
 
1775
- if (queueString.length > 4 * 1024 * 1024) {
1776
- // 4MB 限制
1984
+ if (queueString.length > _this.MAX_STORAGE_SIZE) {
1777
1985
  var maxItems = Math.floor(_this.batchQueue.length * 0.8); // 保留 80%
1778
1986
 
1779
1987
  _this.batchQueue = _this.batchQueue.slice(-maxItems);
1780
1988
 
1781
- _this.printLog("\u961F\u5217\u8FC7\u5927\uFF0C\u5DF2\u622A\u65AD\u4FDD\u7559\u6700\u65B0 " + maxItems + " \u6761\u6570\u636E");
1989
+ _this.printLog("\u961F\u5217\u8FC7\u5927\uFF0C\u5DF2\u622A\u65AD\u4FDD\u7559\u6700\u65B0 " + maxItems + " \u6761\u6570\u636E\uFF08\u9650\u5236: " + _this.MAX_STORAGE_SIZE / 1024 / 1024 + "MB\uFF09");
1782
1990
  }
1783
1991
 
1784
1992
  _this.setLocalStorage(_this.BATCH_QUEUE_STORAGE_KEY, JSON.stringify(_this.batchQueue));
@@ -1788,44 +1996,126 @@
1788
1996
  }
1789
1997
  };
1790
1998
  /**
1791
- * 设置页面卸载监听器,保存队列
1999
+ * 设置页面卸载监听器,确保数据发送
1792
2000
  */
1793
2001
 
1794
2002
 
1795
2003
  _this.setupBeforeUnloadListener = function () {
1796
- // 使用 visibilitychange 事件(更可靠)
1797
- document.addEventListener('visibilitychange', function () {
1798
- if (document.visibilityState === 'hidden' && _this.batchQueue.length > 0) {
1799
- _this.saveBatchQueueToStorage();
2004
+ // 避免重复设置监听器
2005
+ if (_this.isUnloadListenerSetup) {
2006
+ return;
2007
+ }
2008
+
2009
+ _this.isUnloadListenerSetup = true; // 使用 visibilitychange 事件(更可靠,支持页面跳转、切换标签页等场景)
2010
+
2011
+ document.addEventListener("visibilitychange", function () {
2012
+ if (_this.isPageUnloading()) {
2013
+ _this.flushPendingData();
1800
2014
  }
1801
- }); // 使用 beforeunload 事件作为备用
2015
+ }); // 使用 beforeunload 事件作为备用(页面关闭/刷新)
1802
2016
 
1803
- window.addEventListener('beforeunload', function () {
1804
- if (_this.batchQueue.length > 0) {
1805
- // 使用 sendBeacon 尝试发送数据(如果支持)
1806
- if (navigator.sendBeacon && _this.initConfig.serverUrl) {
1807
- try {
1808
- var data = JSON.stringify({
1809
- events: _this.batchQueue
1810
- });
1811
- var blob = new Blob([data], {
1812
- type: 'application/json'
1813
- });
1814
- navigator.sendBeacon(_this.initConfig.serverUrl, blob); // 如果 sendBeacon 成功,清除队列
2017
+ window.addEventListener("beforeunload", function () {
2018
+ _this.flushPendingData();
2019
+ }); // 使用 pagehide 事件(更可靠,支持移动端)
1815
2020
 
1816
- _this.batchQueue = [];
2021
+ window.addEventListener("pagehide", function () {
2022
+ _this.flushPendingData();
2023
+ });
2024
+ };
2025
+ /**
2026
+ * 刷新待发送数据(在页面卸载/跳转时调用)
2027
+ */
1817
2028
 
1818
- _this.setLocalStorage(_this.BATCH_QUEUE_STORAGE_KEY, '[]');
1819
- } catch (e) {
1820
- // sendBeacon 失败,保存到 LocalStorage
1821
- _this.saveBatchQueueToStorage();
2029
+
2030
+ _this.flushPendingData = function () {
2031
+ // 收集所有待发送的数据
2032
+ var allPendingData = []; // 如果有批量队列,添加到待发送列表
2033
+
2034
+ if (_this.batchQueue.length > 0) {
2035
+ allPendingData.push.apply(allPendingData, _this.batchQueue);
2036
+ } // 如果有待发送的单个请求,也添加到列表
2037
+
2038
+
2039
+ if (_this.pendingRequests.length > 0) {
2040
+ allPendingData.push.apply(allPendingData, _this.pendingRequests);
2041
+ }
2042
+
2043
+ if (allPendingData.length === 0) {
2044
+ return;
2045
+ } // 使用 sendBeacon 发送数据(最可靠的方式)
2046
+
2047
+
2048
+ if (navigator.sendBeacon && _this.initConfig.serverUrl) {
2049
+ try {
2050
+ // 如果只有一条数据,直接发送;否则批量发送
2051
+ var dataToSend = allPendingData.length === 1 ? allPendingData[0] : {
2052
+ events: allPendingData
2053
+ };
2054
+ var blob = new Blob([JSON.stringify(dataToSend)], {
2055
+ type: _this.initConfig.contentType || "application/json"
2056
+ });
2057
+ var sent = navigator.sendBeacon(_this.initConfig.serverUrl, blob);
2058
+
2059
+ if (sent) {
2060
+ // 发送成功,清除所有队列
2061
+ _this.batchQueue = [];
2062
+ _this.pendingRequests = [];
2063
+
2064
+ _this.setLocalStorage(_this.BATCH_QUEUE_STORAGE_KEY, "[]");
2065
+
2066
+ if (_this.initConfig.showLog) {
2067
+ _this.printLog("\u9875\u9762\u5378\u8F7D\u65F6\u6210\u529F\u53D1\u9001 " + allPendingData.length + " \u6761\u6570\u636E");
1822
2068
  }
1823
2069
  } else {
1824
- // 不支持 sendBeacon,保存到 LocalStorage
2070
+ // sendBeacon 返回 false,保存到 LocalStorage(批量模式)
2071
+ if (_this.initConfig.batchSend && _this.batchQueue.length > 0) {
2072
+ _this.saveBatchQueueToStorage();
2073
+ } // 保存 pendingRequests 到 LocalStorage(如果支持)
2074
+
2075
+
2076
+ if (_this.pendingRequests.length > 0) {
2077
+ try {
2078
+ _this.setLocalStorage(_this.PENDING_REQUESTS_STORAGE_KEY, JSON.stringify(_this.pendingRequests));
2079
+ } catch (e) {
2080
+ // LocalStorage 可能已满或不可用
2081
+ if (_this.initConfig.showLog) {
2082
+ _this.printLog("\u4FDD\u5B58\u5F85\u53D1\u9001\u8BF7\u6C42\u5230 LocalStorage \u5931\u8D25: " + e);
2083
+ }
2084
+ }
2085
+ }
2086
+ }
2087
+ } catch (e) {
2088
+ // sendBeacon 失败,保存到 LocalStorage(批量模式)
2089
+ if (_this.initConfig.batchSend && _this.batchQueue.length > 0) {
1825
2090
  _this.saveBatchQueueToStorage();
2091
+ } // 保存 pendingRequests 到 LocalStorage(如果支持)
2092
+
2093
+
2094
+ if (_this.pendingRequests.length > 0) {
2095
+ try {
2096
+ _this.setLocalStorage(_this.PENDING_REQUESTS_STORAGE_KEY, JSON.stringify(_this.pendingRequests));
2097
+ } catch (e) {// LocalStorage 可能已满或不可用
2098
+ }
2099
+ }
2100
+
2101
+ if (_this.initConfig.showLog) {
2102
+ _this.printLog("\u9875\u9762\u5378\u8F7D\u65F6\u53D1\u9001\u6570\u636E\u5931\u8D25: " + e);
1826
2103
  }
1827
2104
  }
1828
- });
2105
+ } else {
2106
+ // 不支持 sendBeacon,保存到 LocalStorage(批量模式)
2107
+ if (_this.initConfig.batchSend && _this.batchQueue.length > 0) {
2108
+ _this.saveBatchQueueToStorage();
2109
+ } // 保存 pendingRequests 到 LocalStorage(如果支持)
2110
+
2111
+
2112
+ if (_this.pendingRequests.length > 0) {
2113
+ try {
2114
+ _this.setLocalStorage(_this.PENDING_REQUESTS_STORAGE_KEY, JSON.stringify(_this.pendingRequests));
2115
+ } catch (e) {// LocalStorage 可能已满或不可用
2116
+ }
2117
+ }
2118
+ }
1829
2119
  };
1830
2120
  /**
1831
2121
  * 发送数据通用函数
@@ -1857,16 +2147,61 @@
1857
2147
  success: true,
1858
2148
  message: "已添加到批量队列"
1859
2149
  });
1860
- }
2150
+ } // 如果使用 sendBeacon 且没有自定义 header
2151
+
1861
2152
 
1862
2153
  if (_this.isSupportBeaconSend() === true && !header && !initHeader) {
2154
+ // 检查页面是否即将卸载,如果是,直接使用 sendBeacon 发送,避免被取消
2155
+ if (_this.isPageUnloading()) {
2156
+ var sent = _this.sendWithBeacon(params, serverUrl, contentType);
2157
+
2158
+ if (sent) {
2159
+ return Promise.resolve({
2160
+ success: true,
2161
+ message: "页面卸载时发送成功"
2162
+ });
2163
+ } else {
2164
+ // sendBeacon 返回 false,添加到待发送队列
2165
+ _this.addToPendingRequests(params);
2166
+
2167
+ return Promise.resolve({
2168
+ success: true,
2169
+ message: "已添加到待发送队列"
2170
+ });
2171
+ }
2172
+ } // 正常情况使用 sendBeacon
2173
+
2174
+
1863
2175
  return _this.sendBeacon({
1864
2176
  contentType: contentType,
1865
2177
  url: serverUrl,
1866
2178
  data: params
2179
+ }).catch(function (err) {
2180
+ // sendBeacon 失败,添加到待发送队列,避免数据丢失
2181
+ _this.addToPendingRequests(params);
2182
+
2183
+ return Promise.resolve({
2184
+ success: true,
2185
+ message: "sendBeacon 失败,已添加到待发送队列"
2186
+ });
1867
2187
  });
1868
2188
  } else {
2189
+ // 使用 XMLHttpRequest 发送
1869
2190
  return new Promise(function (resolve, reject) {
2191
+ // 如果页面即将卸载,也尝试使用 sendBeacon 作为备用
2192
+ if (_this.isPageUnloading() && _this.isSupportBeaconSend() && !header && !initHeader) {
2193
+ var sent = _this.sendWithBeacon(params, serverUrl, contentType);
2194
+
2195
+ if (sent) {
2196
+ resolve({
2197
+ success: true,
2198
+ message: "页面卸载时使用 sendBeacon 发送成功"
2199
+ });
2200
+ return;
2201
+ } // sendBeacon 失败,继续使用 XMLHttpRequest
2202
+
2203
+ }
2204
+
1870
2205
  _this.ajax({
1871
2206
  header: header || initHeader,
1872
2207
  url: serverUrl,
@@ -1883,7 +2218,20 @@
1883
2218
  });
1884
2219
  },
1885
2220
  error: function error(err, status) {
1886
- return reject({
2221
+ // 如果请求失败且页面即将卸载,尝试使用 sendBeacon
2222
+ if (_this.isPageUnloading() && _this.isSupportBeaconSend() && !header && !initHeader) {
2223
+ var sent = _this.sendWithBeacon(params, serverUrl, contentType);
2224
+
2225
+ if (sent) {
2226
+ resolve({
2227
+ success: true,
2228
+ message: "XMLHttpRequest 失败,已使用 sendBeacon 发送"
2229
+ });
2230
+ return;
2231
+ }
2232
+ }
2233
+
2234
+ reject({
1887
2235
  success: false,
1888
2236
  message: String(err),
1889
2237
  code: status
@@ -1928,9 +2276,9 @@
1928
2276
  */
1929
2277
 
1930
2278
 
1931
- _this.getItemKey = function (partkey) {
2279
+ _this.getItemKey = function (partkey, pageKey) {
1932
2280
  var appKey = _this.initConfig.appKey;
1933
- var keys = [appKey, _this.pageKey, partkey ? partkey.toString() : undefined].filter(function (key) {
2281
+ var keys = [appKey, (pageKey || _this.pageKey).toString(), partkey ? partkey.toString() : undefined].filter(function (key) {
1934
2282
  return !!key;
1935
2283
  });
1936
2284
  return keys.reduce(function (str, key) {
@@ -1954,7 +2302,9 @@
1954
2302
  sampleRate: 1,
1955
2303
  batchSend: false,
1956
2304
  batchInterval: 5000,
1957
- batchMaxSize: 10 // 批量发送最大数量
2305
+ batchMaxSize: 10,
2306
+ trackPartKeyClick: false,
2307
+ pendingRequestsMaxSize: 50 // 待发送请求队列最大数量(防止内存溢出)
1958
2308
 
1959
2309
  }; // 系统信息
1960
2310