@alibarbar/common 1.0.0
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/README.md +338 -0
- package/dist/algorithm.d.mts +66 -0
- package/dist/algorithm.d.ts +66 -0
- package/dist/algorithm.js +44 -0
- package/dist/algorithm.js.map +1 -0
- package/dist/algorithm.mjs +3 -0
- package/dist/algorithm.mjs.map +1 -0
- package/dist/array.d.mts +139 -0
- package/dist/array.d.ts +139 -0
- package/dist/array.js +84 -0
- package/dist/array.js.map +1 -0
- package/dist/array.mjs +3 -0
- package/dist/array.mjs.map +1 -0
- package/dist/chunk-27UDDVLZ.js +259 -0
- package/dist/chunk-27UDDVLZ.js.map +1 -0
- package/dist/chunk-2FFSQ573.mjs +138 -0
- package/dist/chunk-2FFSQ573.mjs.map +1 -0
- package/dist/chunk-4RGXV4SJ.js +106 -0
- package/dist/chunk-4RGXV4SJ.js.map +1 -0
- package/dist/chunk-56W6YECK.js +374 -0
- package/dist/chunk-56W6YECK.js.map +1 -0
- package/dist/chunk-5BGSUGTI.mjs +128 -0
- package/dist/chunk-5BGSUGTI.mjs.map +1 -0
- package/dist/chunk-7E6GELHJ.mjs +302 -0
- package/dist/chunk-7E6GELHJ.mjs.map +1 -0
- package/dist/chunk-7V5UQXIO.js +89 -0
- package/dist/chunk-7V5UQXIO.js.map +1 -0
- package/dist/chunk-A4SWQXX7.mjs +484 -0
- package/dist/chunk-A4SWQXX7.mjs.map +1 -0
- package/dist/chunk-ALDC6LRJ.mjs +85 -0
- package/dist/chunk-ALDC6LRJ.mjs.map +1 -0
- package/dist/chunk-BHCRFURU.js +491 -0
- package/dist/chunk-BHCRFURU.js.map +1 -0
- package/dist/chunk-D7CS5EKF.js +110 -0
- package/dist/chunk-D7CS5EKF.js.map +1 -0
- package/dist/chunk-DYBSRI7V.js +189 -0
- package/dist/chunk-DYBSRI7V.js.map +1 -0
- package/dist/chunk-F3LAGHPG.js +332 -0
- package/dist/chunk-F3LAGHPG.js.map +1 -0
- package/dist/chunk-HLDFI7R2.mjs +175 -0
- package/dist/chunk-HLDFI7R2.mjs.map +1 -0
- package/dist/chunk-HME2N3VY.mjs +354 -0
- package/dist/chunk-HME2N3VY.mjs.map +1 -0
- package/dist/chunk-I3L42475.js +145 -0
- package/dist/chunk-I3L42475.js.map +1 -0
- package/dist/chunk-JBLX27WD.mjs +240 -0
- package/dist/chunk-JBLX27WD.mjs.map +1 -0
- package/dist/chunk-JHZ7M2MR.mjs +133 -0
- package/dist/chunk-JHZ7M2MR.mjs.map +1 -0
- package/dist/chunk-JK2SE3I2.js +100 -0
- package/dist/chunk-JK2SE3I2.js.map +1 -0
- package/dist/chunk-JQZBPAPO.js +157 -0
- package/dist/chunk-JQZBPAPO.js.map +1 -0
- package/dist/chunk-JXYGC2C5.mjs +100 -0
- package/dist/chunk-JXYGC2C5.mjs.map +1 -0
- package/dist/chunk-KGFTD255.js +104 -0
- package/dist/chunk-KGFTD255.js.map +1 -0
- package/dist/chunk-LBHBNPNJ.mjs +148 -0
- package/dist/chunk-LBHBNPNJ.mjs.map +1 -0
- package/dist/chunk-LCXGZISK.js +158 -0
- package/dist/chunk-LCXGZISK.js.map +1 -0
- package/dist/chunk-LF4CILQS.mjs +87 -0
- package/dist/chunk-LF4CILQS.mjs.map +1 -0
- package/dist/chunk-MMR6XQNX.js +98 -0
- package/dist/chunk-MMR6XQNX.js.map +1 -0
- package/dist/chunk-NSSDYX2U.mjs +80 -0
- package/dist/chunk-NSSDYX2U.mjs.map +1 -0
- package/dist/chunk-O3O67R4I.js +143 -0
- package/dist/chunk-O3O67R4I.js.map +1 -0
- package/dist/chunk-OX5PLOWB.js +90 -0
- package/dist/chunk-OX5PLOWB.js.map +1 -0
- package/dist/chunk-PJ7UCTX4.mjs +362 -0
- package/dist/chunk-PJ7UCTX4.mjs.map +1 -0
- package/dist/chunk-QIBE7GVN.mjs +81 -0
- package/dist/chunk-QIBE7GVN.mjs.map +1 -0
- package/dist/chunk-QIOC54LQ.mjs +130 -0
- package/dist/chunk-QIOC54LQ.mjs.map +1 -0
- package/dist/chunk-QV6MIQ7H.mjs +328 -0
- package/dist/chunk-QV6MIQ7H.mjs.map +1 -0
- package/dist/chunk-TQN37HIN.js +94 -0
- package/dist/chunk-TQN37HIN.js.map +1 -0
- package/dist/chunk-XJTZDXSR.mjs +94 -0
- package/dist/chunk-XJTZDXSR.mjs.map +1 -0
- package/dist/chunk-XVUE53T3.js +361 -0
- package/dist/chunk-XVUE53T3.js.map +1 -0
- package/dist/chunk-Y364QIQH.js +139 -0
- package/dist/chunk-Y364QIQH.js.map +1 -0
- package/dist/chunk-YXM6Q4JS.mjs +94 -0
- package/dist/chunk-YXM6Q4JS.mjs.map +1 -0
- package/dist/chunk-ZDMFMUDR.js +309 -0
- package/dist/chunk-ZDMFMUDR.js.map +1 -0
- package/dist/chunk-ZVJ6NQUM.mjs +82 -0
- package/dist/chunk-ZVJ6NQUM.mjs.map +1 -0
- package/dist/color.d.mts +74 -0
- package/dist/color.d.ts +74 -0
- package/dist/color.js +40 -0
- package/dist/color.js.map +1 -0
- package/dist/color.mjs +3 -0
- package/dist/color.mjs.map +1 -0
- package/dist/crypto.d.mts +92 -0
- package/dist/crypto.d.ts +92 -0
- package/dist/crypto.js +60 -0
- package/dist/crypto.js.map +1 -0
- package/dist/crypto.mjs +3 -0
- package/dist/crypto.mjs.map +1 -0
- package/dist/data-structure.d.mts +213 -0
- package/dist/data-structure.d.ts +213 -0
- package/dist/data-structure.js +32 -0
- package/dist/data-structure.js.map +1 -0
- package/dist/data-structure.mjs +3 -0
- package/dist/data-structure.mjs.map +1 -0
- package/dist/date.d.mts +108 -0
- package/dist/date.d.ts +108 -0
- package/dist/date.js +72 -0
- package/dist/date.js.map +1 -0
- package/dist/date.mjs +3 -0
- package/dist/date.mjs.map +1 -0
- package/dist/dom.d.mts +92 -0
- package/dist/dom.d.ts +92 -0
- package/dist/dom.js +56 -0
- package/dist/dom.js.map +1 -0
- package/dist/dom.mjs +3 -0
- package/dist/dom.mjs.map +1 -0
- package/dist/file.d.mts +44 -0
- package/dist/file.d.ts +44 -0
- package/dist/file.js +32 -0
- package/dist/file.js.map +1 -0
- package/dist/file.mjs +3 -0
- package/dist/file.mjs.map +1 -0
- package/dist/i18n.d.mts +77 -0
- package/dist/i18n.d.ts +77 -0
- package/dist/i18n.js +40 -0
- package/dist/i18n.js.map +1 -0
- package/dist/i18n.mjs +3 -0
- package/dist/i18n.mjs.map +1 -0
- package/dist/index.d.mts +155 -0
- package/dist/index.d.ts +155 -0
- package/dist/index.js +839 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +22 -0
- package/dist/index.mjs.map +1 -0
- package/dist/network.d.mts +47 -0
- package/dist/network.d.ts +47 -0
- package/dist/network.js +28 -0
- package/dist/network.js.map +1 -0
- package/dist/network.mjs +3 -0
- package/dist/network.mjs.map +1 -0
- package/dist/number.d.mts +100 -0
- package/dist/number.d.ts +100 -0
- package/dist/number.js +56 -0
- package/dist/number.js.map +1 -0
- package/dist/number.mjs +3 -0
- package/dist/number.mjs.map +1 -0
- package/dist/object.d.mts +132 -0
- package/dist/object.d.ts +132 -0
- package/dist/object.js +80 -0
- package/dist/object.js.map +1 -0
- package/dist/object.mjs +3 -0
- package/dist/object.mjs.map +1 -0
- package/dist/performance.d.mts +85 -0
- package/dist/performance.d.ts +85 -0
- package/dist/performance.js +40 -0
- package/dist/performance.js.map +1 -0
- package/dist/performance.mjs +3 -0
- package/dist/performance.mjs.map +1 -0
- package/dist/storage.d.mts +176 -0
- package/dist/storage.d.ts +176 -0
- package/dist/storage.js +33 -0
- package/dist/storage.js.map +1 -0
- package/dist/storage.mjs +4 -0
- package/dist/storage.mjs.map +1 -0
- package/dist/string.d.mts +105 -0
- package/dist/string.d.ts +105 -0
- package/dist/string.js +68 -0
- package/dist/string.js.map +1 -0
- package/dist/string.mjs +3 -0
- package/dist/string.mjs.map +1 -0
- package/dist/tracking.d.mts +182 -0
- package/dist/tracking.d.ts +182 -0
- package/dist/tracking.js +52 -0
- package/dist/tracking.js.map +1 -0
- package/dist/tracking.mjs +3 -0
- package/dist/tracking.mjs.map +1 -0
- package/dist/transform.d.mts +53 -0
- package/dist/transform.d.ts +53 -0
- package/dist/transform.js +32 -0
- package/dist/transform.js.map +1 -0
- package/dist/transform.mjs +3 -0
- package/dist/transform.mjs.map +1 -0
- package/dist/upload-DzlQtUBc.d.mts +202 -0
- package/dist/upload-DzlQtUBc.d.ts +202 -0
- package/dist/upload.d.mts +1 -0
- package/dist/upload.d.ts +1 -0
- package/dist/upload.js +17 -0
- package/dist/upload.js.map +1 -0
- package/dist/upload.mjs +4 -0
- package/dist/upload.mjs.map +1 -0
- package/dist/url.d.mts +82 -0
- package/dist/url.d.ts +82 -0
- package/dist/url.js +44 -0
- package/dist/url.js.map +1 -0
- package/dist/url.mjs +3 -0
- package/dist/url.mjs.map +1 -0
- package/dist/validation.d.mts +83 -0
- package/dist/validation.d.ts +83 -0
- package/dist/validation.js +60 -0
- package/dist/validation.js.map +1 -0
- package/dist/validation.mjs +3 -0
- package/dist/validation.mjs.map +1 -0
- package/package.json +170 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/validation.ts"],"names":[],"mappings":"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","file":"chunk-NSSDYX2U.mjs","sourcesContent":["/**\n * 验证工具函数\n */\n\n/**\n * 验证邮箱格式\n * @param email - 邮箱地址\n * @returns 是否为有效邮箱\n */\nexport function isValidEmail(email: string): boolean {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n return emailRegex.test(email);\n}\n\n/**\n * 验证手机号格式(中国大陆)\n * @param phone - 手机号\n * @returns 是否为有效手机号\n */\nexport function isValidPhone(phone: string): boolean {\n const phoneRegex = /^1[3-9]\\d{9}$/;\n return phoneRegex.test(phone);\n}\n\n/**\n * 验证URL格式\n * @param url - URL地址\n * @returns 是否为有效URL\n */\nexport function isValidUrl(url: string): boolean {\n try {\n new URL(url);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * 验证身份证号格式(中国大陆18位)\n * @param idCard - 身份证号\n * @returns 是否为有效身份证号\n */\nexport function isValidIdCard(idCard: string): boolean {\n const idCardRegex = /^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[\\dXx]$/;\n return idCardRegex.test(idCard);\n}\n\n/**\n * 验证是否为空值\n * @param value - 待验证的值\n * @returns 是否为空\n */\nexport function isEmpty(value: unknown): boolean {\n if (value === null || value === undefined) return true;\n if (typeof value === 'string') return value.trim().length === 0;\n if (Array.isArray(value)) return value.length === 0;\n if (typeof value === 'object') return Object.keys(value).length === 0;\n return false;\n}\n\n/**\n * 验证UUID格式\n * @param uuid - UUID字符串\n * @returns 是否为有效UUID\n */\nexport function isValidUUID(uuid: string): boolean {\n const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n return uuidRegex.test(uuid);\n}\n\n/**\n * 验证IP地址格式(IPv4)\n * @param ip - IP地址\n * @returns 是否为有效IP地址\n */\nexport function isValidIP(ip: string): boolean {\n const ipRegex =\n /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;\n return ipRegex.test(ip);\n}\n\n/**\n * 验证域名格式\n * @param domain - 域名\n * @returns 是否为有效域名\n */\nexport function isValidDomain(domain: string): boolean {\n const domainRegex = /^([a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,}$/i;\n return domainRegex.test(domain);\n}\n\n/**\n * 验证十六进制颜色格式\n * @param color - 颜色值\n * @returns 是否为有效十六进制颜色\n */\nexport function isValidHexColor(color: string): boolean {\n const hexColorRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;\n return hexColorRegex.test(color);\n}\n\n/**\n * 验证JSON字符串格式\n * @param json - JSON字符串\n * @returns 是否为有效JSON\n */\nexport function isValidJSON(json: string): boolean {\n try {\n JSON.parse(json);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * 验证是否为数字\n * @param value - 待验证的值\n * @returns 是否为数字\n */\nexport function isNumeric(value: unknown): boolean {\n if (typeof value === 'number') return !isNaN(value) && isFinite(value);\n if (typeof value === 'string') {\n return value.trim() !== '' && !isNaN(Number(value)) && isFinite(Number(value));\n }\n return false;\n}\n\n/**\n * 验证是否为整数\n * @param value - 待验证的值\n * @returns 是否为整数\n */\nexport function isInteger(value: unknown): boolean {\n if (typeof value === 'number') return Number.isInteger(value);\n if (typeof value === 'string') {\n const num = Number(value);\n return !isNaN(num) && Number.isInteger(num);\n }\n return false;\n}\n\n/**\n * 验证是否为浮点数\n * @param value - 待验证的值\n * @returns 是否为浮点数\n */\nexport function isFloat(value: unknown): boolean {\n if (typeof value === 'number')\n return !isNaN(value) && isFinite(value) && !Number.isInteger(value);\n if (typeof value === 'string') {\n const num = Number(value);\n return !isNaN(num) && isFinite(num) && !Number.isInteger(num);\n }\n return false;\n}\n"]}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/data/algorithm.ts
|
|
4
|
+
function binarySearch(array, target, compareFn) {
|
|
5
|
+
let left = 0;
|
|
6
|
+
let right = array.length - 1;
|
|
7
|
+
const compare = compareFn || ((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
8
|
+
while (left <= right) {
|
|
9
|
+
const mid = Math.floor((left + right) / 2);
|
|
10
|
+
const comparison = compare(array[mid], target);
|
|
11
|
+
if (comparison === 0) {
|
|
12
|
+
return mid;
|
|
13
|
+
} else if (comparison < 0) {
|
|
14
|
+
left = mid + 1;
|
|
15
|
+
} else {
|
|
16
|
+
right = mid - 1;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return -1;
|
|
20
|
+
}
|
|
21
|
+
function quickSort(array, compareFn) {
|
|
22
|
+
if (array.length <= 1) {
|
|
23
|
+
return [...array];
|
|
24
|
+
}
|
|
25
|
+
const compare = compareFn || ((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
26
|
+
const pivot = array[Math.floor(array.length / 2)];
|
|
27
|
+
const left = [];
|
|
28
|
+
const right = [];
|
|
29
|
+
const equal = [];
|
|
30
|
+
for (const item of array) {
|
|
31
|
+
const comparison = compare(item, pivot);
|
|
32
|
+
if (comparison < 0) {
|
|
33
|
+
left.push(item);
|
|
34
|
+
} else if (comparison > 0) {
|
|
35
|
+
right.push(item);
|
|
36
|
+
} else {
|
|
37
|
+
equal.push(item);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return [...quickSort(left, compareFn), ...equal, ...quickSort(right, compareFn)];
|
|
41
|
+
}
|
|
42
|
+
function mergeSort(array, compareFn) {
|
|
43
|
+
if (array.length <= 1) {
|
|
44
|
+
return [...array];
|
|
45
|
+
}
|
|
46
|
+
const compare = compareFn || ((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
47
|
+
const mid = Math.floor(array.length / 2);
|
|
48
|
+
const left = mergeSort(array.slice(0, mid), compareFn);
|
|
49
|
+
const right = mergeSort(array.slice(mid), compareFn);
|
|
50
|
+
return merge(left, right, compare);
|
|
51
|
+
}
|
|
52
|
+
function merge(left, right, compareFn) {
|
|
53
|
+
const result = [];
|
|
54
|
+
let i = 0;
|
|
55
|
+
let j = 0;
|
|
56
|
+
while (i < left.length && j < right.length) {
|
|
57
|
+
if (compareFn(left[i], right[j]) <= 0) {
|
|
58
|
+
result.push(left[i]);
|
|
59
|
+
i++;
|
|
60
|
+
} else {
|
|
61
|
+
result.push(right[j]);
|
|
62
|
+
j++;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return result.concat(left.slice(i)).concat(right.slice(j));
|
|
66
|
+
}
|
|
67
|
+
function bubbleSort(array, compareFn) {
|
|
68
|
+
const result = [...array];
|
|
69
|
+
const compare = compareFn || ((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
70
|
+
const n = result.length;
|
|
71
|
+
for (let i = 0; i < n - 1; i++) {
|
|
72
|
+
let swapped = false;
|
|
73
|
+
for (let j = 0; j < n - i - 1; j++) {
|
|
74
|
+
if (compare(result[j], result[j + 1]) > 0) {
|
|
75
|
+
[result[j], result[j + 1]] = [result[j + 1], result[j]];
|
|
76
|
+
swapped = true;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (!swapped) {
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
function fibonacci(n) {
|
|
86
|
+
if (n < 0) {
|
|
87
|
+
throw new Error("n must be non-negative");
|
|
88
|
+
}
|
|
89
|
+
if (n === 0) return 0;
|
|
90
|
+
if (n === 1) return 1;
|
|
91
|
+
let a = 0;
|
|
92
|
+
let b = 1;
|
|
93
|
+
for (let i = 2; i <= n; i++) {
|
|
94
|
+
[a, b] = [b, a + b];
|
|
95
|
+
}
|
|
96
|
+
return b;
|
|
97
|
+
}
|
|
98
|
+
function fibonacciSequence(n) {
|
|
99
|
+
if (n <= 0) return [];
|
|
100
|
+
if (n === 1) return [0];
|
|
101
|
+
if (n === 2) return [0, 1];
|
|
102
|
+
const sequence = [0, 1];
|
|
103
|
+
for (let i = 2; i < n; i++) {
|
|
104
|
+
sequence.push(sequence[i - 1] + sequence[i - 2]);
|
|
105
|
+
}
|
|
106
|
+
return sequence;
|
|
107
|
+
}
|
|
108
|
+
function factorial(n) {
|
|
109
|
+
if (n < 0) {
|
|
110
|
+
throw new Error("n must be non-negative");
|
|
111
|
+
}
|
|
112
|
+
if (n === 0 || n === 1) {
|
|
113
|
+
return 1;
|
|
114
|
+
}
|
|
115
|
+
let result = 1;
|
|
116
|
+
for (let i = 2; i <= n; i++) {
|
|
117
|
+
result *= i;
|
|
118
|
+
}
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
121
|
+
function gcd(a, b) {
|
|
122
|
+
a = Math.abs(a);
|
|
123
|
+
b = Math.abs(b);
|
|
124
|
+
while (b !== 0) {
|
|
125
|
+
[a, b] = [b, a % b];
|
|
126
|
+
}
|
|
127
|
+
return a;
|
|
128
|
+
}
|
|
129
|
+
function lcm(a, b) {
|
|
130
|
+
return Math.abs(a * b) / gcd(a, b);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
exports.binarySearch = binarySearch;
|
|
134
|
+
exports.bubbleSort = bubbleSort;
|
|
135
|
+
exports.factorial = factorial;
|
|
136
|
+
exports.fibonacci = fibonacci;
|
|
137
|
+
exports.fibonacciSequence = fibonacciSequence;
|
|
138
|
+
exports.gcd = gcd;
|
|
139
|
+
exports.lcm = lcm;
|
|
140
|
+
exports.mergeSort = mergeSort;
|
|
141
|
+
exports.quickSort = quickSort;
|
|
142
|
+
//# sourceMappingURL=chunk-O3O67R4I.js.map
|
|
143
|
+
//# sourceMappingURL=chunk-O3O67R4I.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/data/algorithm.ts"],"names":[],"mappings":"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","file":"chunk-O3O67R4I.js","sourcesContent":["/**\n * 算法工具函数\n */\n\n/**\n * 二分查找\n * @param array - 已排序的数组\n * @param target - 目标值\n * @param compareFn - 比较函数(可选)\n * @returns 目标值的索引,如果未找到返回 -1\n */\nexport function binarySearch<T>(array: T[], target: T, compareFn?: (a: T, b: T) => number): number {\n let left = 0;\n let right = array.length - 1;\n\n const compare = compareFn || ((a: T, b: T) => (a < b ? -1 : a > b ? 1 : 0));\n\n while (left <= right) {\n const mid = Math.floor((left + right) / 2);\n const comparison = compare(array[mid], target);\n\n if (comparison === 0) {\n return mid;\n } else if (comparison < 0) {\n left = mid + 1;\n } else {\n right = mid - 1;\n }\n }\n\n return -1;\n}\n\n/**\n * 快速排序\n * @param array - 要排序的数组\n * @param compareFn - 比较函数(可选)\n * @returns 排序后的新数组\n */\nexport function quickSort<T>(array: T[], compareFn?: (a: T, b: T) => number): T[] {\n if (array.length <= 1) {\n return [...array];\n }\n\n const compare = compareFn || ((a: T, b: T) => (a < b ? -1 : a > b ? 1 : 0));\n const pivot = array[Math.floor(array.length / 2)];\n const left: T[] = [];\n const right: T[] = [];\n const equal: T[] = [];\n\n for (const item of array) {\n const comparison = compare(item, pivot);\n if (comparison < 0) {\n left.push(item);\n } else if (comparison > 0) {\n right.push(item);\n } else {\n equal.push(item);\n }\n }\n\n return [...quickSort(left, compareFn), ...equal, ...quickSort(right, compareFn)];\n}\n\n/**\n * 归并排序\n * @param array - 要排序的数组\n * @param compareFn - 比较函数(可选)\n * @returns 排序后的新数组\n */\nexport function mergeSort<T>(array: T[], compareFn?: (a: T, b: T) => number): T[] {\n if (array.length <= 1) {\n return [...array];\n }\n\n const compare = compareFn || ((a: T, b: T) => (a < b ? -1 : a > b ? 1 : 0));\n const mid = Math.floor(array.length / 2);\n const left = mergeSort(array.slice(0, mid), compareFn);\n const right = mergeSort(array.slice(mid), compareFn);\n\n return merge(left, right, compare);\n}\n\n/**\n * 合并两个已排序的数组\n */\nfunction merge<T>(left: T[], right: T[], compareFn: (a: T, b: T) => number): T[] {\n const result: T[] = [];\n let i = 0;\n let j = 0;\n\n while (i < left.length && j < right.length) {\n if (compareFn(left[i], right[j]) <= 0) {\n result.push(left[i]);\n i++;\n } else {\n result.push(right[j]);\n j++;\n }\n }\n\n return result.concat(left.slice(i)).concat(right.slice(j));\n}\n\n/**\n * 冒泡排序\n * @param array - 要排序的数组\n * @param compareFn - 比较函数(可选)\n * @returns 排序后的新数组\n */\nexport function bubbleSort<T>(array: T[], compareFn?: (a: T, b: T) => number): T[] {\n const result = [...array];\n const compare = compareFn || ((a: T, b: T) => (a < b ? -1 : a > b ? 1 : 0));\n const n = result.length;\n\n for (let i = 0; i < n - 1; i++) {\n let swapped = false;\n\n for (let j = 0; j < n - i - 1; j++) {\n if (compare(result[j], result[j + 1]) > 0) {\n [result[j], result[j + 1]] = [result[j + 1], result[j]];\n swapped = true;\n }\n }\n\n // 如果没有交换,说明已经排序完成\n if (!swapped) {\n break;\n }\n }\n\n return result;\n}\n\n/**\n * 计算斐波那契数列的第n项\n * @param n - 位置(从0开始)\n * @returns 斐波那契数\n */\nexport function fibonacci(n: number): number {\n if (n < 0) {\n throw new Error('n must be non-negative');\n }\n\n if (n === 0) return 0;\n if (n === 1) return 1;\n\n // 使用动态规划优化\n let a = 0;\n let b = 1;\n\n for (let i = 2; i <= n; i++) {\n [a, b] = [b, a + b];\n }\n\n return b;\n}\n\n/**\n * 计算斐波那契数列(返回前n项)\n * @param n - 项数\n * @returns 斐波那契数列数组\n */\nexport function fibonacciSequence(n: number): number[] {\n if (n <= 0) return [];\n if (n === 1) return [0];\n if (n === 2) return [0, 1];\n\n const sequence = [0, 1];\n for (let i = 2; i < n; i++) {\n sequence.push(sequence[i - 1] + sequence[i - 2]);\n }\n\n return sequence;\n}\n\n/**\n * 计算阶乘\n * @param n - 非负整数\n * @returns 阶乘结果\n */\nexport function factorial(n: number): number {\n if (n < 0) {\n throw new Error('n must be non-negative');\n }\n\n if (n === 0 || n === 1) {\n return 1;\n }\n\n let result = 1;\n for (let i = 2; i <= n; i++) {\n result *= i;\n }\n\n return result;\n}\n\n/**\n * 计算最大公约数(GCD)\n * @param a - 第一个数\n * @param b - 第二个数\n * @returns 最大公约数\n */\nexport function gcd(a: number, b: number): number {\n a = Math.abs(a);\n b = Math.abs(b);\n\n while (b !== 0) {\n [a, b] = [b, a % b];\n }\n\n return a;\n}\n\n/**\n * 计算最小公倍数(LCM)\n * @param a - 第一个数\n * @param b - 第二个数\n * @returns 最小公倍数\n */\nexport function lcm(a: number, b: number): number {\n return Math.abs(a * b) / gcd(a, b);\n}\n"]}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/format/i18n.ts
|
|
4
|
+
function getLocale() {
|
|
5
|
+
if (typeof navigator !== "undefined" && navigator.language) {
|
|
6
|
+
return navigator.language;
|
|
7
|
+
}
|
|
8
|
+
return "en-US";
|
|
9
|
+
}
|
|
10
|
+
function formatNumberI18n(value, locale, options) {
|
|
11
|
+
const loc = locale || getLocale();
|
|
12
|
+
return new Intl.NumberFormat(loc, options).format(value);
|
|
13
|
+
}
|
|
14
|
+
function formatDateI18n(date, locale, options) {
|
|
15
|
+
const loc = locale || getLocale();
|
|
16
|
+
const dateObj = typeof date === "number" ? new Date(date) : date;
|
|
17
|
+
return new Intl.DateTimeFormat(loc, options).format(dateObj);
|
|
18
|
+
}
|
|
19
|
+
function formatCurrencyI18n(value, currency, locale, options) {
|
|
20
|
+
const loc = locale || getLocale();
|
|
21
|
+
return new Intl.NumberFormat(loc, {
|
|
22
|
+
style: "currency",
|
|
23
|
+
currency,
|
|
24
|
+
...options
|
|
25
|
+
}).format(value);
|
|
26
|
+
}
|
|
27
|
+
function translate(key, dictionary, defaultValue) {
|
|
28
|
+
const keys = key.split(".");
|
|
29
|
+
let current = dictionary;
|
|
30
|
+
for (const k of keys) {
|
|
31
|
+
if (typeof current === "object" && current !== null && k in current) {
|
|
32
|
+
current = current[k];
|
|
33
|
+
} else {
|
|
34
|
+
return defaultValue || key;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (typeof current === "string") {
|
|
38
|
+
return current;
|
|
39
|
+
}
|
|
40
|
+
return defaultValue || key;
|
|
41
|
+
}
|
|
42
|
+
function createTranslator(dictionary) {
|
|
43
|
+
return (key, defaultValue) => {
|
|
44
|
+
return translate(key, dictionary, defaultValue);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function formatRelativeTime(date, locale) {
|
|
48
|
+
const loc = locale || getLocale();
|
|
49
|
+
const dateObj = typeof date === "number" ? new Date(date) : date;
|
|
50
|
+
const now = /* @__PURE__ */ new Date();
|
|
51
|
+
const diffInSeconds = Math.floor((now.getTime() - dateObj.getTime()) / 1e3);
|
|
52
|
+
const rtf = new Intl.RelativeTimeFormat(loc, { numeric: "auto" });
|
|
53
|
+
const intervals = [
|
|
54
|
+
{ unit: "year", seconds: 31536e3 },
|
|
55
|
+
{ unit: "month", seconds: 2592e3 },
|
|
56
|
+
{ unit: "week", seconds: 604800 },
|
|
57
|
+
{ unit: "day", seconds: 86400 },
|
|
58
|
+
{ unit: "hour", seconds: 3600 },
|
|
59
|
+
{ unit: "minute", seconds: 60 },
|
|
60
|
+
{ unit: "second", seconds: 1 }
|
|
61
|
+
];
|
|
62
|
+
for (const interval of intervals) {
|
|
63
|
+
const count = Math.floor(Math.abs(diffInSeconds) / interval.seconds);
|
|
64
|
+
if (count >= 1) {
|
|
65
|
+
return rtf.format(diffInSeconds < 0 ? count : -count, interval.unit);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return rtf.format(0, "second");
|
|
69
|
+
}
|
|
70
|
+
function pluralize(count, singular, plural, locale) {
|
|
71
|
+
const loc = locale || getLocale();
|
|
72
|
+
const pluralForm = plural || `${singular}s`;
|
|
73
|
+
const pluralRules = new Intl.PluralRules(loc);
|
|
74
|
+
const rule = pluralRules.select(count);
|
|
75
|
+
if (rule === "one" || count === 1) {
|
|
76
|
+
return `${count} ${singular}`;
|
|
77
|
+
}
|
|
78
|
+
return `${count} ${pluralForm}`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
exports.createTranslator = createTranslator;
|
|
82
|
+
exports.formatCurrencyI18n = formatCurrencyI18n;
|
|
83
|
+
exports.formatDateI18n = formatDateI18n;
|
|
84
|
+
exports.formatNumberI18n = formatNumberI18n;
|
|
85
|
+
exports.formatRelativeTime = formatRelativeTime;
|
|
86
|
+
exports.getLocale = getLocale;
|
|
87
|
+
exports.pluralize = pluralize;
|
|
88
|
+
exports.translate = translate;
|
|
89
|
+
//# sourceMappingURL=chunk-OX5PLOWB.js.map
|
|
90
|
+
//# sourceMappingURL=chunk-OX5PLOWB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/format/i18n.ts"],"names":[],"mappings":";;;AAkBO,SAAS,SAAA,GAAoB;AAClC,EAAA,IAAI,OAAO,SAAA,KAAc,WAAA,IAAe,SAAA,CAAU,QAAA,EAAU;AAC1D,IAAA,OAAO,SAAA,CAAU,QAAA;AAAA,EACnB;AACA,EAAA,OAAO,OAAA;AACT;AASO,SAAS,gBAAA,CACd,KAAA,EACA,MAAA,EACA,OAAA,EACQ;AACR,EAAA,MAAM,GAAA,GAAM,UAAU,SAAA,EAAU;AAChC,EAAA,OAAO,IAAI,IAAA,CAAK,YAAA,CAAa,KAAK,OAAO,CAAA,CAAE,OAAO,KAAK,CAAA;AACzD;AASO,SAAS,cAAA,CACd,IAAA,EACA,MAAA,EACA,OAAA,EACQ;AACR,EAAA,MAAM,GAAA,GAAM,UAAU,SAAA,EAAU;AAChC,EAAA,MAAM,UAAU,OAAO,IAAA,KAAS,WAAW,IAAI,IAAA,CAAK,IAAI,CAAA,GAAI,IAAA;AAC5D,EAAA,OAAO,IAAI,IAAA,CAAK,cAAA,CAAe,KAAK,OAAO,CAAA,CAAE,OAAO,OAAO,CAAA;AAC7D;AAUO,SAAS,kBAAA,CACd,KAAA,EACA,QAAA,EACA,MAAA,EACA,OAAA,EACQ;AACR,EAAA,MAAM,GAAA,GAAM,UAAU,SAAA,EAAU;AAChC,EAAA,OAAO,IAAI,IAAA,CAAK,YAAA,CAAa,GAAA,EAAK;AAAA,IAChC,KAAA,EAAO,UAAA;AAAA,IACP,QAAA;AAAA,IACA,GAAG;AAAA,GACJ,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA;AACjB;AAcO,SAAS,SAAA,CACd,GAAA,EACA,UAAA,EACA,YAAA,EACQ;AACR,EAAA,MAAM,IAAA,GAAO,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA;AAC1B,EAAA,IAAI,OAAA,GAAmB,UAAA;AAEvB,EAAA,KAAA,MAAW,KAAK,IAAA,EAAM;AACpB,IAAA,IAAI,OAAO,OAAA,KAAY,QAAA,IAAY,OAAA,KAAY,IAAA,IAAQ,KAAK,OAAA,EAAS;AACnE,MAAA,OAAA,GAAW,QAAkC,CAAC,CAAA;AAAA,IAChD,CAAA,MAAO;AACL,MAAA,OAAO,YAAA,IAAgB,GAAA;AAAA,IACzB;AAAA,EACF;AAEA,EAAA,IAAI,OAAO,YAAY,QAAA,EAAU;AAC/B,IAAA,OAAO,OAAA;AAAA,EACT;AAEA,EAAA,OAAO,YAAA,IAAgB,GAAA;AACzB;AAOO,SAAS,iBAAiB,UAAA,EAAmC;AAClE,EAAA,OAAO,CAAC,KAAa,YAAA,KAAkC;AACrD,IAAA,OAAO,SAAA,CAAU,GAAA,EAAK,UAAA,EAAY,YAAY,CAAA;AAAA,EAChD,CAAA;AACF;AAQO,SAAS,kBAAA,CAAmB,MAAqB,MAAA,EAAyB;AAC/E,EAAA,MAAM,GAAA,GAAM,UAAU,SAAA,EAAU;AAChC,EAAA,MAAM,UAAU,OAAO,IAAA,KAAS,WAAW,IAAI,IAAA,CAAK,IAAI,CAAA,GAAI,IAAA;AAC5D,EAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AACrB,EAAA,MAAM,aAAA,GAAgB,KAAK,KAAA,CAAA,CAAO,GAAA,CAAI,SAAQ,GAAI,OAAA,CAAQ,OAAA,EAAQ,IAAK,GAAI,CAAA;AAE3E,EAAA,MAAM,GAAA,GAAM,IAAI,IAAA,CAAK,kBAAA,CAAmB,KAAK,EAAE,OAAA,EAAS,QAAQ,CAAA;AAEhE,EAAA,MAAM,SAAA,GAA2E;AAAA,IAC/E,EAAE,IAAA,EAAM,MAAA,EAAQ,OAAA,EAAS,OAAA,EAAS;AAAA,IAClC,EAAE,IAAA,EAAM,OAAA,EAAS,OAAA,EAAS,MAAA,EAAQ;AAAA,IAClC,EAAE,IAAA,EAAM,MAAA,EAAQ,OAAA,EAAS,MAAA,EAAO;AAAA,IAChC,EAAE,IAAA,EAAM,KAAA,EAAO,OAAA,EAAS,KAAA,EAAM;AAAA,IAC9B,EAAE,IAAA,EAAM,MAAA,EAAQ,OAAA,EAAS,IAAA,EAAK;AAAA,IAC9B,EAAE,IAAA,EAAM,QAAA,EAAU,OAAA,EAAS,EAAA,EAAG;AAAA,IAC9B,EAAE,IAAA,EAAM,QAAA,EAAU,OAAA,EAAS,CAAA;AAAE,GAC/B;AAEA,EAAA,KAAA,MAAW,YAAY,SAAA,EAAW;AAChC,IAAA,MAAM,KAAA,GAAQ,KAAK,KAAA,CAAM,IAAA,CAAK,IAAI,aAAa,CAAA,GAAI,SAAS,OAAO,CAAA;AACnE,IAAA,IAAI,SAAS,CAAA,EAAG;AACd,MAAA,OAAO,GAAA,CAAI,OAAO,aAAA,GAAgB,CAAA,GAAI,QAAQ,CAAC,KAAA,EAAO,SAAS,IAAI,CAAA;AAAA,IACrE;AAAA,EACF;AAEA,EAAA,OAAO,GAAA,CAAI,MAAA,CAAO,CAAA,EAAG,QAAQ,CAAA;AAC/B;AAUO,SAAS,SAAA,CACd,KAAA,EACA,QAAA,EACA,MAAA,EACA,MAAA,EACQ;AACR,EAAA,MAAM,GAAA,GAAM,UAAU,SAAA,EAAU;AAChC,EAAA,MAAM,UAAA,GAAa,MAAA,IAAU,CAAA,EAAG,QAAQ,CAAA,CAAA,CAAA;AAGxC,EAAA,MAAM,WAAA,GAAc,IAAI,IAAA,CAAK,WAAA,CAAY,GAAG,CAAA;AAC5C,EAAA,MAAM,IAAA,GAAO,WAAA,CAAY,MAAA,CAAO,KAAK,CAAA;AAGrC,EAAA,IAAI,IAAA,KAAS,KAAA,IAAS,KAAA,KAAU,CAAA,EAAG;AACjC,IAAA,OAAO,CAAA,EAAG,KAAK,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAA;AAAA,EAC7B;AAEA,EAAA,OAAO,CAAA,EAAG,KAAK,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA;AAC/B","file":"chunk-OX5PLOWB.js","sourcesContent":["/**\n * 国际化工具函数\n */\n\n/**\n * 语言环境类型\n */\nexport type Locale = string;\n\n/**\n * 货币代码类型(ISO 4217)\n */\nexport type CurrencyCode = string;\n\n/**\n * 获取当前语言环境\n * @returns 语言环境字符串(如 'zh-CN', 'en-US')\n */\nexport function getLocale(): Locale {\n if (typeof navigator !== 'undefined' && navigator.language) {\n return navigator.language;\n }\n return 'en-US';\n}\n\n/**\n * 数字本地化格式化\n * @param value - 数字值\n * @param locale - 语言环境,默认为当前环境\n * @param options - Intl.NumberFormat选项\n * @returns 格式化后的字符串\n */\nexport function formatNumberI18n(\n value: number,\n locale?: Locale,\n options?: Intl.NumberFormatOptions\n): string {\n const loc = locale || getLocale();\n return new Intl.NumberFormat(loc, options).format(value);\n}\n\n/**\n * 日期本地化格式化\n * @param date - 日期对象或时间戳\n * @param locale - 语言环境,默认为当前环境\n * @param options - Intl.DateTimeFormat选项\n * @returns 格式化后的字符串\n */\nexport function formatDateI18n(\n date: Date | number,\n locale?: Locale,\n options?: Intl.DateTimeFormatOptions\n): string {\n const loc = locale || getLocale();\n const dateObj = typeof date === 'number' ? new Date(date) : date;\n return new Intl.DateTimeFormat(loc, options).format(dateObj);\n}\n\n/**\n * 货币本地化格式化\n * @param value - 金额\n * @param currency - 货币代码(ISO 4217),如 'USD', 'CNY', 'EUR'\n * @param locale - 语言环境,默认为当前环境\n * @param options - Intl.NumberFormat选项\n * @returns 格式化后的货币字符串\n */\nexport function formatCurrencyI18n(\n value: number,\n currency: CurrencyCode,\n locale?: Locale,\n options?: Intl.NumberFormatOptions\n): string {\n const loc = locale || getLocale();\n return new Intl.NumberFormat(loc, {\n style: 'currency',\n currency,\n ...options,\n }).format(value);\n}\n\n/**\n * 翻译字典类型\n */\nexport type TranslationDictionary = Record<string, string | Record<string, unknown>>;\n\n/**\n * 翻译函数\n * @param key - 翻译键(支持点号分隔的嵌套键,如 'user.name')\n * @param dictionary - 翻译字典\n * @param defaultValue - 默认值(如果找不到翻译)\n * @returns 翻译后的字符串\n */\nexport function translate(\n key: string,\n dictionary: TranslationDictionary,\n defaultValue?: string\n): string {\n const keys = key.split('.');\n let current: unknown = dictionary;\n\n for (const k of keys) {\n if (typeof current === 'object' && current !== null && k in current) {\n current = (current as TranslationDictionary)[k];\n } else {\n return defaultValue || key;\n }\n }\n\n if (typeof current === 'string') {\n return current;\n }\n\n return defaultValue || key;\n}\n\n/**\n * 创建翻译函数(带预设字典)\n * @param dictionary - 翻译字典\n * @returns 翻译函数\n */\nexport function createTranslator(dictionary: TranslationDictionary) {\n return (key: string, defaultValue?: string): string => {\n return translate(key, dictionary, defaultValue);\n };\n}\n\n/**\n * 获取相对时间格式化(本地化)\n * @param date - 日期对象或时间戳\n * @param locale - 语言环境,默认为当前环境\n * @returns 格式化后的相对时间字符串\n */\nexport function formatRelativeTime(date: Date | number, locale?: Locale): string {\n const loc = locale || getLocale();\n const dateObj = typeof date === 'number' ? new Date(date) : date;\n const now = new Date();\n const diffInSeconds = Math.floor((now.getTime() - dateObj.getTime()) / 1000);\n\n const rtf = new Intl.RelativeTimeFormat(loc, { numeric: 'auto' });\n\n const intervals: Array<{ unit: Intl.RelativeTimeFormatUnit; seconds: number }> = [\n { unit: 'year', seconds: 31536000 },\n { unit: 'month', seconds: 2592000 },\n { unit: 'week', seconds: 604800 },\n { unit: 'day', seconds: 86400 },\n { unit: 'hour', seconds: 3600 },\n { unit: 'minute', seconds: 60 },\n { unit: 'second', seconds: 1 },\n ];\n\n for (const interval of intervals) {\n const count = Math.floor(Math.abs(diffInSeconds) / interval.seconds);\n if (count >= 1) {\n return rtf.format(diffInSeconds < 0 ? count : -count, interval.unit);\n }\n }\n\n return rtf.format(0, 'second');\n}\n\n/**\n * 获取复数形式(简单实现)\n * @param count - 数量\n * @param singular - 单数形式\n * @param plural - 复数形式(可选,默认为 singular + 's')\n * @param locale - 语言环境,默认为当前环境\n * @returns 格式化后的字符串\n */\nexport function pluralize(\n count: number,\n singular: string,\n plural?: string,\n locale?: Locale\n): string {\n const loc = locale || getLocale();\n const pluralForm = plural || `${singular}s`;\n\n // 使用 Intl.PluralRules 获取正确的复数形式\n const pluralRules = new Intl.PluralRules(loc);\n const rule = pluralRules.select(count);\n\n // 简单实现:大多数语言中,1 使用单数,其他使用复数\n if (rule === 'one' || count === 1) {\n return `${count} ${singular}`;\n }\n\n return `${count} ${pluralForm}`;\n}\n"]}
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
// src/helper/tracking.ts
|
|
2
|
+
var Tracker = class {
|
|
3
|
+
constructor(options) {
|
|
4
|
+
this.eventQueue = [];
|
|
5
|
+
this.batchTimer = null;
|
|
6
|
+
this.userInfo = {};
|
|
7
|
+
this.exposureObservers = /* @__PURE__ */ new Map();
|
|
8
|
+
this.exposureTimers = /* @__PURE__ */ new Map();
|
|
9
|
+
this.exposedElements = /* @__PURE__ */ new Set();
|
|
10
|
+
if (!options.endpoint && !options.customSend) {
|
|
11
|
+
throw new Error("Either endpoint or customSend must be provided");
|
|
12
|
+
}
|
|
13
|
+
this.options = {
|
|
14
|
+
endpoint: options.endpoint || "",
|
|
15
|
+
batchSize: options.batchSize ?? 10,
|
|
16
|
+
batchDelay: options.batchDelay ?? 3e3,
|
|
17
|
+
autoTrackPageView: options.autoTrackPageView ?? true,
|
|
18
|
+
autoTrackClick: options.autoTrackClick ?? false,
|
|
19
|
+
commonParams: options.commonParams || {},
|
|
20
|
+
customSend: options.customSend,
|
|
21
|
+
debug: options.debug ?? false
|
|
22
|
+
};
|
|
23
|
+
this.sessionId = this.generateSessionId();
|
|
24
|
+
if (this.options.autoTrackPageView && typeof window !== "undefined") {
|
|
25
|
+
this.trackPageView();
|
|
26
|
+
this.setupPageViewListener();
|
|
27
|
+
}
|
|
28
|
+
if (this.options.autoTrackClick && typeof window !== "undefined") {
|
|
29
|
+
this.setupClickListener();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 生成会话ID
|
|
34
|
+
*/
|
|
35
|
+
generateSessionId() {
|
|
36
|
+
return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 获取公共数据
|
|
40
|
+
*/
|
|
41
|
+
getCommonData() {
|
|
42
|
+
const data = {
|
|
43
|
+
timestamp: Date.now(),
|
|
44
|
+
sessionId: this.sessionId,
|
|
45
|
+
...this.options.commonParams,
|
|
46
|
+
...this.userInfo
|
|
47
|
+
};
|
|
48
|
+
if (typeof window !== "undefined") {
|
|
49
|
+
data.url = window.location.href;
|
|
50
|
+
data.userAgent = navigator.userAgent;
|
|
51
|
+
}
|
|
52
|
+
return data;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 添加事件到队列
|
|
56
|
+
*/
|
|
57
|
+
enqueue(event) {
|
|
58
|
+
this.eventQueue.push(event);
|
|
59
|
+
if (this.options.debug) {
|
|
60
|
+
console.log("[Tracker] Event enqueued:", event);
|
|
61
|
+
}
|
|
62
|
+
if (this.eventQueue.length >= this.options.batchSize) {
|
|
63
|
+
this.flush();
|
|
64
|
+
} else {
|
|
65
|
+
this.scheduleBatch();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* 安排批量上报
|
|
70
|
+
*/
|
|
71
|
+
scheduleBatch() {
|
|
72
|
+
if (this.batchTimer) {
|
|
73
|
+
clearTimeout(this.batchTimer);
|
|
74
|
+
}
|
|
75
|
+
this.batchTimer = setTimeout(() => {
|
|
76
|
+
this.flush();
|
|
77
|
+
}, this.options.batchDelay);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* 上报事件
|
|
81
|
+
*/
|
|
82
|
+
async sendEvents(events) {
|
|
83
|
+
if (events.length === 0) return;
|
|
84
|
+
try {
|
|
85
|
+
if (this.options.customSend) {
|
|
86
|
+
await this.options.customSend(events);
|
|
87
|
+
} else if (this.options.endpoint) {
|
|
88
|
+
await this.sendToEndpoint(events);
|
|
89
|
+
}
|
|
90
|
+
if (this.options.debug) {
|
|
91
|
+
console.log("[Tracker] Events sent:", events);
|
|
92
|
+
}
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error("[Tracker] Failed to send events:", error);
|
|
95
|
+
this.eventQueue.unshift(...events);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* 发送到上报接口
|
|
100
|
+
*/
|
|
101
|
+
async sendToEndpoint(events) {
|
|
102
|
+
const response = await fetch(this.options.endpoint, {
|
|
103
|
+
method: "POST",
|
|
104
|
+
headers: {
|
|
105
|
+
"Content-Type": "application/json"
|
|
106
|
+
},
|
|
107
|
+
body: JSON.stringify({ events })
|
|
108
|
+
});
|
|
109
|
+
if (!response.ok) {
|
|
110
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* 立即上报所有待上报事件
|
|
115
|
+
*/
|
|
116
|
+
async flush() {
|
|
117
|
+
if (this.batchTimer) {
|
|
118
|
+
clearTimeout(this.batchTimer);
|
|
119
|
+
this.batchTimer = null;
|
|
120
|
+
}
|
|
121
|
+
if (this.eventQueue.length === 0) return;
|
|
122
|
+
const events = [...this.eventQueue];
|
|
123
|
+
this.eventQueue = [];
|
|
124
|
+
await this.sendEvents(events);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* 追踪事件
|
|
128
|
+
*/
|
|
129
|
+
trackEvent(name, params) {
|
|
130
|
+
const event = {
|
|
131
|
+
type: "event",
|
|
132
|
+
name,
|
|
133
|
+
params,
|
|
134
|
+
...this.getCommonData()
|
|
135
|
+
};
|
|
136
|
+
this.enqueue(event);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* 追踪页面浏览
|
|
140
|
+
*/
|
|
141
|
+
trackPageView(params) {
|
|
142
|
+
const event = {
|
|
143
|
+
type: "pageview",
|
|
144
|
+
name: "pageview",
|
|
145
|
+
params: {
|
|
146
|
+
path: typeof window !== "undefined" ? window.location.pathname : void 0,
|
|
147
|
+
search: typeof window !== "undefined" ? window.location.search : void 0,
|
|
148
|
+
hash: typeof window !== "undefined" ? window.location.hash : void 0,
|
|
149
|
+
...params
|
|
150
|
+
},
|
|
151
|
+
...this.getCommonData()
|
|
152
|
+
};
|
|
153
|
+
this.enqueue(event);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* 追踪点击事件
|
|
157
|
+
*/
|
|
158
|
+
trackClick(element, params) {
|
|
159
|
+
const el = typeof element === "string" ? document.querySelector(element) : element;
|
|
160
|
+
if (!el) {
|
|
161
|
+
if (this.options.debug) {
|
|
162
|
+
console.warn("[Tracker] Element not found:", element);
|
|
163
|
+
}
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const event = {
|
|
167
|
+
type: "click",
|
|
168
|
+
name: "click",
|
|
169
|
+
params: {
|
|
170
|
+
element: el.tagName.toLowerCase(),
|
|
171
|
+
id: el.id || void 0,
|
|
172
|
+
className: el.className || void 0,
|
|
173
|
+
text: el.textContent?.trim().substring(0, 100) || void 0,
|
|
174
|
+
...params
|
|
175
|
+
},
|
|
176
|
+
...this.getCommonData()
|
|
177
|
+
};
|
|
178
|
+
this.enqueue(event);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* 追踪曝光事件
|
|
182
|
+
*/
|
|
183
|
+
trackExposure(element, options, params) {
|
|
184
|
+
if (typeof window === "undefined" || !window.IntersectionObserver) {
|
|
185
|
+
if (this.options.debug) {
|
|
186
|
+
console.warn("[Tracker] IntersectionObserver is not supported");
|
|
187
|
+
}
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const el = typeof element === "string" ? document.querySelector(element) : element;
|
|
191
|
+
if (!el) {
|
|
192
|
+
if (this.options.debug) {
|
|
193
|
+
console.warn("[Tracker] Element not found:", element);
|
|
194
|
+
}
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const { threshold = 0.5, duration = 1e3, once = true } = options || {};
|
|
198
|
+
const elementId = `${Date.now()}-${Math.random()}`;
|
|
199
|
+
if (once && this.exposedElements.has(el)) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
let exposureTimer = null;
|
|
203
|
+
let startTime = null;
|
|
204
|
+
const observer = new IntersectionObserver(
|
|
205
|
+
(entries) => {
|
|
206
|
+
entries.forEach((entry) => {
|
|
207
|
+
if (entry.isIntersecting && entry.intersectionRatio >= threshold) {
|
|
208
|
+
if (!startTime) {
|
|
209
|
+
startTime = Date.now();
|
|
210
|
+
const currentStartTime = startTime;
|
|
211
|
+
exposureTimer = setTimeout(() => {
|
|
212
|
+
const event = {
|
|
213
|
+
type: "exposure",
|
|
214
|
+
name: "exposure",
|
|
215
|
+
params: {
|
|
216
|
+
element: el.tagName.toLowerCase(),
|
|
217
|
+
id: el.id || void 0,
|
|
218
|
+
className: el.className || void 0,
|
|
219
|
+
duration: currentStartTime ? Date.now() - currentStartTime : duration,
|
|
220
|
+
...params
|
|
221
|
+
},
|
|
222
|
+
...this.getCommonData()
|
|
223
|
+
};
|
|
224
|
+
this.enqueue(event);
|
|
225
|
+
this.exposedElements.add(el);
|
|
226
|
+
observer.disconnect();
|
|
227
|
+
this.exposureObservers.delete(elementId);
|
|
228
|
+
if (exposureTimer) {
|
|
229
|
+
clearTimeout(exposureTimer);
|
|
230
|
+
this.exposureTimers.delete(elementId);
|
|
231
|
+
}
|
|
232
|
+
}, duration);
|
|
233
|
+
this.exposureTimers.set(elementId, exposureTimer);
|
|
234
|
+
}
|
|
235
|
+
} else {
|
|
236
|
+
if (exposureTimer) {
|
|
237
|
+
clearTimeout(exposureTimer);
|
|
238
|
+
this.exposureTimers.delete(elementId);
|
|
239
|
+
}
|
|
240
|
+
startTime = null;
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
threshold: [threshold]
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
observer.observe(el);
|
|
249
|
+
this.exposureObservers.set(elementId, observer);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* 设置用户信息
|
|
253
|
+
*/
|
|
254
|
+
setUserInfo(userInfo) {
|
|
255
|
+
this.userInfo = { ...this.userInfo, ...userInfo };
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* 设置公共参数
|
|
259
|
+
*/
|
|
260
|
+
setCommonParams(params) {
|
|
261
|
+
this.options.commonParams = { ...this.options.commonParams, ...params };
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* 设置页面浏览监听器(SPA应用)
|
|
265
|
+
*/
|
|
266
|
+
setupPageViewListener() {
|
|
267
|
+
if (typeof window === "undefined") return;
|
|
268
|
+
window.addEventListener("popstate", () => {
|
|
269
|
+
this.trackPageView();
|
|
270
|
+
});
|
|
271
|
+
const originalPushState = history.pushState;
|
|
272
|
+
const originalReplaceState = history.replaceState;
|
|
273
|
+
history.pushState = function(...args) {
|
|
274
|
+
originalPushState.apply(history, args);
|
|
275
|
+
window.dispatchEvent(new Event("pushstate"));
|
|
276
|
+
};
|
|
277
|
+
history.replaceState = function(...args) {
|
|
278
|
+
originalReplaceState.apply(history, args);
|
|
279
|
+
window.dispatchEvent(new Event("replacestate"));
|
|
280
|
+
};
|
|
281
|
+
window.addEventListener("pushstate", () => {
|
|
282
|
+
this.trackPageView();
|
|
283
|
+
});
|
|
284
|
+
window.addEventListener("replacestate", () => {
|
|
285
|
+
this.trackPageView();
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* 设置点击事件监听器
|
|
290
|
+
*/
|
|
291
|
+
setupClickListener() {
|
|
292
|
+
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
293
|
+
document.addEventListener(
|
|
294
|
+
"click",
|
|
295
|
+
(event) => {
|
|
296
|
+
const target = event.target;
|
|
297
|
+
if (target) {
|
|
298
|
+
this.trackClick(target);
|
|
299
|
+
}
|
|
300
|
+
},
|
|
301
|
+
true
|
|
302
|
+
// 使用捕获阶段
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* 清理资源
|
|
307
|
+
*/
|
|
308
|
+
destroy() {
|
|
309
|
+
if (this.batchTimer) {
|
|
310
|
+
clearTimeout(this.batchTimer);
|
|
311
|
+
this.batchTimer = null;
|
|
312
|
+
}
|
|
313
|
+
this.exposureObservers.forEach((observer) => observer.disconnect());
|
|
314
|
+
this.exposureObservers.clear();
|
|
315
|
+
this.exposureTimers.forEach((timer) => clearTimeout(timer));
|
|
316
|
+
this.exposureTimers.clear();
|
|
317
|
+
this.flush().catch(console.error);
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
function createTracker(options) {
|
|
321
|
+
return new Tracker(options);
|
|
322
|
+
}
|
|
323
|
+
var defaultTracker = null;
|
|
324
|
+
function initTracker(options) {
|
|
325
|
+
if (defaultTracker) {
|
|
326
|
+
console.warn("[Tracker] Default tracker already initialized");
|
|
327
|
+
return defaultTracker;
|
|
328
|
+
}
|
|
329
|
+
defaultTracker = new Tracker(options);
|
|
330
|
+
return defaultTracker;
|
|
331
|
+
}
|
|
332
|
+
function getTracker() {
|
|
333
|
+
if (!defaultTracker) {
|
|
334
|
+
throw new Error("Tracker not initialized. Call initTracker() first.");
|
|
335
|
+
}
|
|
336
|
+
return defaultTracker;
|
|
337
|
+
}
|
|
338
|
+
function trackEvent(name, params) {
|
|
339
|
+
getTracker().trackEvent(name, params);
|
|
340
|
+
}
|
|
341
|
+
function trackPageView(params) {
|
|
342
|
+
getTracker().trackPageView(params);
|
|
343
|
+
}
|
|
344
|
+
function trackClick(element, params) {
|
|
345
|
+
getTracker().trackClick(element, params);
|
|
346
|
+
}
|
|
347
|
+
function trackExposure(element, options, params) {
|
|
348
|
+
getTracker().trackExposure(element, options, params);
|
|
349
|
+
}
|
|
350
|
+
function setUserInfo(userInfo) {
|
|
351
|
+
getTracker().setUserInfo(userInfo);
|
|
352
|
+
}
|
|
353
|
+
function setCommonParams(params) {
|
|
354
|
+
getTracker().setCommonParams(params);
|
|
355
|
+
}
|
|
356
|
+
async function flush() {
|
|
357
|
+
await getTracker().flush();
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
export { Tracker, createTracker, flush, getTracker, initTracker, setCommonParams, setUserInfo, trackClick, trackEvent, trackExposure, trackPageView };
|
|
361
|
+
//# sourceMappingURL=chunk-PJ7UCTX4.mjs.map
|
|
362
|
+
//# sourceMappingURL=chunk-PJ7UCTX4.mjs.map
|