visual-buried-point-platform-h5 1.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,425 @@
1
+ import { Base64 } from "js-base64";
2
+ import MD5 from "md5";
3
+ import pako from "pako";
4
+ import { Config } from "../config";
5
+ import { GlobalVal } from "../config/global";
6
+ import { request } from "../reporter";
7
+ import { addCache, clearCache, getCache } from "./cache";
8
+ import { addCacheCu, clearCacheCu, getCacheCu } from "./cacheCu";
9
+ import { parsePVUVUrl, timeToStr } from "./tools";
10
+ import { originalOpen, originalSend, originalSet } from "./xhr";
11
+
12
+ export function isSupportSendBeacon() {
13
+ return !!window.navigator?.sendBeacon;
14
+ }
15
+
16
+ // const sendBeacon = isSupportSendBeacon()
17
+ // ? window.navigator.sendBeacon.bind(window.navigator)
18
+ // : reportWithXHR;
19
+
20
+ const sendBeacon = (url: string, reportData: Record<string, any>) => {
21
+ request({
22
+ url: url,
23
+ type: "POST",
24
+ data: reportData,
25
+ });
26
+ };
27
+
28
+ export function report(data, isImmediate = false) {
29
+ if (!Config.reportUrl) {
30
+ console.error("请设置上传 url 地址");
31
+ }
32
+ data = skipData(data, "time");
33
+ // 上传数据压缩
34
+ const str = JSON.stringify(data);
35
+ const output = pako.gzip(str, { to: "string" });
36
+ // 解压缩示例
37
+ // const compressed = new Uint8Array(output);
38
+ // const result = pako.inflate(compressed, { to: "string" });
39
+ // 调试上报的数据
40
+ // const base64jiem = Base64.atob("xxx");
41
+ // console.log("result: ", pako.inflate(base64jiem, { to: "string" }));
42
+ const base64Str = Base64.btoa(output);
43
+ const md5Str = MD5(base64Str);
44
+
45
+ const reportData = {
46
+ data: base64Str,
47
+ dataAbstract: md5Str,
48
+ };
49
+
50
+ if (isImmediate) {
51
+ sendBeacon(Config.reportUrl, reportData);
52
+ return;
53
+ }
54
+
55
+ if (window.requestIdleCallback) {
56
+ window.requestIdleCallback(
57
+ () => {
58
+ sendBeacon(Config.reportUrl, reportData);
59
+ },
60
+ { timeout: 3000 }
61
+ );
62
+ } else {
63
+ setTimeout(() => {
64
+ sendBeacon(Config.reportUrl, reportData);
65
+ });
66
+ }
67
+ }
68
+
69
+ // 新的pvuv上报
70
+ export function reportPuv(data) {
71
+ if (!Config.reportTrackUrl) {
72
+ console.error("please setting track report url ");
73
+ return;
74
+ }
75
+ const comData = commonData(data);
76
+ const reportData = {
77
+ ...comData,
78
+ dataAbstract: MD5(JSON.stringify(comData)),
79
+ };
80
+ sendBeacon(Config.reportTrackUrl, reportData);
81
+ }
82
+
83
+ // 新的自定义埋点上报
84
+ export function reportCuEvent(data, isImmediate = false) {
85
+ if (!Config.reportEventUrl) {
86
+ console.error("please setting custom event report url ");
87
+ return;
88
+ }
89
+ const comData = commonData(data);
90
+ const reportData = {
91
+ ...comData,
92
+ dataAbstract: MD5(JSON.stringify(comData)),
93
+ };
94
+ if (isImmediate) {
95
+ sendBeacon(Config.reportEventUrl, reportData);
96
+ return;
97
+ }
98
+ if (window.requestIdleCallback) {
99
+ window.requestIdleCallback(
100
+ () => {
101
+ sendBeacon(Config.reportEventUrl, reportData);
102
+ },
103
+ { timeout: 3000 }
104
+ );
105
+ } else {
106
+ setTimeout(() => {
107
+ sendBeacon(Config.reportEventUrl, reportData);
108
+ });
109
+ }
110
+ }
111
+
112
+ let timer = null;
113
+ let timerCu = null;
114
+ // 流量上报采集
115
+ let startTime = 0;
116
+ let startTimeLong = 0;
117
+ let tInterval = null;
118
+ let busObj = null;
119
+ export function lazyReportCache(data, timeout = 3000) {
120
+ // 当APP与内嵌H5埋点通信时 暂不上报已埋点数据 仅操作埋点
121
+ if (GlobalVal.enableJavaScriptBridgeCircle) {
122
+ return false;
123
+ }
124
+ if (
125
+ data.t === "pv" ||
126
+ data.t === "behavior" ||
127
+ data.t === "health" ||
128
+ data.t === "custom"
129
+ ) {
130
+ // 数据清洗
131
+ const eventList = sessionStorage.getItem("eventList")
132
+ ? JSON.parse(sessionStorage.getItem("eventList"))
133
+ : [];
134
+ // 可视化上报obj
135
+ let reportData = null;
136
+ // 页面性能数据、用于可视化离开页面采集数据obj
137
+ let healthData = null;
138
+ if (data.t === "pv") {
139
+ const browseList = eventList.filter(
140
+ (event) => event.type === "browse" && event.buryingType === "visual"
141
+ );
142
+ // 可视化页面浏览数据
143
+ for (let index = 0; index < browseList.length; index++) {
144
+ const item = browseList[index];
145
+ if (item.screenName == data.original_url) {
146
+ healthData = {
147
+ busSegment: item.busSegment ? item.busSegment : "",
148
+ ctk: "",
149
+ duration: 0,
150
+ element: null,
151
+ eventId: item.id,
152
+ groupId: item.groupId ? item.groupId : "",
153
+ module: item.module ? item.module : "",
154
+ event: item.eventCode,
155
+ path: "",
156
+ page: {
157
+ domain: window.location.hostname,
158
+ pageId: MD5(data.original_url),
159
+ path: data.original_url,
160
+ title: document.title,
161
+ },
162
+ properties: "",
163
+ traceId: "",
164
+ trackId: GlobalVal.trackId,
165
+ triggerTime: timeToStr(Date.now()),
166
+ };
167
+ break;
168
+ }
169
+ }
170
+ }
171
+ // 行为数据`click`
172
+ if (data.t === "behavior" && data.data && data.type === "setElmPath") {
173
+ const behaviorList = eventList.filter(
174
+ (event) => event.type === "click" && event.buryingType === "visual"
175
+ );
176
+ for (let index = 0; index < behaviorList.length; index++) {
177
+ const item = behaviorList[index];
178
+ // data.data.properties.$element_type ==>data.data.properties.$url
179
+ // `${item.screenName}/${item.elementSelector}`.includes(
180
+ // `${data.data.properties.$url}/${data.data.properties.$element_selector}`
181
+ // )
182
+ let flag =
183
+ data.data.properties.$url.includes(item.screenName) &&
184
+ `${data.data.properties.$element_selector}`.startsWith(
185
+ `${item.elementSelector}`
186
+ );
187
+
188
+ if (flag) {
189
+ let _path = window.location.pathname;
190
+ reportData = {
191
+ busSegment: item.busSegment,
192
+ ctk: "",
193
+ duration: 0,
194
+ element: {
195
+ className: data.data.properties.$element_class_name,
196
+ content: data.data.properties.$element_content,
197
+ id: "",
198
+ path: data.data.properties.$element_path,
199
+ position: "",
200
+ selector: data.data.properties.$element_selector,
201
+ type: data.data.properties.$element_type,
202
+ },
203
+ eventId: item.id,
204
+ groupId: item.groupId ? item.groupId : "",
205
+ module: item.module,
206
+ event: item.eventCode,
207
+ path: data.data.properties.$element_path,
208
+ page: {
209
+ domain: window.location.hostname,
210
+ pageId: MD5(_path),
211
+ path: _path,
212
+ title: document.title,
213
+ },
214
+ properties: "",
215
+ traceId: "",
216
+ trackId: GlobalVal.trackId,
217
+ triggerTime: timeToStr(Date.now()),
218
+ };
219
+ break;
220
+ }
221
+ }
222
+ }
223
+ //离开页面
224
+ if (data.t === "health") {
225
+ if (
226
+ Config.enableTrackPageLeave &&
227
+ healthData &&
228
+ healthData.eventCode &&
229
+ healthData.eventId
230
+ ) {
231
+ reportData = {
232
+ ...healthData,
233
+ duration: data.stay,
234
+ };
235
+ }
236
+ }
237
+
238
+ // 可视化埋点新的数据结构
239
+ if (reportData) {
240
+ addCache(reportData);
241
+ clearTimeout(timer);
242
+ timer = setTimeout(() => {
243
+ const data = getCache();
244
+ if (data.length) {
245
+ reportCuEvent(data);
246
+ clearCache();
247
+ }
248
+ }, timeout);
249
+ }
250
+ }
251
+ }
252
+
253
+ // 自定义部分 type=>custom event=>到四种具体事件类型 extend_param 扩展字段
254
+ export function onCustReport(data) {
255
+ const _page = data.$page ? data.$page : "";
256
+ const _path = _page.path ? _page.path : window.location.pathname;
257
+ const reportEventData = {
258
+ ctk: data.$ctk ? data.$ctk : "",
259
+ duration: data.$duration ? data.$duration : "",
260
+ element: null,
261
+ eventId: data.$id ? data.$id : "",
262
+ event: data.$event_code ? data.$event_code : "",
263
+ groupId: "",
264
+ busSegment: data.$busSegment,
265
+ module: data.$module,
266
+ properties: data.$extend_param ? JSON.stringify(data.$extend_param) : "",
267
+ traceId: "",
268
+ trackId: GlobalVal.trackId,
269
+ triggerTime: timeToStr(Date.now()),
270
+ path: data.$path,
271
+ page: {
272
+ domain: _page.domain ? _page.domain : "",
273
+ pageId: MD5(_path),
274
+ path: _path,
275
+ title: _page.title ? _page.title : "",
276
+ },
277
+ };
278
+
279
+ //自定义上报新数据结构
280
+ if (reportEventData) {
281
+ addCacheCu(reportEventData);
282
+ clearTimeout(timerCu);
283
+ timerCu = setTimeout(() => {
284
+ const data = getCacheCu();
285
+ if (data.length) {
286
+ reportCuEvent(data);
287
+ clearCacheCu();
288
+ }
289
+ }, 3000);
290
+ }
291
+ }
292
+
293
+ /**
294
+ * 获取circulation等数据
295
+ */
296
+ const getTrackObj = () => {
297
+ let gcp = GlobalVal.routerArray;
298
+ let hs = history.state;
299
+ if (gcp) {
300
+ let curPath = gcp[gcp.length - 1];
301
+ let sUrl = "";
302
+ if (gcp.length > 1) {
303
+ sUrl = gcp[gcp.length - 2];
304
+ } else {
305
+ sUrl = curPath;
306
+ }
307
+ return {
308
+ path: curPath,
309
+ circulation: gcp.length > 1 ? 2 : 1,
310
+ sourceUrl: sUrl,
311
+ visitPage: gcp.length,
312
+ };
313
+ } else if (hs) {
314
+ let curPath = hs.current;
315
+ let sUrl = hs.back ? hs.back : curPath;
316
+ return {
317
+ path: curPath,
318
+ circulation: hs.back ? 2 : 1,
319
+ sourceUrl: sUrl,
320
+ visitPage: hs.position + 1,
321
+ };
322
+ } else {
323
+ return {
324
+ path: "/",
325
+ circulation: 1,
326
+ sourceUrl: "/",
327
+ visitPage: 1,
328
+ };
329
+ }
330
+ };
331
+
332
+ const onTrackReport = (type: string) => {
333
+ let puvData = null;
334
+ if (type === "destroy") {
335
+ startTime = (Date.now() - startTimeLong) / 1000;
336
+ }
337
+ let dt = document.title;
338
+ let obj = getTrackObj();
339
+ puvData = {
340
+ busSegment: busObj.busSegment ? busObj.busSegment : Config.busSegment,
341
+ circulation: obj.circulation,
342
+ ctk: busObj.ctk ? busObj.ctk : "",
343
+ domain: busObj.domain ? busObj.domain : "",
344
+ duration: startTime === 0 ? 0 : startTime,
345
+ module: busObj.module ? busObj.module : Config.module,
346
+ path: obj.path,
347
+ properties: busObj.extend_param ? JSON.stringify(busObj.extend_param) : "",
348
+ sourceDomain: busObj.sourceDomain ? busObj.sourceDomain : "",
349
+ sourceUrl: obj.sourceUrl,
350
+ sourceType: "route",
351
+ title: busObj.title ? busObj.title : dt,
352
+ traceId: "",
353
+ trackId: GlobalVal.trackId,
354
+ visitPage: obj.visitPage,
355
+ visitTime: timeToStr(Date.now()),
356
+ };
357
+ if (puvData) {
358
+ reportPuv([puvData]);
359
+ }
360
+ };
361
+
362
+ /**
363
+ * 注册
364
+ */
365
+ export function onStartTrackReport(tData: any) {
366
+ parsePVUVUrl();
367
+ busObj = null;
368
+ startTime = 0;
369
+ startTimeLong = Date.now();
370
+ busObj = tData;
371
+ clearInterval(tInterval);
372
+ onTrackReport("start");
373
+ tInterval = setInterval(() => {
374
+ startTime += 15;
375
+ startTimeLong = Date.now();
376
+ onTrackReport("start");
377
+ }, 15 * 1000);
378
+ }
379
+
380
+ /**
381
+ * 销毁
382
+ */
383
+ export function onDestroyTrackReport() {
384
+ onTrackReport("destroy");
385
+ clearInterval(tInterval);
386
+ }
387
+
388
+ const commonData = (allData) => {
389
+ return {
390
+ app: GlobalVal.app,
391
+ data: allData,
392
+ device: GlobalVal.device,
393
+ lsi: GlobalVal.lsi,
394
+ projectId: Config.token,
395
+ userAgent: navigator ? navigator.userAgent : "",
396
+ anonymousId: GlobalVal.anonId,
397
+ userId: GlobalVal.userId,
398
+ };
399
+ };
400
+
401
+ export function reportWithXHR(data) {
402
+ const xhr = new XMLHttpRequest();
403
+ originalOpen.call(xhr, "post", Config.reportUrl);
404
+ originalSet.call("projectId", Config.token);
405
+ originalSend.call(xhr, JSON.stringify(data));
406
+ }
407
+
408
+ //去重cache和storage数据,避免上报重复数据
409
+ function skipData(_data, time: string) {
410
+ let d = JSON.parse(sessionStorage.getItem("skipData"));
411
+ if (d) {
412
+ let temp = {};
413
+ let result = [];
414
+ let arr = d.concat(_data);
415
+ arr.forEach((item) => {
416
+ if (!temp[item[time]]) {
417
+ result.push(item);
418
+ temp[item[time]] = true;
419
+ }
420
+ });
421
+ sessionStorage.removeItem("skipData");
422
+ return result;
423
+ }
424
+ return _data;
425
+ }