@uxda/appkit 4.2.93 → 4.2.94
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/dist/index.js +1082 -22
- package/package.json +2 -1
- package/src/payment/components/RechargeView.vue +2 -1
- package/src/payment/types.ts +1 -0
- package/src/shared/index.ts +1 -0
- package/src/shared/tracking/README.md +509 -0
- package/src/shared/tracking/directives/index.ts +40 -0
- package/src/shared/tracking/directives/track-click.ts +142 -0
- package/src/shared/tracking/directives/track-page.ts +50 -0
- package/src/shared/tracking/directives/track-scroll.ts +116 -0
- package/src/shared/tracking/directives/track-search.ts +179 -0
- package/src/shared/tracking/examples/data-structure-example.ts +239 -0
- package/src/shared/tracking/examples/directive-tracking-example.vue +202 -0
- package/src/shared/tracking/examples/global-tracking-example.vue +25 -0
- package/src/shared/tracking/examples/page-tracking-template.vue +27 -0
- package/src/shared/tracking/examples/sdk-tracking-example.vue +33 -0
- package/src/shared/tracking/index.ts +5 -0
- package/src/shared/tracking/tracking-init.ts +214 -0
- package/src/shared/tracking/tracking-sdk.ts +986 -0
- package/src/shared/tracking/useAutoTracking.ts +108 -0
package/dist/index.js
CHANGED
|
@@ -4,19 +4,21 @@ import '@nutui/nutui-taro/dist/packages/checkbox/style/css';
|
|
|
4
4
|
import { defineComponent, reactive, openBlock, createBlock, withCtx, createElementBlock, Fragment, renderList, normalizeClass, createElementVNode, toDisplayString, createTextVNode, ref, computed, onUnmounted, resolveDirective, createCommentVNode, withDirectives, renderSlot, createVNode, normalizeStyle, unref, isRef, onMounted, createStaticVNode, watch, vShow, mergeModels, useModel, resolveComponent, vModelText, watchPostEffect, withModifiers } from 'vue';
|
|
5
5
|
import '@nutui/nutui-taro/dist/packages/grid/style/css';
|
|
6
6
|
import '@nutui/nutui-taro/dist/packages/griditem/style/css';
|
|
7
|
-
import Taro, { showModal, getSystemInfoSync, getMenuButtonBoundingClientRect, uploadFile, request as request$1, showToast, chooseMedia, chooseMessageFile, showLoading, hideLoading,
|
|
7
|
+
import Taro, { showModal, getSystemInfoSync, getMenuButtonBoundingClientRect, uploadFile, request as request$1, showToast, chooseMedia, chooseMessageFile, showLoading, hideLoading, getStorageSync, setStorageSync, getSystemInfo, getNetworkType, getEnv, getAccountInfoSync, getPerformance, onAppHide, useDidShow, onAppShow, onNetworkStatusChange, useRouter } from '@tarojs/taro';
|
|
8
8
|
import '@nutui/nutui-taro/dist/packages/popup/style/css';
|
|
9
9
|
import isMobilePhone from 'validator/es/lib/isMobilePhone';
|
|
10
10
|
import isIdentityCard from 'validator/es/lib/isIdentityCard';
|
|
11
11
|
import { NsForm, NsInput, NsButton, NsIcon, usePopup, useNutshell, NsButtonGroup, usePaging, NsPage, NsTabs, NsTabsItem, NsPageContent, NsSkeleton, NsRepeator, NsCard, NsEmpty, NsCheckbox } from '@uxda/nutshell/taro';
|
|
12
12
|
import '@nutui/nutui-taro/dist/packages/actionsheet/style/css';
|
|
13
|
+
import pako from 'pako';
|
|
14
|
+
import dsBridge from 'dsbridge';
|
|
15
|
+
import { debounce as debounce$1 } from 'lodash-es';
|
|
13
16
|
import debounce from 'lodash-es/debounce';
|
|
14
17
|
import '@nutui/nutui-taro/dist/packages/dialog/style/css';
|
|
15
18
|
import '@nutui/nutui-taro/dist/packages/datepicker/style/css';
|
|
16
19
|
import dayjs from 'dayjs';
|
|
17
20
|
import groupBy from 'lodash-es/groupBy';
|
|
18
21
|
import { ScrollView, Swiper, SwiperItem } from '@tarojs/components';
|
|
19
|
-
import dsBridge from 'dsbridge';
|
|
20
22
|
import { IconFont } from '@nutui/icons-vue-taro';
|
|
21
23
|
import '@nutui/nutui-taro/dist/packages/form/style/css';
|
|
22
24
|
import '@nutui/nutui-taro/dist/packages/formitem/style/css';
|
|
@@ -1519,6 +1521,1081 @@ function createHttp(config) {
|
|
|
1519
1521
|
};
|
|
1520
1522
|
}
|
|
1521
1523
|
|
|
1524
|
+
function dataURItoBlob(dataURI) {
|
|
1525
|
+
const byteString = atob(dataURI.split(",")[1]);
|
|
1526
|
+
const mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0];
|
|
1527
|
+
const ab = new ArrayBuffer(byteString.length);
|
|
1528
|
+
const ia = new Uint8Array(ab);
|
|
1529
|
+
for (let i = 0; i < byteString.length; i++) {
|
|
1530
|
+
ia[i] = byteString.charCodeAt(i);
|
|
1531
|
+
}
|
|
1532
|
+
return new Blob([ab], { type: mimeString });
|
|
1533
|
+
}
|
|
1534
|
+
function isWeb() {
|
|
1535
|
+
const env = process.env.TARO_ENV || "";
|
|
1536
|
+
return env === "h5" || Taro.getEnv() === "WEB";
|
|
1537
|
+
}
|
|
1538
|
+
function isApp() {
|
|
1539
|
+
return dsBridge.hasNativeMethod("openWebPage");
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
var __defProp = Object.defineProperty;
|
|
1543
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1544
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1545
|
+
const DEFAULT_CONFIG = {
|
|
1546
|
+
enabled: true,
|
|
1547
|
+
debug: false,
|
|
1548
|
+
batchSize: 30,
|
|
1549
|
+
flushInterval: 1e5,
|
|
1550
|
+
apiEndpoint: ""
|
|
1551
|
+
};
|
|
1552
|
+
class TrackingSDK {
|
|
1553
|
+
// 用户信息(优先使用)
|
|
1554
|
+
constructor(config = {}) {
|
|
1555
|
+
__publicField(this, "config");
|
|
1556
|
+
__publicField(this, "eventQueue", []);
|
|
1557
|
+
__publicField(this, "currentPage", "");
|
|
1558
|
+
__publicField(this, "pageStartTime", 0);
|
|
1559
|
+
__publicField(this, "flushTimer", null);
|
|
1560
|
+
__publicField(this, "isInitialized", false);
|
|
1561
|
+
__publicField(this, "pageHistory", []);
|
|
1562
|
+
// 页面历史记录
|
|
1563
|
+
__publicField(this, "PAGE_HISTORY_KEY", "tracking_page_history");
|
|
1564
|
+
// 存储键
|
|
1565
|
+
__publicField(this, "MAX_HISTORY_LENGTH", 10);
|
|
1566
|
+
// 最大历史记录数
|
|
1567
|
+
__publicField(this, "userInfo");
|
|
1568
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
1569
|
+
if (config.userInfo) {
|
|
1570
|
+
this.userInfo = config.userInfo;
|
|
1571
|
+
}
|
|
1572
|
+
this.init();
|
|
1573
|
+
}
|
|
1574
|
+
/**
|
|
1575
|
+
* 初始化SDK
|
|
1576
|
+
*/
|
|
1577
|
+
init() {
|
|
1578
|
+
if (this.isInitialized) return;
|
|
1579
|
+
this.isInitialized = true;
|
|
1580
|
+
this.loadPageHistory();
|
|
1581
|
+
this.setupAutoTracking();
|
|
1582
|
+
this.startFlushTimer();
|
|
1583
|
+
if (this.config.debug) {
|
|
1584
|
+
console.log("[TrackingSDK] \u521D\u59CB\u5316\u5B8C\u6210", this.config);
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
/**
|
|
1588
|
+
* 加载页面历史记录
|
|
1589
|
+
*/
|
|
1590
|
+
loadPageHistory() {
|
|
1591
|
+
try {
|
|
1592
|
+
const historyStr = getStorageSync(this.PAGE_HISTORY_KEY);
|
|
1593
|
+
if (historyStr) {
|
|
1594
|
+
this.pageHistory = JSON.parse(historyStr);
|
|
1595
|
+
}
|
|
1596
|
+
} catch (error) {
|
|
1597
|
+
if (this.config.debug) {
|
|
1598
|
+
console.log("[TrackingSDK] \u52A0\u8F7D\u9875\u9762\u5386\u53F2\u5931\u8D25:", error);
|
|
1599
|
+
}
|
|
1600
|
+
this.pageHistory = [];
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
/**
|
|
1604
|
+
* 简单的Token加密 (Base64 + 反转)
|
|
1605
|
+
* @returns 加密后的token字符串
|
|
1606
|
+
*/
|
|
1607
|
+
encryptToken() {
|
|
1608
|
+
const raw = `Ddjf@Log1125|${Date.now()}`;
|
|
1609
|
+
let base64;
|
|
1610
|
+
if (typeof btoa !== "undefined") {
|
|
1611
|
+
base64 = btoa(unescape(encodeURIComponent(raw)));
|
|
1612
|
+
} else {
|
|
1613
|
+
base64 = this.base64Encode(raw);
|
|
1614
|
+
}
|
|
1615
|
+
return base64.split("").reverse().join("");
|
|
1616
|
+
}
|
|
1617
|
+
/**
|
|
1618
|
+
* Base64 编码(降级方案)
|
|
1619
|
+
*/
|
|
1620
|
+
base64Encode(str) {
|
|
1621
|
+
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
|
1622
|
+
let output = "";
|
|
1623
|
+
let i = 0;
|
|
1624
|
+
while (i < str.length) {
|
|
1625
|
+
const a = str.charCodeAt(i++);
|
|
1626
|
+
const b = i < str.length ? str.charCodeAt(i++) : 0;
|
|
1627
|
+
const c = i < str.length ? str.charCodeAt(i++) : 0;
|
|
1628
|
+
const bitmap = a << 16 | b << 8 | c;
|
|
1629
|
+
output += chars.charAt(bitmap >> 18 & 63);
|
|
1630
|
+
output += chars.charAt(bitmap >> 12 & 63);
|
|
1631
|
+
output += i - 2 < str.length ? chars.charAt(bitmap >> 6 & 63) : "=";
|
|
1632
|
+
output += i - 1 < str.length ? chars.charAt(bitmap & 63) : "=";
|
|
1633
|
+
}
|
|
1634
|
+
return output;
|
|
1635
|
+
}
|
|
1636
|
+
/**
|
|
1637
|
+
* 保存页面历史记录
|
|
1638
|
+
*/
|
|
1639
|
+
savePageHistory() {
|
|
1640
|
+
try {
|
|
1641
|
+
setStorageSync(this.PAGE_HISTORY_KEY, JSON.stringify(this.pageHistory));
|
|
1642
|
+
} catch (error) {
|
|
1643
|
+
if (this.config.debug) {
|
|
1644
|
+
console.log("[TrackingSDK] \u4FDD\u5B58\u9875\u9762\u5386\u53F2\u5931\u8D25:", error);
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
/**
|
|
1649
|
+
* 添加页面到历史记录
|
|
1650
|
+
*/
|
|
1651
|
+
addPageToHistory(route, title) {
|
|
1652
|
+
const history = {
|
|
1653
|
+
route,
|
|
1654
|
+
title,
|
|
1655
|
+
timestamp: Date.now()
|
|
1656
|
+
};
|
|
1657
|
+
this.pageHistory.push(history);
|
|
1658
|
+
if (this.pageHistory.length > this.MAX_HISTORY_LENGTH) {
|
|
1659
|
+
this.pageHistory.shift();
|
|
1660
|
+
}
|
|
1661
|
+
this.savePageHistory();
|
|
1662
|
+
}
|
|
1663
|
+
/**
|
|
1664
|
+
* 获取上一页信息(从历史记录中)
|
|
1665
|
+
*/
|
|
1666
|
+
getLastPageFromHistory() {
|
|
1667
|
+
if (this.pageHistory.length >= 2) {
|
|
1668
|
+
return this.pageHistory[this.pageHistory.length - 2];
|
|
1669
|
+
}
|
|
1670
|
+
return null;
|
|
1671
|
+
}
|
|
1672
|
+
/**
|
|
1673
|
+
* 清空页面历史记录
|
|
1674
|
+
*/
|
|
1675
|
+
clearPageHistory() {
|
|
1676
|
+
this.pageHistory = [];
|
|
1677
|
+
this.savePageHistory();
|
|
1678
|
+
}
|
|
1679
|
+
/**
|
|
1680
|
+
* 获取用户信息
|
|
1681
|
+
* 优先级:1. 初始化时传入的userInfo 2. Storage中的用户信息 3. 生成新的sessionId
|
|
1682
|
+
*/
|
|
1683
|
+
getUserInfo() {
|
|
1684
|
+
if (this.userInfo) {
|
|
1685
|
+
return {
|
|
1686
|
+
userId: this.userInfo.userId,
|
|
1687
|
+
tenantId: this.userInfo.tenantId,
|
|
1688
|
+
sessionId: this.userInfo.sessionId || this.generateSessionId()
|
|
1689
|
+
};
|
|
1690
|
+
}
|
|
1691
|
+
return { sessionId: this.generateSessionId() };
|
|
1692
|
+
}
|
|
1693
|
+
/**
|
|
1694
|
+
* 生成会话ID
|
|
1695
|
+
*/
|
|
1696
|
+
generateSessionId() {
|
|
1697
|
+
return `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
1698
|
+
}
|
|
1699
|
+
/**
|
|
1700
|
+
* 获取设备信息
|
|
1701
|
+
*/
|
|
1702
|
+
async getDeviceInfo() {
|
|
1703
|
+
try {
|
|
1704
|
+
const systemInfo = await getSystemInfo();
|
|
1705
|
+
let networkType = "";
|
|
1706
|
+
try {
|
|
1707
|
+
const networkInfo = await getNetworkType();
|
|
1708
|
+
networkType = networkInfo.networkType || "";
|
|
1709
|
+
} catch {
|
|
1710
|
+
networkType = "";
|
|
1711
|
+
}
|
|
1712
|
+
return {
|
|
1713
|
+
device_type: systemInfo.platform === "ios" || systemInfo.platform === "android" ? "mobile" : "desktop",
|
|
1714
|
+
os: systemInfo.platform,
|
|
1715
|
+
os_version: systemInfo.system,
|
|
1716
|
+
brand: systemInfo.brand || "",
|
|
1717
|
+
model: systemInfo.model || "",
|
|
1718
|
+
network_type: networkType
|
|
1719
|
+
};
|
|
1720
|
+
} catch {
|
|
1721
|
+
return {};
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
/**
|
|
1725
|
+
* 获取应用信息
|
|
1726
|
+
*/
|
|
1727
|
+
getAppInfo() {
|
|
1728
|
+
try {
|
|
1729
|
+
const env = getEnv();
|
|
1730
|
+
if (env === "WEAPP") {
|
|
1731
|
+
const accountInfo = getAccountInfoSync?.();
|
|
1732
|
+
return {
|
|
1733
|
+
app_version: accountInfo?.miniProgram?.version || "1.0.0",
|
|
1734
|
+
package_name: accountInfo?.miniProgram?.appId || "",
|
|
1735
|
+
app_channel: "WeChat"
|
|
1736
|
+
};
|
|
1737
|
+
} else {
|
|
1738
|
+
return {
|
|
1739
|
+
app_version: "1.0.0",
|
|
1740
|
+
package_name: "",
|
|
1741
|
+
app_channel: env === "WEB" ? "H5" : "App Store"
|
|
1742
|
+
};
|
|
1743
|
+
}
|
|
1744
|
+
} catch {
|
|
1745
|
+
return {
|
|
1746
|
+
app_version: "1.0.0",
|
|
1747
|
+
package_name: "",
|
|
1748
|
+
app_channel: getEnv() === "WEB" ? "H5" : "Unknown"
|
|
1749
|
+
};
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
/**
|
|
1753
|
+
* 获取来源类型
|
|
1754
|
+
*/
|
|
1755
|
+
getSourceType() {
|
|
1756
|
+
const env = getEnv();
|
|
1757
|
+
if (isApp()) return "app";
|
|
1758
|
+
if (env === "WEB") return "H5";
|
|
1759
|
+
if (env === "WEAPP") return "app";
|
|
1760
|
+
return "PC";
|
|
1761
|
+
}
|
|
1762
|
+
/**
|
|
1763
|
+
* 获取页面性能数据
|
|
1764
|
+
*/
|
|
1765
|
+
async getPerformanceData() {
|
|
1766
|
+
try {
|
|
1767
|
+
const performanceData = {};
|
|
1768
|
+
const env = getEnv();
|
|
1769
|
+
if (env === "WEB") {
|
|
1770
|
+
if (typeof window !== "undefined" && window.performance) {
|
|
1771
|
+
const perfEntries = window.performance.getEntriesByType("navigation");
|
|
1772
|
+
if (perfEntries && perfEntries.length > 0) {
|
|
1773
|
+
const navigationTiming = perfEntries[0];
|
|
1774
|
+
performanceData.page_load_time = Math.round(navigationTiming.duration || 0);
|
|
1775
|
+
performanceData.response_time = Math.round(
|
|
1776
|
+
(navigationTiming.responseEnd || 0) - (navigationTiming.requestStart || 0)
|
|
1777
|
+
);
|
|
1778
|
+
}
|
|
1779
|
+
const memory = window.performance.memory;
|
|
1780
|
+
if (memory) {
|
|
1781
|
+
const usedMemory = memory.usedJSHeapSize || 0;
|
|
1782
|
+
const totalMemory = memory.jsHeapSizeLimit || 0;
|
|
1783
|
+
if (totalMemory > 0) {
|
|
1784
|
+
performanceData.memory_usage = Number((usedMemory / totalMemory * 100).toFixed(2));
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
} else {
|
|
1789
|
+
const performance = await getPerformance();
|
|
1790
|
+
if (performance) {
|
|
1791
|
+
const entryList = performance.getEntriesByType?.("navigation");
|
|
1792
|
+
if (entryList && entryList.length > 0) {
|
|
1793
|
+
const navigationTiming = entryList[0];
|
|
1794
|
+
performanceData.page_load_time = Math.round(navigationTiming.duration || 0);
|
|
1795
|
+
performanceData.response_time = Math.round(
|
|
1796
|
+
(navigationTiming.responseEnd || 0) - (navigationTiming.requestStart || 0)
|
|
1797
|
+
);
|
|
1798
|
+
}
|
|
1799
|
+
if (env === "WEAPP") {
|
|
1800
|
+
try {
|
|
1801
|
+
const performanceObj = performance;
|
|
1802
|
+
const memoryInfo = performanceObj?.getMemoryInfo?.();
|
|
1803
|
+
if (memoryInfo) {
|
|
1804
|
+
const usedMemory = memoryInfo.usedJSHeapSize || 0;
|
|
1805
|
+
const totalMemory = memoryInfo.totalJSHeapSize || memoryInfo.jsHeapSizeLimit || 0;
|
|
1806
|
+
if (totalMemory > 0) {
|
|
1807
|
+
performanceData.memory_usage = Number(
|
|
1808
|
+
(usedMemory / totalMemory * 100).toFixed(2)
|
|
1809
|
+
);
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
} catch {
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
return performanceData;
|
|
1818
|
+
} catch (error) {
|
|
1819
|
+
if (this.config.debug) {
|
|
1820
|
+
console.log("[TrackingSDK] \u83B7\u53D6\u6027\u80FD\u6570\u636E\u5931\u8D25:", error);
|
|
1821
|
+
}
|
|
1822
|
+
return {};
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
/**
|
|
1826
|
+
* 创建基础埋点数据(新版数据结构)
|
|
1827
|
+
*/
|
|
1828
|
+
async createBaseTrackingData(eventType, customData) {
|
|
1829
|
+
const userInfo = this.getUserInfo();
|
|
1830
|
+
const pagePath = customData?.pagePath || this.currentPage || "";
|
|
1831
|
+
const now = Date.now();
|
|
1832
|
+
const pageData = {};
|
|
1833
|
+
const eventData = {};
|
|
1834
|
+
let logType = "";
|
|
1835
|
+
let appInfo = {};
|
|
1836
|
+
let deviceInfo = {};
|
|
1837
|
+
let performanceData = {};
|
|
1838
|
+
if (eventType === "app_device_info" /* APP_DEVICE_INFO */) {
|
|
1839
|
+
deviceInfo = await this.getDeviceInfo();
|
|
1840
|
+
appInfo = this.getAppInfo();
|
|
1841
|
+
} else {
|
|
1842
|
+
if (pagePath) {
|
|
1843
|
+
pageData.page_url = pagePath;
|
|
1844
|
+
pageData.page_name = customData?.pageTitle || this.getPageTitle(pagePath);
|
|
1845
|
+
pageData.page_referrer = customData?.lastPagePath || "";
|
|
1846
|
+
pageData.previous_page_name = customData?.lastPageTitle || "";
|
|
1847
|
+
if (this.pageStartTime) {
|
|
1848
|
+
pageData.page_start_time = new Date(this.pageStartTime).toISOString();
|
|
1849
|
+
pageData.page_duration = now - this.pageStartTime;
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
if (eventType === "click" /* CLICK */) {
|
|
1853
|
+
eventData.event_type = "click";
|
|
1854
|
+
eventData.event_name = customData?.elementText || customData?.businessData?.elementText || "\u70B9\u51FB\u4E8B\u4EF6";
|
|
1855
|
+
eventData.element_id = customData?.elementId || "";
|
|
1856
|
+
} else if (eventType === "custom" /* CUSTOM */) {
|
|
1857
|
+
eventData.event_type = "custom";
|
|
1858
|
+
eventData.event_name = customData?.businessData?.eventName || "\u81EA\u5B9A\u4E49\u4E8B\u4EF6";
|
|
1859
|
+
} else {
|
|
1860
|
+
eventData.event_type = eventType;
|
|
1861
|
+
eventData.event_name = eventType;
|
|
1862
|
+
}
|
|
1863
|
+
if (eventType === "page_view" /* PAGE_VIEW */ || customData?.businessData?.performance) {
|
|
1864
|
+
performanceData = await this.getPerformanceData();
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
if (["click" /* CLICK */, "custom" /* CUSTOM */].includes(eventType)) {
|
|
1868
|
+
logType = "event";
|
|
1869
|
+
} else if (["page_view" /* PAGE_VIEW */, "page_leave" /* PAGE_LEAVE */].includes(eventType)) {
|
|
1870
|
+
logType = "page";
|
|
1871
|
+
} else if (["app_device_info" /* APP_DEVICE_INFO */].includes(eventType)) {
|
|
1872
|
+
logType = "device";
|
|
1873
|
+
}
|
|
1874
|
+
const finalPerformanceData = {
|
|
1875
|
+
...performanceData,
|
|
1876
|
+
...customData?.businessData?.performance
|
|
1877
|
+
};
|
|
1878
|
+
const logData = {};
|
|
1879
|
+
if (Object.keys(pageData).length > 0) {
|
|
1880
|
+
logData.page = pageData;
|
|
1881
|
+
}
|
|
1882
|
+
if (Object.keys(eventData).length > 0) {
|
|
1883
|
+
logData.event = eventData;
|
|
1884
|
+
}
|
|
1885
|
+
if (Object.keys(appInfo).length > 0) {
|
|
1886
|
+
logData.app = appInfo;
|
|
1887
|
+
}
|
|
1888
|
+
if (Object.keys(deviceInfo).length > 0) {
|
|
1889
|
+
logData.device = deviceInfo;
|
|
1890
|
+
}
|
|
1891
|
+
if (Object.keys(finalPerformanceData).length > 0) {
|
|
1892
|
+
logData.performance = finalPerformanceData;
|
|
1893
|
+
}
|
|
1894
|
+
const errorData = customData?.businessData?.error;
|
|
1895
|
+
if (errorData && Object.keys(errorData).length > 0) {
|
|
1896
|
+
logData.error = errorData;
|
|
1897
|
+
}
|
|
1898
|
+
const trackingData = {
|
|
1899
|
+
log_id: `${now}_${Math.random().toString(36).substr(2, 9)}`,
|
|
1900
|
+
log_time: now,
|
|
1901
|
+
log_type: logType || "event",
|
|
1902
|
+
tenant_id: customData?.tenantId || userInfo.tenantId || "",
|
|
1903
|
+
user_id: customData?.userId || userInfo.userId || "",
|
|
1904
|
+
source: this.getSourceType(),
|
|
1905
|
+
session_id: userInfo.sessionId || "",
|
|
1906
|
+
log_data: logData
|
|
1907
|
+
};
|
|
1908
|
+
return trackingData;
|
|
1909
|
+
}
|
|
1910
|
+
/**
|
|
1911
|
+
* 根据页面路径获取页面标题
|
|
1912
|
+
*/
|
|
1913
|
+
getPageTitle(pagePath) {
|
|
1914
|
+
const titleMap = {
|
|
1915
|
+
"/aiapprove/pages": "AI\u5BA1\u6279",
|
|
1916
|
+
"/aiapprove/views": "\u4F01\u660E\u661F",
|
|
1917
|
+
"/pages/beidou": "\u5317\u6597\u661F",
|
|
1918
|
+
"/pages/contracts": "\u8702\u9E1F\u7B7E\u7EA6",
|
|
1919
|
+
"/pages/user": "\u6211\u7684"
|
|
1920
|
+
};
|
|
1921
|
+
for (const [path, title] of Object.entries(titleMap)) {
|
|
1922
|
+
if (pagePath.includes(path)) {
|
|
1923
|
+
return title;
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
return pagePath;
|
|
1927
|
+
}
|
|
1928
|
+
/**
|
|
1929
|
+
* 添加埋点数据到队列
|
|
1930
|
+
*/
|
|
1931
|
+
addToQueue(data) {
|
|
1932
|
+
if (!this.config.enabled) return;
|
|
1933
|
+
this.eventQueue.push(data);
|
|
1934
|
+
if (this.config.debug) {
|
|
1935
|
+
console.log("[TrackingSDK] \u6DFB\u52A0\u57CB\u70B9\u6570\u636E:", data);
|
|
1936
|
+
}
|
|
1937
|
+
if (this.eventQueue.length >= this.config.batchSize) {
|
|
1938
|
+
this.flush();
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
/**
|
|
1942
|
+
* 发送埋点数据
|
|
1943
|
+
*/
|
|
1944
|
+
async flush() {
|
|
1945
|
+
if (this.eventQueue.length === 0) return;
|
|
1946
|
+
const events = [...this.eventQueue];
|
|
1947
|
+
this.eventQueue = [];
|
|
1948
|
+
try {
|
|
1949
|
+
const jsonStr = JSON.stringify(events);
|
|
1950
|
+
const compressed = pako.deflate(jsonStr);
|
|
1951
|
+
const encryptedToken = this.encryptToken();
|
|
1952
|
+
const { success } = await this.http({
|
|
1953
|
+
url: `${this.config.apiEndpoint}?contentId=${encryptedToken}`,
|
|
1954
|
+
method: "POST",
|
|
1955
|
+
data: compressed,
|
|
1956
|
+
header: {
|
|
1957
|
+
"Content-Encoding": "deflate"
|
|
1958
|
+
}
|
|
1959
|
+
});
|
|
1960
|
+
if (success && this.config.debug) {
|
|
1961
|
+
console.log("[TrackingSDK] \u57CB\u70B9\u6570\u636E\u53D1\u9001\u6210\u529F:", events.length, "\u6761");
|
|
1962
|
+
}
|
|
1963
|
+
} catch (error) {
|
|
1964
|
+
console.error("[TrackingSDK] \u57CB\u70B9\u6570\u636E\u53D1\u9001\u5931\u8D25:", error);
|
|
1965
|
+
if (events.length > 0) {
|
|
1966
|
+
this.eventQueue.unshift(...events);
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
/**
|
|
1971
|
+
* 请求拦截
|
|
1972
|
+
*/
|
|
1973
|
+
http(params) {
|
|
1974
|
+
return new Promise((resolve, reject) => {
|
|
1975
|
+
request$1({
|
|
1976
|
+
url: params.url,
|
|
1977
|
+
method: params.method || "GET",
|
|
1978
|
+
data: params.data,
|
|
1979
|
+
header: params.header
|
|
1980
|
+
}).then((res) => {
|
|
1981
|
+
console.log("===res", res);
|
|
1982
|
+
resolve(res.data);
|
|
1983
|
+
}).catch((err) => {
|
|
1984
|
+
reject(err);
|
|
1985
|
+
});
|
|
1986
|
+
});
|
|
1987
|
+
}
|
|
1988
|
+
/**
|
|
1989
|
+
* 启动定时刷新
|
|
1990
|
+
*/
|
|
1991
|
+
startFlushTimer() {
|
|
1992
|
+
if (this.flushTimer) {
|
|
1993
|
+
clearInterval(this.flushTimer);
|
|
1994
|
+
}
|
|
1995
|
+
this.flushTimer = setInterval(() => {
|
|
1996
|
+
this.flush();
|
|
1997
|
+
}, this.config.flushInterval);
|
|
1998
|
+
}
|
|
1999
|
+
/**
|
|
2000
|
+
* 设置自动埋点
|
|
2001
|
+
*/
|
|
2002
|
+
setupAutoTracking() {
|
|
2003
|
+
onAppHide(() => {
|
|
2004
|
+
this.trackPageLeave();
|
|
2005
|
+
this.flushNow();
|
|
2006
|
+
});
|
|
2007
|
+
if (getEnv() === "WEB" && typeof window !== "undefined") {
|
|
2008
|
+
window.addEventListener("beforeunload", () => {
|
|
2009
|
+
this.flushNow();
|
|
2010
|
+
});
|
|
2011
|
+
document.addEventListener("visibilitychange", () => {
|
|
2012
|
+
if (document.visibilityState === "hidden") {
|
|
2013
|
+
this.flushNow();
|
|
2014
|
+
}
|
|
2015
|
+
});
|
|
2016
|
+
window.addEventListener("pagehide", () => {
|
|
2017
|
+
this.flushNow();
|
|
2018
|
+
});
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
/**
|
|
2022
|
+
* 手动埋点 - 页面访问
|
|
2023
|
+
*/
|
|
2024
|
+
async trackPageView(pageTitle) {
|
|
2025
|
+
const currentPage = this.getPageInfoByIndex();
|
|
2026
|
+
const currentPath = currentPage.route || "";
|
|
2027
|
+
const currentTitle = pageTitle || currentPage.options?.title || currentPage.config?.navigationBarTitleText || "";
|
|
2028
|
+
if (currentPath) {
|
|
2029
|
+
this.addPageToHistory(currentPath, currentTitle);
|
|
2030
|
+
}
|
|
2031
|
+
let lastPath = "";
|
|
2032
|
+
let lastTitle = "";
|
|
2033
|
+
const lastPageHistory = this.getLastPageFromHistory();
|
|
2034
|
+
if (lastPageHistory) {
|
|
2035
|
+
lastPath = lastPageHistory.route;
|
|
2036
|
+
lastTitle = lastPageHistory.title;
|
|
2037
|
+
}
|
|
2038
|
+
this.currentPage = currentPath;
|
|
2039
|
+
this.pageStartTime = Date.now();
|
|
2040
|
+
const data = await this.createBaseTrackingData("page_view" /* PAGE_VIEW */, {
|
|
2041
|
+
pagePath: currentPath,
|
|
2042
|
+
pageTitle: currentTitle,
|
|
2043
|
+
lastPagePath: lastPath,
|
|
2044
|
+
lastPageTitle: lastTitle
|
|
2045
|
+
});
|
|
2046
|
+
this.addToQueue(data);
|
|
2047
|
+
}
|
|
2048
|
+
/**
|
|
2049
|
+
* 手动埋点 - 页面离开
|
|
2050
|
+
*/
|
|
2051
|
+
async trackPageLeave(pagePath) {
|
|
2052
|
+
const path = pagePath || this.currentPage;
|
|
2053
|
+
if (!path) return;
|
|
2054
|
+
const data = await this.createBaseTrackingData("page_leave" /* PAGE_LEAVE */, {
|
|
2055
|
+
pagePath: path
|
|
2056
|
+
});
|
|
2057
|
+
this.addToQueue(data);
|
|
2058
|
+
}
|
|
2059
|
+
/**
|
|
2060
|
+
* 手动埋点 - 点击事件
|
|
2061
|
+
*/
|
|
2062
|
+
async trackClick(elementId, elementText) {
|
|
2063
|
+
const data = await this.createBaseTrackingData("click" /* CLICK */, {
|
|
2064
|
+
elementId,
|
|
2065
|
+
elementText
|
|
2066
|
+
});
|
|
2067
|
+
this.addToQueue(data);
|
|
2068
|
+
}
|
|
2069
|
+
/**
|
|
2070
|
+
* 手动埋点 - 自定义事件
|
|
2071
|
+
*/
|
|
2072
|
+
async trackCustom(eventName, customData) {
|
|
2073
|
+
const data = await this.createBaseTrackingData("custom" /* CUSTOM */, {
|
|
2074
|
+
businessData: {
|
|
2075
|
+
eventName,
|
|
2076
|
+
...customData
|
|
2077
|
+
}
|
|
2078
|
+
});
|
|
2079
|
+
this.addToQueue(data);
|
|
2080
|
+
}
|
|
2081
|
+
/**
|
|
2082
|
+
* 手动埋点 - 业务事件
|
|
2083
|
+
*/
|
|
2084
|
+
async trackBusiness(event, businessData) {
|
|
2085
|
+
const data = await this.createBaseTrackingData(event, {
|
|
2086
|
+
businessData
|
|
2087
|
+
});
|
|
2088
|
+
this.addToQueue(data);
|
|
2089
|
+
}
|
|
2090
|
+
/**
|
|
2091
|
+
* 手动埋点 - app 和 device 信息
|
|
2092
|
+
*/
|
|
2093
|
+
async trackAppDeviceInfo() {
|
|
2094
|
+
const data = await this.createBaseTrackingData("app_device_info" /* APP_DEVICE_INFO */, {});
|
|
2095
|
+
this.addToQueue(data);
|
|
2096
|
+
}
|
|
2097
|
+
/**
|
|
2098
|
+
* 获取指定页面信息
|
|
2099
|
+
*/
|
|
2100
|
+
getPageInfoByIndex(index = 1) {
|
|
2101
|
+
try {
|
|
2102
|
+
const pages = getCurrentPages();
|
|
2103
|
+
const currentPage = pages[pages.length - index];
|
|
2104
|
+
return currentPage || {};
|
|
2105
|
+
} catch {
|
|
2106
|
+
return {};
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
/**
|
|
2110
|
+
* 更新配置
|
|
2111
|
+
*/
|
|
2112
|
+
updateConfig(newConfig) {
|
|
2113
|
+
this.config = {
|
|
2114
|
+
enabled: newConfig.enabled ?? this.config.enabled,
|
|
2115
|
+
debug: newConfig.debug ?? this.config.debug,
|
|
2116
|
+
batchSize: newConfig.batchSize ?? this.config.batchSize,
|
|
2117
|
+
flushInterval: newConfig.flushInterval ?? this.config.flushInterval,
|
|
2118
|
+
apiEndpoint: newConfig.apiEndpoint ?? this.config.apiEndpoint,
|
|
2119
|
+
userInfo: newConfig.userInfo ?? this.userInfo
|
|
2120
|
+
};
|
|
2121
|
+
if (newConfig.userInfo !== void 0) {
|
|
2122
|
+
this.userInfo = newConfig.userInfo;
|
|
2123
|
+
}
|
|
2124
|
+
if (newConfig.flushInterval) {
|
|
2125
|
+
this.startFlushTimer();
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
/**
|
|
2129
|
+
* 立即发送所有待发送的数据(同步方式)
|
|
2130
|
+
*/
|
|
2131
|
+
flushNow() {
|
|
2132
|
+
if (this.eventQueue.length === 0) return;
|
|
2133
|
+
const events = [...this.eventQueue];
|
|
2134
|
+
this.eventQueue = [];
|
|
2135
|
+
try {
|
|
2136
|
+
const env = getEnv();
|
|
2137
|
+
if (env === "WEB" && typeof navigator !== "undefined" && navigator.sendBeacon) {
|
|
2138
|
+
const blob = new Blob([JSON.stringify(events)], {
|
|
2139
|
+
type: "application/json"
|
|
2140
|
+
});
|
|
2141
|
+
const encryptedToken = this.encryptToken();
|
|
2142
|
+
const sent = navigator.sendBeacon(
|
|
2143
|
+
`${this.config.apiEndpoint}?contentId=${encryptedToken}`,
|
|
2144
|
+
blob
|
|
2145
|
+
);
|
|
2146
|
+
if (this.config.debug) {
|
|
2147
|
+
console.log(
|
|
2148
|
+
"[TrackingSDK] \u4F7F\u7528 sendBeacon \u53D1\u9001:",
|
|
2149
|
+
sent ? "\u6210\u529F" : "\u5931\u8D25",
|
|
2150
|
+
events.length,
|
|
2151
|
+
"\u6761"
|
|
2152
|
+
);
|
|
2153
|
+
}
|
|
2154
|
+
if (!sent) {
|
|
2155
|
+
this.eventQueue.unshift(...events);
|
|
2156
|
+
this.flush().catch(console.error);
|
|
2157
|
+
}
|
|
2158
|
+
} else {
|
|
2159
|
+
this.flush().catch((error) => {
|
|
2160
|
+
console.error("[TrackingSDK] \u7ACB\u5373\u53D1\u9001\u5931\u8D25:", error);
|
|
2161
|
+
this.eventQueue.unshift(...events);
|
|
2162
|
+
});
|
|
2163
|
+
}
|
|
2164
|
+
} catch (error) {
|
|
2165
|
+
console.error("[TrackingSDK] flushNow \u6267\u884C\u5931\u8D25:", error);
|
|
2166
|
+
this.eventQueue.unshift(...events);
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
/**
|
|
2170
|
+
* 销毁SDK
|
|
2171
|
+
*/
|
|
2172
|
+
destroy() {
|
|
2173
|
+
if (this.flushTimer) {
|
|
2174
|
+
clearInterval(this.flushTimer);
|
|
2175
|
+
this.flushTimer = null;
|
|
2176
|
+
}
|
|
2177
|
+
this.flushNow();
|
|
2178
|
+
this.isInitialized = false;
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
const trackingSDK = new TrackingSDK();
|
|
2182
|
+
|
|
2183
|
+
function useAutoTracking(config = {}) {
|
|
2184
|
+
const { trackPageView = true, trackClicks = true, pageTitle, customData = {} } = config;
|
|
2185
|
+
const pageStartTime = ref(0);
|
|
2186
|
+
const isPageVisible = ref(true);
|
|
2187
|
+
const handlePageShow = () => {
|
|
2188
|
+
isPageVisible.value = true;
|
|
2189
|
+
pageStartTime.value = Date.now();
|
|
2190
|
+
if (trackPageView) {
|
|
2191
|
+
trackingSDK.trackPageView(pageTitle);
|
|
2192
|
+
}
|
|
2193
|
+
};
|
|
2194
|
+
const handlePageHide = () => {
|
|
2195
|
+
isPageVisible.value = false;
|
|
2196
|
+
};
|
|
2197
|
+
const handleClick = (event) => {
|
|
2198
|
+
if (!trackClicks || !isPageVisible.value) return;
|
|
2199
|
+
const target = event.target || event.currentTarget;
|
|
2200
|
+
const elementId = target?.id;
|
|
2201
|
+
const elementClass = target?.className;
|
|
2202
|
+
const elementText = target?.textContent || target?.innerText;
|
|
2203
|
+
trackingSDK.trackClick(elementId || elementClass, elementText);
|
|
2204
|
+
};
|
|
2205
|
+
const trackEvent = (eventName, data) => {
|
|
2206
|
+
trackingSDK.trackCustom(eventName, { ...customData, ...data });
|
|
2207
|
+
};
|
|
2208
|
+
const trackBusinessEvent = (event, businessData) => {
|
|
2209
|
+
trackingSDK.trackBusiness(event, businessData);
|
|
2210
|
+
};
|
|
2211
|
+
useDidShow(() => {
|
|
2212
|
+
handlePageShow();
|
|
2213
|
+
});
|
|
2214
|
+
onUnmounted(() => {
|
|
2215
|
+
handlePageHide();
|
|
2216
|
+
});
|
|
2217
|
+
return {
|
|
2218
|
+
// 状态
|
|
2219
|
+
isPageVisible,
|
|
2220
|
+
pageStartTime,
|
|
2221
|
+
// 事件处理函数
|
|
2222
|
+
handleClick,
|
|
2223
|
+
// 手动埋点方法
|
|
2224
|
+
trackEvent,
|
|
2225
|
+
trackBusinessEvent,
|
|
2226
|
+
// 页面生命周期
|
|
2227
|
+
handlePageShow,
|
|
2228
|
+
handlePageHide
|
|
2229
|
+
};
|
|
2230
|
+
}
|
|
2231
|
+
function usePageTracking(config = {}) {
|
|
2232
|
+
return useAutoTracking(config);
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2235
|
+
function getElementInfo(el) {
|
|
2236
|
+
return {
|
|
2237
|
+
id: el.id,
|
|
2238
|
+
className: el.className,
|
|
2239
|
+
text: (el.textContent || el.innerText || "").trim()
|
|
2240
|
+
};
|
|
2241
|
+
}
|
|
2242
|
+
function getClickPosition(event) {
|
|
2243
|
+
const e = event;
|
|
2244
|
+
if ("touches" in e && e.touches.length > 0) {
|
|
2245
|
+
return {
|
|
2246
|
+
x: e.touches[0].clientX,
|
|
2247
|
+
y: e.touches[0].clientY
|
|
2248
|
+
};
|
|
2249
|
+
} else if ("clientX" in e) {
|
|
2250
|
+
return {
|
|
2251
|
+
x: e.clientX,
|
|
2252
|
+
y: e.clientY
|
|
2253
|
+
};
|
|
2254
|
+
}
|
|
2255
|
+
return { x: 0, y: 0 };
|
|
2256
|
+
}
|
|
2257
|
+
function bindClickEvent(el, binding) {
|
|
2258
|
+
const oldHandler = el.__trackClickHandler;
|
|
2259
|
+
const oldOptions = el.__trackClickOptions;
|
|
2260
|
+
if (oldHandler) {
|
|
2261
|
+
el.removeEventListener("click", oldHandler, oldOptions);
|
|
2262
|
+
delete el.__trackClickHandler;
|
|
2263
|
+
delete el.__trackClickOptions;
|
|
2264
|
+
}
|
|
2265
|
+
const value = binding.value;
|
|
2266
|
+
const config = typeof value === "string" ? { event: value } : value || {};
|
|
2267
|
+
const { data = {}, elementId, elementText, preventDefault = false } = config;
|
|
2268
|
+
const elementInfo = getElementInfo(el);
|
|
2269
|
+
const finalElementId = elementId || elementInfo.id;
|
|
2270
|
+
const finalElementClass = elementInfo.className;
|
|
2271
|
+
const finalElementText = elementText || elementInfo.text;
|
|
2272
|
+
const handleClick = (clickEvent) => {
|
|
2273
|
+
if (preventDefault) {
|
|
2274
|
+
clickEvent.preventDefault();
|
|
2275
|
+
}
|
|
2276
|
+
const position = getClickPosition(clickEvent);
|
|
2277
|
+
trackingSDK.trackClick(finalElementId || finalElementClass, finalElementText);
|
|
2278
|
+
if (config.event && config.event !== "click") {
|
|
2279
|
+
trackingSDK.trackCustom(config.event, {
|
|
2280
|
+
elementId: finalElementId || finalElementClass,
|
|
2281
|
+
elementText: finalElementText,
|
|
2282
|
+
position,
|
|
2283
|
+
...data
|
|
2284
|
+
});
|
|
2285
|
+
}
|
|
2286
|
+
};
|
|
2287
|
+
const eventOptions = { capture: true, passive: !preventDefault };
|
|
2288
|
+
el.addEventListener("click", handleClick, eventOptions);
|
|
2289
|
+
el.__trackClickHandler = handleClick;
|
|
2290
|
+
el.__trackClickOptions = eventOptions;
|
|
2291
|
+
}
|
|
2292
|
+
const trackClickDirective = {
|
|
2293
|
+
mounted(el, binding) {
|
|
2294
|
+
setTimeout(() => {
|
|
2295
|
+
bindClickEvent(el, binding);
|
|
2296
|
+
}, 0);
|
|
2297
|
+
},
|
|
2298
|
+
updated(el, binding) {
|
|
2299
|
+
bindClickEvent(el, binding);
|
|
2300
|
+
},
|
|
2301
|
+
unmounted(el) {
|
|
2302
|
+
const handler = el.__trackClickHandler;
|
|
2303
|
+
const options = el.__trackClickOptions;
|
|
2304
|
+
if (handler) {
|
|
2305
|
+
el.removeEventListener("click", handler, options);
|
|
2306
|
+
delete el.__trackClickHandler;
|
|
2307
|
+
delete el.__trackClickOptions;
|
|
2308
|
+
}
|
|
2309
|
+
}
|
|
2310
|
+
};
|
|
2311
|
+
function installTrackClickDirective(app) {
|
|
2312
|
+
app.directive("track-click", trackClickDirective);
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2315
|
+
const trackPageDirective = {
|
|
2316
|
+
mounted(el, binding) {
|
|
2317
|
+
const value = binding.value;
|
|
2318
|
+
const config = typeof value === "string" ? { pageTitle: value } : value || {};
|
|
2319
|
+
const { pageTitle, customData = {}, trackStay = true } = config;
|
|
2320
|
+
trackingSDK.trackPageView(pageTitle);
|
|
2321
|
+
if (Object.keys(customData).length > 0) {
|
|
2322
|
+
trackingSDK.trackCustom("page_view_custom", customData);
|
|
2323
|
+
}
|
|
2324
|
+
if (trackStay) {
|
|
2325
|
+
el.__trackPageStartTime = Date.now();
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2328
|
+
};
|
|
2329
|
+
function installTrackPageDirective(app) {
|
|
2330
|
+
app.directive("track-page", trackPageDirective);
|
|
2331
|
+
}
|
|
2332
|
+
|
|
2333
|
+
const trackScrollDirective = {
|
|
2334
|
+
mounted(el, binding) {
|
|
2335
|
+
const value = binding.value;
|
|
2336
|
+
const config = typeof value === "boolean" ? { threshold: 0.5, trackDirection: value } : value || {};
|
|
2337
|
+
const { threshold = 0.5, data = {}, trackDirection = false } = config;
|
|
2338
|
+
let hasTracked = false;
|
|
2339
|
+
let lastScrollTop = 0;
|
|
2340
|
+
const handleScroll = () => {
|
|
2341
|
+
if (hasTracked) return;
|
|
2342
|
+
const rect = el.getBoundingClientRect();
|
|
2343
|
+
const windowHeight = window.innerHeight;
|
|
2344
|
+
const elementTop = rect.top;
|
|
2345
|
+
const elementHeight = rect.height;
|
|
2346
|
+
const visibleHeight = Math.min(elementHeight, windowHeight - Math.max(0, elementTop));
|
|
2347
|
+
const visibleRatio = visibleHeight / elementHeight;
|
|
2348
|
+
if (visibleRatio >= threshold) {
|
|
2349
|
+
hasTracked = true;
|
|
2350
|
+
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
|
2351
|
+
const scrollDirection = scrollTop > lastScrollTop ? "down" : "up";
|
|
2352
|
+
lastScrollTop = scrollTop;
|
|
2353
|
+
trackingSDK.trackCustom("scroll_into_view", {
|
|
2354
|
+
elementId: el.id,
|
|
2355
|
+
visibleRatio,
|
|
2356
|
+
scrollDirection: trackDirection ? scrollDirection : void 0,
|
|
2357
|
+
scrollTop,
|
|
2358
|
+
...data
|
|
2359
|
+
});
|
|
2360
|
+
}
|
|
2361
|
+
};
|
|
2362
|
+
if ("IntersectionObserver" in window) {
|
|
2363
|
+
const observer = new IntersectionObserver(
|
|
2364
|
+
(entries) => {
|
|
2365
|
+
entries.forEach((entry) => {
|
|
2366
|
+
if (entry.isIntersecting && entry.intersectionRatio >= threshold) {
|
|
2367
|
+
hasTracked = true;
|
|
2368
|
+
trackingSDK.trackCustom("scroll_into_view", {
|
|
2369
|
+
elementId: el.id,
|
|
2370
|
+
intersectionRatio: entry.intersectionRatio,
|
|
2371
|
+
...data
|
|
2372
|
+
});
|
|
2373
|
+
observer.unobserve(el);
|
|
2374
|
+
}
|
|
2375
|
+
});
|
|
2376
|
+
},
|
|
2377
|
+
{ threshold }
|
|
2378
|
+
);
|
|
2379
|
+
observer.observe(el);
|
|
2380
|
+
el.__scrollObserver = observer;
|
|
2381
|
+
} else {
|
|
2382
|
+
if (typeof window !== "undefined") {
|
|
2383
|
+
window.addEventListener("scroll", handleScroll, { passive: true });
|
|
2384
|
+
el.__scrollHandler = handleScroll;
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2387
|
+
},
|
|
2388
|
+
unmounted(el) {
|
|
2389
|
+
const observer = el.__scrollObserver;
|
|
2390
|
+
if (observer) {
|
|
2391
|
+
observer.disconnect();
|
|
2392
|
+
delete el.__scrollObserver;
|
|
2393
|
+
}
|
|
2394
|
+
const handler = el.__scrollHandler;
|
|
2395
|
+
if (handler && typeof window !== "undefined") {
|
|
2396
|
+
window.removeEventListener("scroll", handler);
|
|
2397
|
+
delete el.__scrollHandler;
|
|
2398
|
+
}
|
|
2399
|
+
}
|
|
2400
|
+
};
|
|
2401
|
+
function installTrackScrollDirective(app) {
|
|
2402
|
+
app.directive("track-scroll", trackScrollDirective);
|
|
2403
|
+
}
|
|
2404
|
+
|
|
2405
|
+
function getSearchElementInfo(el) {
|
|
2406
|
+
let placeholder;
|
|
2407
|
+
if (el.placeholder) {
|
|
2408
|
+
placeholder = el.placeholder;
|
|
2409
|
+
} else if (el.querySelector("input")) {
|
|
2410
|
+
placeholder = el.querySelector("input").placeholder;
|
|
2411
|
+
}
|
|
2412
|
+
return {
|
|
2413
|
+
id: el.id,
|
|
2414
|
+
className: el.className,
|
|
2415
|
+
placeholder: placeholder || ""
|
|
2416
|
+
};
|
|
2417
|
+
}
|
|
2418
|
+
const trackSearchDirective = {
|
|
2419
|
+
mounted(el, binding) {
|
|
2420
|
+
const value = binding.value;
|
|
2421
|
+
const config = typeof value === "string" ? { event: value } : value || {};
|
|
2422
|
+
const {
|
|
2423
|
+
event = "search",
|
|
2424
|
+
data = {},
|
|
2425
|
+
elementId,
|
|
2426
|
+
trackInput = true,
|
|
2427
|
+
trackSubmit = true,
|
|
2428
|
+
debounceTime = 500,
|
|
2429
|
+
minLength = 1
|
|
2430
|
+
} = config;
|
|
2431
|
+
const elementInfo = getSearchElementInfo(el);
|
|
2432
|
+
const finalElementId = elementId || elementInfo.id;
|
|
2433
|
+
const finalElementClass = elementInfo.className;
|
|
2434
|
+
const handleInput = (event2) => {
|
|
2435
|
+
const target = event2.target;
|
|
2436
|
+
const searchValue = target.value.trim();
|
|
2437
|
+
if (searchValue.length < minLength) {
|
|
2438
|
+
return;
|
|
2439
|
+
}
|
|
2440
|
+
trackingSDK.trackCustom("search_input", {
|
|
2441
|
+
elementId: finalElementId || finalElementClass,
|
|
2442
|
+
searchValue,
|
|
2443
|
+
searchLength: searchValue.length,
|
|
2444
|
+
placeholder: elementInfo.placeholder,
|
|
2445
|
+
...data
|
|
2446
|
+
});
|
|
2447
|
+
};
|
|
2448
|
+
const handleSubmit = (event2) => {
|
|
2449
|
+
const target = event2.target;
|
|
2450
|
+
const searchValue = target.value.trim();
|
|
2451
|
+
if (searchValue.length < minLength) {
|
|
2452
|
+
return;
|
|
2453
|
+
}
|
|
2454
|
+
trackingSDK.trackCustom("search_submit", {
|
|
2455
|
+
elementId: finalElementId || finalElementClass,
|
|
2456
|
+
searchValue,
|
|
2457
|
+
searchLength: searchValue.length,
|
|
2458
|
+
placeholder: elementInfo.placeholder,
|
|
2459
|
+
...data
|
|
2460
|
+
});
|
|
2461
|
+
};
|
|
2462
|
+
const debouncedHandleInput = debounce$1(handleInput, debounceTime || 500);
|
|
2463
|
+
if (trackInput) {
|
|
2464
|
+
el.addEventListener("input", debouncedHandleInput, { passive: true });
|
|
2465
|
+
el.__trackSearchInputHandler = debouncedHandleInput;
|
|
2466
|
+
}
|
|
2467
|
+
if (trackSubmit) {
|
|
2468
|
+
el.addEventListener("keydown", (event2) => {
|
|
2469
|
+
if (event2.key === "Enter") {
|
|
2470
|
+
handleSubmit(event2);
|
|
2471
|
+
}
|
|
2472
|
+
});
|
|
2473
|
+
el.__trackSearchSubmitHandler = handleSubmit;
|
|
2474
|
+
}
|
|
2475
|
+
const form = el.closest("form");
|
|
2476
|
+
if (form && trackSubmit) {
|
|
2477
|
+
form.addEventListener("submit", handleSubmit);
|
|
2478
|
+
el.__trackSearchFormHandler = handleSubmit;
|
|
2479
|
+
}
|
|
2480
|
+
},
|
|
2481
|
+
updated(el, binding) {
|
|
2482
|
+
const inputHandler = el.__trackSearchInputHandler;
|
|
2483
|
+
if (inputHandler) {
|
|
2484
|
+
el.removeEventListener("input", inputHandler);
|
|
2485
|
+
delete el.__trackSearchInputHandler;
|
|
2486
|
+
trackSearchDirective.mounted?.(el, binding);
|
|
2487
|
+
}
|
|
2488
|
+
},
|
|
2489
|
+
unmounted(el) {
|
|
2490
|
+
const inputHandler = el.__trackSearchInputHandler;
|
|
2491
|
+
const submitHandler = el.__trackSearchSubmitHandler;
|
|
2492
|
+
const formHandler = el.__trackSearchFormHandler;
|
|
2493
|
+
if (inputHandler) {
|
|
2494
|
+
el.removeEventListener("input", inputHandler);
|
|
2495
|
+
delete el.__trackSearchInputHandler;
|
|
2496
|
+
}
|
|
2497
|
+
if (submitHandler) {
|
|
2498
|
+
el.removeEventListener("submit", submitHandler);
|
|
2499
|
+
delete el.__trackSearchSubmitHandler;
|
|
2500
|
+
}
|
|
2501
|
+
if (formHandler) {
|
|
2502
|
+
const form = el.closest("form");
|
|
2503
|
+
if (form) {
|
|
2504
|
+
form.removeEventListener("submit", formHandler);
|
|
2505
|
+
}
|
|
2506
|
+
delete el.__trackSearchFormHandler;
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
};
|
|
2510
|
+
function installTrackSearchDirective(app) {
|
|
2511
|
+
app.directive("track-search", trackSearchDirective);
|
|
2512
|
+
}
|
|
2513
|
+
|
|
2514
|
+
function installTrackingDirectives(app) {
|
|
2515
|
+
installTrackClickDirective(app);
|
|
2516
|
+
installTrackPageDirective(app);
|
|
2517
|
+
installTrackScrollDirective(app);
|
|
2518
|
+
installTrackSearchDirective(app);
|
|
2519
|
+
console.log("[TrackingDirectives] \u6240\u6709\u57CB\u70B9\u6307\u4EE4\u5B89\u88C5\u5B8C\u6210");
|
|
2520
|
+
}
|
|
2521
|
+
|
|
2522
|
+
async function initTracking(config = {}) {
|
|
2523
|
+
try {
|
|
2524
|
+
console.log("[TrackingInit] \u5F00\u59CB\u521D\u59CB\u5316\u57CB\u70B9\u7CFB\u7EDF...");
|
|
2525
|
+
const sdkConfig = {
|
|
2526
|
+
enabled: config.enabled,
|
|
2527
|
+
debug: config.debug,
|
|
2528
|
+
apiEndpoint: config.apiEndpoint,
|
|
2529
|
+
batchSize: config.batchSize,
|
|
2530
|
+
flushInterval: config.flushInterval,
|
|
2531
|
+
userInfo: config.userInfo
|
|
2532
|
+
// 传递用户信息
|
|
2533
|
+
};
|
|
2534
|
+
trackingSDK.updateConfig(sdkConfig);
|
|
2535
|
+
setupGlobalErrorHandling();
|
|
2536
|
+
setupPageLifecycleTracking();
|
|
2537
|
+
setupGlobalProperties();
|
|
2538
|
+
trackingSDK.clearPageHistory();
|
|
2539
|
+
console.log("[TrackingInit] \u57CB\u70B9\u7CFB\u7EDF\u521D\u59CB\u5316\u5B8C\u6210");
|
|
2540
|
+
await trackingSDK.trackCustom("tracking_init_complete", {
|
|
2541
|
+
logTime: Date.now()
|
|
2542
|
+
});
|
|
2543
|
+
} catch (error) {
|
|
2544
|
+
console.error("[TrackingInit] \u57CB\u70B9\u7CFB\u7EDF\u521D\u59CB\u5316\u5931\u8D25:", error);
|
|
2545
|
+
}
|
|
2546
|
+
}
|
|
2547
|
+
function setupGlobalErrorHandling() {
|
|
2548
|
+
window.addEventListener("error", () => {
|
|
2549
|
+
});
|
|
2550
|
+
window.addEventListener("unhandledrejection", (event) => {
|
|
2551
|
+
});
|
|
2552
|
+
}
|
|
2553
|
+
function setupPageLifecycleTracking() {
|
|
2554
|
+
onAppShow(() => {
|
|
2555
|
+
trackingSDK.trackCustom("app_show", {
|
|
2556
|
+
logTime: Date.now()
|
|
2557
|
+
}).catch(console.error);
|
|
2558
|
+
});
|
|
2559
|
+
onAppHide(() => {
|
|
2560
|
+
trackingSDK.trackCustom("app_hide", {
|
|
2561
|
+
logTime: Date.now()
|
|
2562
|
+
}).catch(console.error);
|
|
2563
|
+
});
|
|
2564
|
+
onNetworkStatusChange((res) => {
|
|
2565
|
+
trackingSDK.trackCustom("network_status_change", {
|
|
2566
|
+
isConnected: res.isConnected,
|
|
2567
|
+
networkType: res.networkType,
|
|
2568
|
+
logTime: Date.now()
|
|
2569
|
+
}).catch(console.error);
|
|
2570
|
+
});
|
|
2571
|
+
}
|
|
2572
|
+
function setupGlobalProperties() {
|
|
2573
|
+
if (typeof window !== "undefined") {
|
|
2574
|
+
window.__trackingSDK = trackingSDK;
|
|
2575
|
+
}
|
|
2576
|
+
if (typeof globalThis !== "undefined") {
|
|
2577
|
+
globalThis.track = trackingSDK.trackCustom.bind(trackingSDK);
|
|
2578
|
+
globalThis.trackPage = trackingSDK.trackPageView.bind(trackingSDK);
|
|
2579
|
+
globalThis.trackClick = trackingSDK.trackClick.bind(trackingSDK);
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2582
|
+
function installTrackingPlugin(app) {
|
|
2583
|
+
installTrackingDirectives(app);
|
|
2584
|
+
app.config.globalProperties.$track = async (event, data) => {
|
|
2585
|
+
await trackingSDK.trackCustom(event, data);
|
|
2586
|
+
};
|
|
2587
|
+
app.config.globalProperties.$trackPage = async (pageTitle, customData) => {
|
|
2588
|
+
await trackingSDK.trackPageView(pageTitle);
|
|
2589
|
+
if (customData) {
|
|
2590
|
+
await trackingSDK.trackCustom("page_custom", customData);
|
|
2591
|
+
}
|
|
2592
|
+
};
|
|
2593
|
+
app.config.globalProperties.$trackClick = async (elementId, elementText) => {
|
|
2594
|
+
await trackingSDK.trackClick(elementId, elementText);
|
|
2595
|
+
};
|
|
2596
|
+
console.log("[TrackingInit] Vue\u57CB\u70B9\u63D2\u4EF6\u5B89\u88C5\u5B8C\u6210");
|
|
2597
|
+
}
|
|
2598
|
+
|
|
1522
2599
|
const endpointsList$2 = {
|
|
1523
2600
|
/**
|
|
1524
2601
|
* 获取充值套餐包列表
|
|
@@ -1894,7 +2971,8 @@ var script$E = /* @__PURE__ */ defineComponent({
|
|
|
1894
2971
|
accountAuthFlag: false,
|
|
1895
2972
|
channelCode: "centergzh",
|
|
1896
2973
|
payFinishJumpUrl: props.payFinishJumpUrl,
|
|
1897
|
-
fromMini: !!params.from
|
|
2974
|
+
fromMini: !!params.from,
|
|
2975
|
+
clientInfo: "H5"
|
|
1898
2976
|
}).then((result) => {
|
|
1899
2977
|
console.log(result, "------requestBrandWCPay");
|
|
1900
2978
|
state.buttonLoading = false;
|
|
@@ -3098,24 +4176,6 @@ var script$u = /* @__PURE__ */ defineComponent({
|
|
|
3098
4176
|
|
|
3099
4177
|
script$u.__file = "src/balance/components/Tip.vue";
|
|
3100
4178
|
|
|
3101
|
-
function dataURItoBlob(dataURI) {
|
|
3102
|
-
const byteString = atob(dataURI.split(",")[1]);
|
|
3103
|
-
const mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0];
|
|
3104
|
-
const ab = new ArrayBuffer(byteString.length);
|
|
3105
|
-
const ia = new Uint8Array(ab);
|
|
3106
|
-
for (let i = 0; i < byteString.length; i++) {
|
|
3107
|
-
ia[i] = byteString.charCodeAt(i);
|
|
3108
|
-
}
|
|
3109
|
-
return new Blob([ab], { type: mimeString });
|
|
3110
|
-
}
|
|
3111
|
-
function isWeb() {
|
|
3112
|
-
const env = process.env.TARO_ENV || "";
|
|
3113
|
-
return env === "h5" || Taro.getEnv() === "WEB";
|
|
3114
|
-
}
|
|
3115
|
-
function isApp() {
|
|
3116
|
-
return dsBridge.hasNativeMethod("openWebPage");
|
|
3117
|
-
}
|
|
3118
|
-
|
|
3119
4179
|
const _hoisted_1$q = { class: "account-view" };
|
|
3120
4180
|
const _hoisted_2$k = { class: "scroll-content" };
|
|
3121
4181
|
const _hoisted_3$e = { class: "row jusify-right" };
|
|
@@ -10140,4 +11200,4 @@ const AppKit = {
|
|
|
10140
11200
|
}
|
|
10141
11201
|
};
|
|
10142
11202
|
|
|
10143
|
-
export { script$t as AccountView, script$M as AmountPicker, script$K as AppDrawer, script$J as AppVerify, script$z as BalanceCard, script$s as BalanceReminder, script$r as DateRange, script$H as DeviceVersion, script$p as ListFilter, script$4 as LoginSetting, script$i as NoticeBanner, script$h as NoticeEntry, script$f as NoticeList, script$e as NoticeList2, script$F as OcrBusinessLicense, script$G as OcrIcon, script$L as PageHeader, script$o as PromoterCard, script$C as RechargeResult, script$E as RechargeView, script$k as SelfRegistration, script as SharePoster, script$A as TradeView, script$D as UserAgreement, script$2 as UserAuth, script$a as UserBinding, script$9 as UserBindingSuccess, script$d as UserEntry, script$6 as UserFeedback, script$5 as UserFeedbackEntry, script$7 as UserHeadCrop, script$b as UserInfo, script$3 as UserResourceEmpty, components, createHttp, AppKit as default, defaultCryptoConfig, generateUniqueId, getSdkConfig, jssdkServices, requestPayment$2 as requestPayment, requestWxH5Pay, services$1 as services, useAppKit, useCountdown, useCrypto, useEncode, useLogger, useSafeArea, useTabbar, useUpload, useValidator, useWxAuth };
|
|
11203
|
+
export { script$t as AccountView, script$M as AmountPicker, script$K as AppDrawer, script$J as AppVerify, script$z as BalanceCard, script$s as BalanceReminder, script$r as DateRange, script$H as DeviceVersion, script$p as ListFilter, script$4 as LoginSetting, script$i as NoticeBanner, script$h as NoticeEntry, script$f as NoticeList, script$e as NoticeList2, script$F as OcrBusinessLicense, script$G as OcrIcon, script$L as PageHeader, script$o as PromoterCard, script$C as RechargeResult, script$E as RechargeView, script$k as SelfRegistration, script as SharePoster, script$A as TradeView, script$D as UserAgreement, script$2 as UserAuth, script$a as UserBinding, script$9 as UserBindingSuccess, script$d as UserEntry, script$6 as UserFeedback, script$5 as UserFeedbackEntry, script$7 as UserHeadCrop, script$b as UserInfo, script$3 as UserResourceEmpty, components, createHttp, AppKit as default, defaultCryptoConfig, generateUniqueId, getSdkConfig, initTracking, installTrackingPlugin, jssdkServices, requestPayment$2 as requestPayment, requestWxH5Pay, services$1 as services, trackingSDK, useAppKit, useCountdown, useCrypto, useEncode, useLogger, usePageTracking, useSafeArea, useTabbar, useUpload, useValidator, useWxAuth };
|