@jx3box/jx3box-ui 2.4.2 → 2.4.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.
- package/assets/css/header/box.less +33 -3
- package/docs/agents/traffic-analytics.md +50 -0
- package/index.js +2 -0
- package/package.json +3 -2
- package/src/CommonHeader.vue +28 -2
- package/src/header/box-menu.js +42 -0
- package/src/header/box.vue +22 -20
- package/src/header/box2.vue +80 -264
- package/src/utils/client-stat.js +34 -6
- package/src/utils/traffic-analytics.js +504 -0
- package/tests/client-stat.test.js +11 -4
- package/tests/traffic-analytics-contract.test.js +907 -0
package/src/header/box2.vue
CHANGED
|
@@ -1,36 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<transition name="box2-fade">
|
|
3
|
-
<div v-if="status" class="c-jx3box2-mask"
|
|
3
|
+
<div v-if="status" class="c-jx3box2-mask">
|
|
4
4
|
<section class="c-jx3box2" @click.stop>
|
|
5
|
-
<div class="u-topline"></div>
|
|
6
|
-
|
|
7
|
-
<div class="u-head">
|
|
8
|
-
<div class="u-title-wrap">
|
|
9
|
-
<div class="u-logo">
|
|
10
|
-
<img svg-inline src="../../assets/img/common/logo.svg" alt="JX3BOX" />
|
|
11
|
-
</div>
|
|
12
|
-
<div>
|
|
13
|
-
<h2 class="u-title">{{ $jx3boxT("jx3boxUi.box2.title", "魔盒矩阵") }}</h2>
|
|
14
|
-
<p class="u-subtitle">THE BOX MATRIX NAVIGATION</p>
|
|
15
|
-
</div>
|
|
16
|
-
</div>
|
|
17
|
-
<div class="u-search">
|
|
18
|
-
<el-icon class="u-search-icon"><Search></Search></el-icon>
|
|
19
|
-
<input
|
|
20
|
-
v-model.trim="searchQuery"
|
|
21
|
-
class="u-search-input"
|
|
22
|
-
type="text"
|
|
23
|
-
:placeholder="$jx3boxT('jx3boxUi.box2.searchPlaceholder', '搜索应用')"
|
|
24
|
-
/>
|
|
25
|
-
<button v-if="searchQuery" class="u-search-clear" type="button" @click="searchQuery = ''">
|
|
26
|
-
<el-icon><Close /></el-icon>
|
|
27
|
-
</button>
|
|
28
|
-
</div>
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
5
|
<div class="u-body">
|
|
32
6
|
<ul class="u-list">
|
|
33
|
-
<li
|
|
7
|
+
<li>
|
|
34
8
|
<a class="u-item" href="/index">
|
|
35
9
|
<div class="u-icon-wrap">
|
|
36
10
|
<img class="u-pic" svg-inline :src="homeicon" />
|
|
@@ -38,7 +12,7 @@
|
|
|
38
12
|
<span class="u-txt">{{ $jx3boxT("jx3boxUi.commonHeader.home", "首页") }}</span>
|
|
39
13
|
</a>
|
|
40
14
|
</li>
|
|
41
|
-
<li v-for="(item, i) in
|
|
15
|
+
<li v-for="(item, i) in list" :key="i">
|
|
42
16
|
<a class="u-item" :href="item.href" :target="getTarget(item.href)">
|
|
43
17
|
<div class="u-icon-wrap">
|
|
44
18
|
<img class="u-pic" :src="getBoxIcon(item.img)" />
|
|
@@ -46,7 +20,7 @@
|
|
|
46
20
|
<span class="u-txt">{{ item.abbr }}</span>
|
|
47
21
|
</a>
|
|
48
22
|
</li>
|
|
49
|
-
<li v-if="
|
|
23
|
+
<li v-if="list.length > 0">
|
|
50
24
|
<a class="u-item" href="/app">
|
|
51
25
|
<div class="u-icon-wrap">
|
|
52
26
|
<img class="u-pic" svg-inline :src="allicon" />
|
|
@@ -55,9 +29,12 @@
|
|
|
55
29
|
</a>
|
|
56
30
|
</li>
|
|
57
31
|
</ul>
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
32
|
+
</div>
|
|
33
|
+
<div class="u-actions">
|
|
34
|
+
<button class="u-collapse" type="button" @click="closeBox">
|
|
35
|
+
<el-icon><Upload /></el-icon>
|
|
36
|
+
<span>{{ $jx3boxT("jx3boxUi.commonHeader.collapse", "收起") }}</span>
|
|
37
|
+
</button>
|
|
61
38
|
</div>
|
|
62
39
|
</section>
|
|
63
40
|
</div>
|
|
@@ -69,11 +46,9 @@ import Bus from "../../utils/bus";
|
|
|
69
46
|
import JX3BOX from "@jx3box/jx3box-common/data/jx3box.json";
|
|
70
47
|
import i18nMixin from "../../i18n/mixin";
|
|
71
48
|
import box from "../../assets/data/box.json";
|
|
72
|
-
import {
|
|
73
|
-
import axios from "axios";
|
|
74
|
-
import { flatten } from "lodash";
|
|
49
|
+
import { loadBoxMenu } from "./box-menu";
|
|
75
50
|
|
|
76
|
-
const { __cdn
|
|
51
|
+
const { __cdn } = JX3BOX;
|
|
77
52
|
|
|
78
53
|
export default {
|
|
79
54
|
name: "Box2",
|
|
@@ -81,7 +56,6 @@ export default {
|
|
|
81
56
|
data: function () {
|
|
82
57
|
return {
|
|
83
58
|
status: false,
|
|
84
|
-
searchQuery: "",
|
|
85
59
|
data: [],
|
|
86
60
|
client: location.href.includes("origin") ? "origin" : "std",
|
|
87
61
|
};
|
|
@@ -110,50 +84,8 @@ export default {
|
|
|
110
84
|
return matchedClient;
|
|
111
85
|
});
|
|
112
86
|
},
|
|
113
|
-
filteredList: function () {
|
|
114
|
-
const query = (this.searchQuery || "").toLowerCase();
|
|
115
|
-
if (!query) return this.list;
|
|
116
|
-
|
|
117
|
-
const compactQuery = query.replace(/\s+/g, "");
|
|
118
|
-
return this.list.filter((item) => {
|
|
119
|
-
const abbr = String(item.abbr || "").toLowerCase();
|
|
120
|
-
const abbrCompact = abbr.replace(/\s+/g, "");
|
|
121
|
-
const uuid = String(item.uuid || "").toLowerCase();
|
|
122
|
-
return abbr.includes(query) || abbrCompact.includes(compactQuery) || uuid.includes(query);
|
|
123
|
-
});
|
|
124
|
-
},
|
|
125
|
-
homeMatched: function () {
|
|
126
|
-
const query = (this.searchQuery || "").toLowerCase().trim();
|
|
127
|
-
if (!query) return true;
|
|
128
|
-
return this.$jx3boxT("jx3boxUi.commonHeader.home", "首页").includes(query);
|
|
129
|
-
},
|
|
130
|
-
allMatched: function () {
|
|
131
|
-
const query = (this.searchQuery || "").toLowerCase().trim();
|
|
132
|
-
if (!query) return true;
|
|
133
|
-
return this.$jx3boxT("jx3boxUi.commonHeader.all", "全部").includes(query);
|
|
134
|
-
},
|
|
135
87
|
},
|
|
136
88
|
methods: {
|
|
137
|
-
setPageScrollLock(locked) {
|
|
138
|
-
const docEl = document.documentElement;
|
|
139
|
-
const body = document.body;
|
|
140
|
-
|
|
141
|
-
if (locked) {
|
|
142
|
-
if (this.__prevHtmlOverflow === undefined) {
|
|
143
|
-
this.__prevHtmlOverflow = docEl.style.overflow;
|
|
144
|
-
}
|
|
145
|
-
if (this.__prevBodyOverflow === undefined) {
|
|
146
|
-
this.__prevBodyOverflow = body.style.overflow;
|
|
147
|
-
}
|
|
148
|
-
docEl.style.overflow = "hidden";
|
|
149
|
-
body.style.overflow = "hidden";
|
|
150
|
-
} else {
|
|
151
|
-
docEl.style.overflow = this.__prevHtmlOverflow ?? "";
|
|
152
|
-
body.style.overflow = this.__prevBodyOverflow ?? "";
|
|
153
|
-
this.__prevHtmlOverflow = undefined;
|
|
154
|
-
this.__prevBodyOverflow = undefined;
|
|
155
|
-
}
|
|
156
|
-
},
|
|
157
89
|
closeBox() {
|
|
158
90
|
this.status = false;
|
|
159
91
|
},
|
|
@@ -169,28 +101,9 @@ export default {
|
|
|
169
101
|
}
|
|
170
102
|
},
|
|
171
103
|
loadMenu() {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
this.data = data;
|
|
176
|
-
} else {
|
|
177
|
-
axios.get(__imgPath + "logo/app.json").then((res) => {
|
|
178
|
-
const _data = flatten(Object.values(res.data || {}));
|
|
179
|
-
this.data = _data.map((item) => ({
|
|
180
|
-
img: item.key + ".svg",
|
|
181
|
-
uuid: item.key,
|
|
182
|
-
abbr: item.label,
|
|
183
|
-
href: item.link,
|
|
184
|
-
client: item.client || ["std", "origin"],
|
|
185
|
-
}));
|
|
186
|
-
|
|
187
|
-
if (!this.data.length) this.data = box;
|
|
188
|
-
sessionStorage.setItem("box", JSON.stringify(this.data));
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
} catch (e) {
|
|
192
|
-
this.data = box;
|
|
193
|
-
}
|
|
104
|
+
loadBoxMenu(box).then((data) => {
|
|
105
|
+
this.data = data;
|
|
106
|
+
});
|
|
194
107
|
},
|
|
195
108
|
onEsc(e) {
|
|
196
109
|
if (e.key === "Escape") {
|
|
@@ -210,6 +123,8 @@ export default {
|
|
|
210
123
|
}
|
|
211
124
|
};
|
|
212
125
|
Bus.on("toggleBox", this.__toggleHandler);
|
|
126
|
+
this.__docClickHandler = () => this.closeBox();
|
|
127
|
+
document.addEventListener("click", this.__docClickHandler);
|
|
213
128
|
window.addEventListener("keydown", this.onEsc);
|
|
214
129
|
},
|
|
215
130
|
beforeUnmount() {
|
|
@@ -217,13 +132,11 @@ export default {
|
|
|
217
132
|
Bus.off("toggleBox", this.__toggleHandler);
|
|
218
133
|
this.__toggleHandler = null;
|
|
219
134
|
}
|
|
135
|
+
if (this.__docClickHandler) {
|
|
136
|
+
document.removeEventListener("click", this.__docClickHandler);
|
|
137
|
+
this.__docClickHandler = null;
|
|
138
|
+
}
|
|
220
139
|
window.removeEventListener("keydown", this.onEsc);
|
|
221
|
-
this.setPageScrollLock(false);
|
|
222
|
-
},
|
|
223
|
-
watch: {
|
|
224
|
-
status(val) {
|
|
225
|
-
this.setPageScrollLock(!!val);
|
|
226
|
-
},
|
|
227
140
|
},
|
|
228
141
|
};
|
|
229
142
|
</script>
|
|
@@ -233,17 +146,13 @@ export default {
|
|
|
233
146
|
.c-jx3box2-mask {
|
|
234
147
|
position: fixed;
|
|
235
148
|
left: 0;
|
|
236
|
-
top:
|
|
237
|
-
z-index:
|
|
238
|
-
width:
|
|
239
|
-
height: 100vh;
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
padding: 20px;
|
|
244
|
-
background: rgba(0, 0, 0, 0.72);
|
|
245
|
-
backdrop-filter: blur(12px);
|
|
246
|
-
-webkit-backdrop-filter: blur(12px);
|
|
149
|
+
top: @header-height;
|
|
150
|
+
z-index: 800;
|
|
151
|
+
width: 100%;
|
|
152
|
+
max-height: calc(100vh - @header-height);
|
|
153
|
+
overflow: hidden;
|
|
154
|
+
background: rgba(21, 25, 35, 0.98);
|
|
155
|
+
box-shadow: 0 18px 42px rgba(0, 0, 0, 0.36);
|
|
247
156
|
}
|
|
248
157
|
@media screen and (max-width: @phone) {
|
|
249
158
|
.c-jx3box2-mask {
|
|
@@ -253,147 +162,33 @@ export default {
|
|
|
253
162
|
|
|
254
163
|
.box2-fade-enter-active,
|
|
255
164
|
.box2-fade-leave-active {
|
|
256
|
-
transition: opacity 0.
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
.box2-fade-enter-active .c-jx3box2,
|
|
260
|
-
.box2-fade-leave-active .c-jx3box2 {
|
|
261
|
-
transition: transform 0.25s ease, opacity 0.25s ease;
|
|
165
|
+
transition: opacity 0.2s ease, transform 0.2s ease;
|
|
262
166
|
}
|
|
263
167
|
|
|
264
168
|
.box2-fade-enter-from,
|
|
265
169
|
.box2-fade-leave-to {
|
|
266
170
|
opacity: 0;
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
.box2-fade-enter-from .c-jx3box2,
|
|
270
|
-
.box2-fade-leave-to .c-jx3box2 {
|
|
271
|
-
transform: translateY(16px) scale(0.96);
|
|
272
|
-
opacity: 0;
|
|
171
|
+
transform: translateY(-12px);
|
|
273
172
|
}
|
|
274
173
|
|
|
275
174
|
.c-jx3box2 {
|
|
276
175
|
position: relative;
|
|
277
|
-
width:
|
|
278
|
-
max-height:
|
|
176
|
+
width: 100%;
|
|
177
|
+
max-height: calc(100vh - @header-height);
|
|
279
178
|
display: flex;
|
|
280
179
|
flex-direction: column;
|
|
281
180
|
overflow: hidden;
|
|
282
|
-
|
|
283
|
-
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
284
|
-
background: rgba(21, 25, 35, 0.9);
|
|
285
|
-
box-shadow: 0 30px 100px rgba(0, 0, 0, 0.45);
|
|
181
|
+
background: transparent;
|
|
286
182
|
}
|
|
287
183
|
|
|
288
184
|
.c-jx3box2 {
|
|
289
|
-
.u-
|
|
290
|
-
height: 6px;
|
|
185
|
+
.u-body {
|
|
291
186
|
width: 100%;
|
|
292
|
-
background: linear-gradient(90deg, transparent, rgba(59, 130, 246, 0.6), transparent);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
.u-head {
|
|
296
|
-
padding: 28px 32px 24px;
|
|
297
|
-
display: flex;
|
|
298
|
-
align-items: center;
|
|
299
|
-
gap: 20px;
|
|
300
|
-
justify-content: space-between;
|
|
301
|
-
flex-wrap: wrap;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
.u-title-wrap {
|
|
305
|
-
display: flex;
|
|
306
|
-
align-items: center;
|
|
307
|
-
gap: 14px;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
.u-logo {
|
|
311
|
-
width: 46px;
|
|
312
|
-
height: 46px;
|
|
313
|
-
border-radius: 14px;
|
|
314
|
-
background: #fff;
|
|
315
|
-
color: #fff;
|
|
316
|
-
display: inline-flex;
|
|
317
|
-
align-items: center;
|
|
318
|
-
justify-content: center;
|
|
319
|
-
box-shadow: 0 8px 24px rgba(37, 99, 235, 0.38);
|
|
320
|
-
padding:5px;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
.u-title {
|
|
324
187
|
margin: 0;
|
|
325
|
-
color: #fff;
|
|
326
|
-
font-size: 28px;
|
|
327
|
-
line-height: 1.1;
|
|
328
|
-
font-weight: 800;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
.u-subtitle {
|
|
332
|
-
margin: 6px 0 0;
|
|
333
|
-
color: #60a5fa;
|
|
334
|
-
font-size: 10px;
|
|
335
|
-
letter-spacing: 0.26em;
|
|
336
|
-
font-weight: 700;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
.u-search {
|
|
340
|
-
width: min(460px, 100%);
|
|
341
|
-
margin-left: auto;
|
|
342
|
-
position: relative;
|
|
343
|
-
.flex;
|
|
344
|
-
align-items: center;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
.u-search-input {
|
|
348
|
-
width: 100%;
|
|
349
|
-
height: 48px;
|
|
350
|
-
border-radius: 16px;
|
|
351
|
-
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
352
|
-
background: rgba(0, 0, 0, 0.3);
|
|
353
|
-
color: #fff;
|
|
354
|
-
outline: none;
|
|
355
|
-
padding: 0 40px 0 40px;
|
|
356
188
|
box-sizing: border-box;
|
|
357
|
-
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
.u-search-input::placeholder {
|
|
361
|
-
color: #6b7280;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
.u-search-input:focus {
|
|
365
|
-
border-color: rgba(59, 130, 246, 0.5);
|
|
366
|
-
box-shadow: 0 0 20px rgba(59, 130, 246, 0.2);
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
.u-search-icon {
|
|
370
|
-
position: absolute;
|
|
371
|
-
left: 14px;
|
|
372
|
-
top: 50%;
|
|
373
|
-
transform: translateY(-50%);
|
|
374
|
-
color: #6b7280;
|
|
375
|
-
font-size: 16px;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
.u-search-clear {
|
|
379
|
-
position: absolute;
|
|
380
|
-
right: 10px;
|
|
381
|
-
top: 50%;
|
|
382
|
-
transform: translateY(-50%);
|
|
383
|
-
border: 0;
|
|
384
|
-
background: transparent;
|
|
385
|
-
color: #798192;
|
|
386
|
-
cursor: pointer;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
.u-search-clear:hover {
|
|
390
|
-
color: #fff;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
.u-body {
|
|
394
|
-
padding: 4px 32px 24px;
|
|
189
|
+
padding: 16px 24px 22px;
|
|
395
190
|
flex: 1;
|
|
396
|
-
min-height:
|
|
191
|
+
min-height: 0;
|
|
397
192
|
display: flex;
|
|
398
193
|
flex-direction: column;
|
|
399
194
|
overflow-y: auto;
|
|
@@ -404,18 +199,18 @@ export default {
|
|
|
404
199
|
padding: 0;
|
|
405
200
|
list-style: none;
|
|
406
201
|
display: grid;
|
|
407
|
-
grid-template-columns: repeat(
|
|
408
|
-
gap:
|
|
202
|
+
grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
|
|
203
|
+
gap: 10px;
|
|
409
204
|
align-content: start;
|
|
410
205
|
}
|
|
411
206
|
|
|
412
207
|
.u-item {
|
|
413
|
-
height:
|
|
208
|
+
height: 88px;
|
|
414
209
|
display: flex;
|
|
415
210
|
flex-direction: column;
|
|
416
211
|
align-items: center;
|
|
417
212
|
justify-content: center;
|
|
418
|
-
border-radius:
|
|
213
|
+
border-radius: 12px;
|
|
419
214
|
background: rgba(255, 255, 255, 0.03);
|
|
420
215
|
border: 1px solid rgba(255, 255, 255, 0.07);
|
|
421
216
|
text-decoration: none;
|
|
@@ -423,16 +218,16 @@ export default {
|
|
|
423
218
|
}
|
|
424
219
|
|
|
425
220
|
.u-item:hover {
|
|
426
|
-
transform: translateY(-
|
|
427
|
-
border-color:
|
|
428
|
-
background:
|
|
429
|
-
box-shadow: 0 14px 26px -12px rgba(0, 0, 0, 0.55), 0 0 16px
|
|
221
|
+
transform: translateY(-2px);
|
|
222
|
+
border-color: fade(@v4primary500, 50%);
|
|
223
|
+
background: fade(@v4primary500, 12%);
|
|
224
|
+
box-shadow: 0 14px 26px -12px rgba(0, 0, 0, 0.55), 0 0 16px fade(@v4primary500, 20%);
|
|
430
225
|
}
|
|
431
226
|
|
|
432
227
|
.u-icon-wrap {
|
|
433
|
-
width:
|
|
434
|
-
height:
|
|
435
|
-
border-radius:
|
|
228
|
+
width: 40px;
|
|
229
|
+
height: 40px;
|
|
230
|
+
border-radius: 10px;
|
|
436
231
|
background: rgba(255, 255, 255, 0.05);
|
|
437
232
|
display: flex;
|
|
438
233
|
align-items: center;
|
|
@@ -441,17 +236,17 @@ export default {
|
|
|
441
236
|
}
|
|
442
237
|
|
|
443
238
|
.u-item:hover .u-icon-wrap {
|
|
444
|
-
background:
|
|
239
|
+
background: fade(@v4primary, 18%);
|
|
445
240
|
}
|
|
446
241
|
|
|
447
242
|
.u-pic {
|
|
448
|
-
width:
|
|
449
|
-
height:
|
|
243
|
+
width: 26px;
|
|
244
|
+
height: 26px;
|
|
450
245
|
object-fit: contain;
|
|
451
246
|
}
|
|
452
247
|
|
|
453
248
|
.u-txt {
|
|
454
|
-
margin-top:
|
|
249
|
+
margin-top: 7px;
|
|
455
250
|
font-size: 12px;
|
|
456
251
|
color: #a8b0be;
|
|
457
252
|
line-height: 1.2;
|
|
@@ -461,13 +256,34 @@ export default {
|
|
|
461
256
|
color: #fff;
|
|
462
257
|
}
|
|
463
258
|
|
|
464
|
-
.u-
|
|
465
|
-
|
|
259
|
+
.u-actions {
|
|
260
|
+
width: 100%;
|
|
261
|
+
margin: 0;
|
|
262
|
+
padding: 0 24px 14px;
|
|
263
|
+
box-sizing: border-box;
|
|
466
264
|
display: flex;
|
|
265
|
+
justify-content: flex-end;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.u-collapse {
|
|
269
|
+
display: inline-flex;
|
|
467
270
|
align-items: center;
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
271
|
+
gap: 5px;
|
|
272
|
+
padding: 7px 12px;
|
|
273
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
274
|
+
border-radius: 6px;
|
|
275
|
+
background: rgba(255, 255, 255, 0.06);
|
|
276
|
+
color: #a8b0be;
|
|
277
|
+
font-size: 12px;
|
|
278
|
+
line-height: 1;
|
|
279
|
+
cursor: pointer;
|
|
280
|
+
transition: all 0.2s ease;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.u-collapse:hover {
|
|
284
|
+
border-color: fade(@v4primary500, 45%);
|
|
285
|
+
background: fade(@v4primary500, 14%);
|
|
286
|
+
color: #fff;
|
|
471
287
|
}
|
|
472
288
|
|
|
473
289
|
.u-foot {
|
|
@@ -493,7 +309,7 @@ export default {
|
|
|
493
309
|
width: 6px;
|
|
494
310
|
height: 6px;
|
|
495
311
|
border-radius: 50%;
|
|
496
|
-
background:
|
|
312
|
+
background: @v4primary500;
|
|
497
313
|
}
|
|
498
314
|
|
|
499
315
|
.u-close {
|
|
@@ -511,13 +327,13 @@ export default {
|
|
|
511
327
|
|
|
512
328
|
@media screen and (max-width: 1200px) {
|
|
513
329
|
.u-list {
|
|
514
|
-
grid-template-columns: repeat(
|
|
330
|
+
grid-template-columns: repeat(auto-fill, minmax(86px, 1fr));
|
|
515
331
|
}
|
|
516
332
|
}
|
|
517
333
|
|
|
518
334
|
@media screen and (max-width: 992px) {
|
|
519
335
|
.u-list {
|
|
520
|
-
grid-template-columns: repeat(
|
|
336
|
+
grid-template-columns: repeat(auto-fill, minmax(82px, 1fr));
|
|
521
337
|
}
|
|
522
338
|
}
|
|
523
339
|
}
|
package/src/utils/client-stat.js
CHANGED
|
@@ -2,16 +2,22 @@ import { $cms } from "@jx3box/jx3box-common/js/api";
|
|
|
2
2
|
import { isMiniProgram, isApp } from "@jx3box/jx3box-common/js/utils";
|
|
3
3
|
import User from "@jx3box/jx3box-common/js/user";
|
|
4
4
|
import { applyJx3boxClientStatRules } from "./client-stat-business";
|
|
5
|
+
import packageInfo from "../../package.json";
|
|
5
6
|
|
|
6
7
|
const INSTANCE_ID_KEY = "jx3box:device_id";
|
|
7
8
|
const REPORT_DATE_KEY = "jx3box:client-stat-report-date";
|
|
8
9
|
const REPORT_SIGNATURE_KEY = "jx3box:client-stat-report-signature";
|
|
9
10
|
const STAT_SDK_VERSION = "v0.0.2";
|
|
11
|
+
const PACKAGE_VERSION = packageInfo.version;
|
|
12
|
+
const WEB_VERSION = `jx3box-ui@${PACKAGE_VERSION}`;
|
|
10
13
|
const STARTUP_DELAY_MIN = 3 * 1000;
|
|
11
14
|
const STARTUP_DELAY_MAX = 15 * 1000;
|
|
12
15
|
|
|
13
16
|
let reportTask = null;
|
|
14
17
|
let scheduledTimer = null;
|
|
18
|
+
let trafficPermission = null;
|
|
19
|
+
let trafficPermissionCheckedAt = 0;
|
|
20
|
+
const TRAFFIC_PERMISSION_MAX_AGE = 5 * 60 * 1000;
|
|
15
21
|
|
|
16
22
|
function compactPayload(payload) {
|
|
17
23
|
return Object.fromEntries(
|
|
@@ -97,6 +103,12 @@ function resolveClient(platform, userAgent) {
|
|
|
97
103
|
return "unknown";
|
|
98
104
|
}
|
|
99
105
|
|
|
106
|
+
export function resolveCurrentClientSurface() {
|
|
107
|
+
const nav = window.navigator || {};
|
|
108
|
+
const userAgent = String(nav.userAgent || "");
|
|
109
|
+
return resolveClient(resolvePlatform(userAgent, nav.platform), userAgent);
|
|
110
|
+
}
|
|
111
|
+
|
|
100
112
|
function parseBrowser(userAgent) {
|
|
101
113
|
const candidates = [
|
|
102
114
|
["Edge", /EdgA?[\s/]([\d.]+)/i],
|
|
@@ -141,10 +153,6 @@ function resolveDisplayMode() {
|
|
|
141
153
|
return "browser";
|
|
142
154
|
}
|
|
143
155
|
|
|
144
|
-
function resolveWebVersion() {
|
|
145
|
-
return window.__APP_VERSION__ || process.env.VUE_APP_VERSION || process.env.VITE_APP_VERSION || null;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
156
|
export function buildClientStatPayload(instanceId) {
|
|
149
157
|
const nav = window.navigator || {};
|
|
150
158
|
const screen = window.screen || {};
|
|
@@ -165,7 +173,9 @@ export function buildClientStatPayload(instanceId) {
|
|
|
165
173
|
platform: context.platform,
|
|
166
174
|
domain: window.location.hostname,
|
|
167
175
|
channel: resolveChannel(),
|
|
168
|
-
|
|
176
|
+
app_version: "jx3box-ui",
|
|
177
|
+
app_build: PACKAGE_VERSION,
|
|
178
|
+
web_version: WEB_VERSION,
|
|
169
179
|
sdk_version: STAT_SDK_VERSION,
|
|
170
180
|
|
|
171
181
|
os_name: system.os_name,
|
|
@@ -208,7 +218,7 @@ export function buildClientStatPayload(instanceId) {
|
|
|
208
218
|
|
|
209
219
|
function getReportSignature() {
|
|
210
220
|
const uid = User.isLogin() ? Number(User.getInfo()?.uid || localStorage.getItem("uid") || 0) : 0;
|
|
211
|
-
return `${uid}:${
|
|
221
|
+
return `${uid}:${WEB_VERSION}`;
|
|
212
222
|
}
|
|
213
223
|
|
|
214
224
|
export async function reportClientStat({ force = false } = {}) {
|
|
@@ -240,6 +250,24 @@ export async function reportClientStat({ force = false } = {}) {
|
|
|
240
250
|
return reportTask;
|
|
241
251
|
}
|
|
242
252
|
|
|
253
|
+
export async function resolveClientTrafficPermission({ force = false } = {}) {
|
|
254
|
+
if (!force && trafficPermission && Date.now() - trafficPermissionCheckedAt < TRAFFIC_PERMISSION_MAX_AGE) {
|
|
255
|
+
return trafficPermission;
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
const result = await reportClientStat({ force: true });
|
|
259
|
+
const data = result?.data;
|
|
260
|
+
if (data && typeof data.traffic_allowed === "boolean") {
|
|
261
|
+
trafficPermission = data;
|
|
262
|
+
trafficPermissionCheckedAt = Date.now();
|
|
263
|
+
return data;
|
|
264
|
+
}
|
|
265
|
+
} catch (error) {
|
|
266
|
+
// Traffic remains fail-closed when heartbeat cannot confirm permission.
|
|
267
|
+
}
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
|
|
243
271
|
function isLocalhost() {
|
|
244
272
|
return ["localhost", "127.0.0.1", "::1"].includes(window.location.hostname);
|
|
245
273
|
}
|