befly-admin-ui 1.10.17 → 1.10.18

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "befly-admin-ui",
3
- "version": "1.10.17",
3
+ "version": "1.10.18",
4
4
  "gitHead": "071d17be177355cdd61f30659c6e4c5873f87d39",
5
5
  "private": false,
6
6
  "description": "Befly - 管理后台功能组件",
@@ -15,8 +15,8 @@
15
15
  <span class="env-value">{{ $Data.environmentInfo.server }}</span>
16
16
  </div>
17
17
  <div class="env-compact-item">
18
- <span class="env-label">Node版本</span>
19
- <span class="env-value">{{ $Data.environmentInfo.nodeVersion }}</span>
18
+ <span class="env-label">运行时</span>
19
+ <span class="env-value">{{ $Data.environmentInfo.runtimeVersion || $Data.environmentInfo.nodeVersion }}</span>
20
20
  </div>
21
21
  <div class="env-compact-item">
22
22
  <span class="env-label">数据库</span>
@@ -46,6 +46,7 @@ const $Data = reactive({
46
46
  environmentInfo: {
47
47
  os: "",
48
48
  server: "",
49
+ runtimeVersion: "",
49
50
  nodeVersion: "",
50
51
  database: "",
51
52
  cache: "",
@@ -26,15 +26,21 @@
26
26
  </div>
27
27
  <div class="perf-metric">
28
28
  <div class="perf-info">
29
- <div class="perf-label">活跃连接</div>
30
- <div class="perf-value">{{ $Data.performanceMetrics.activeConnections }}</div>
29
+ <div class="perf-label">活跃请求</div>
30
+ <div class="perf-value">{{ $Data.performanceMetrics.activeRequests }}</div>
31
31
  </div>
32
32
  </div>
33
33
  </div>
34
- <!-- 最慢接口提示 -->
35
- <div v-if="$Data.performanceMetrics.slowestApi" class="perf-slowest">
34
+ <!-- 最慢接口列表 -->
35
+ <div v-if="$Data.slowestApis.length > 0" class="perf-slowest">
36
36
  <ErrorTriangleIcon />
37
- <span>最慢接口: {{ $Data.performanceMetrics.slowestApi.path }} ({{ $Data.performanceMetrics.slowestApi.time }}ms)</span>
37
+ <div class="perf-slowest-list">
38
+ <div v-for="(item, index) in $Data.slowestApis" :key="`${item.path}-${index}`" class="perf-slowest-item">
39
+ <span class="perf-slowest-rank">{{ index + 1 }}.</span>
40
+ <span class="perf-slowest-path">{{ item.path }}</span>
41
+ <span class="perf-slowest-time">{{ item.time }}ms</span>
42
+ </div>
43
+ </div>
38
44
  </div>
39
45
  </div>
40
46
  </div>
@@ -52,16 +58,44 @@ const $Data = reactive({
52
58
  avgResponseTime: 0,
53
59
  qps: 0,
54
60
  errorRate: 0,
61
+ activeRequests: 0,
55
62
  activeConnections: 0,
56
- slowestApi: null
57
- }
63
+ slowestApi: null,
64
+ slowestApis: []
65
+ },
66
+ slowestApis: []
58
67
  });
59
68
 
60
69
  const $Method = {
70
+ normalizeSlowestApis: function (resData) {
71
+ const apiList = [];
72
+
73
+ if (Array.isArray(resData?.slowestApis) && resData.slowestApis.length > 0) {
74
+ for (const item of resData.slowestApis) {
75
+ if (!item || !item.path) {
76
+ continue;
77
+ }
78
+
79
+ apiList.push({
80
+ path: String(item.path),
81
+ time: Number(item.time || 0)
82
+ });
83
+ }
84
+ } else if (resData?.slowestApi?.path) {
85
+ apiList.push({
86
+ path: String(resData.slowestApi.path),
87
+ time: Number(resData.slowestApi.time || 0)
88
+ });
89
+ }
90
+
91
+ return apiList.slice(0, 3);
92
+ },
61
93
  fetchData: async function () {
62
94
  try {
63
95
  const res = await $Http("/core/dashboard/performanceMetrics", {}, [""]);
64
96
  Object.assign($Data.performanceMetrics, res.data);
97
+ $Data.performanceMetrics.activeRequests = Number(res.data?.activeRequests ?? res.data?.activeConnections ?? 0);
98
+ $Data.slowestApis = $Method.normalizeSlowestApis(res.data);
65
99
  } catch (_error) {
66
100
  // 静默失败:不阻断页面展示
67
101
  }
@@ -139,6 +173,37 @@ $Method.fetchData();
139
173
  font-size: 12px;
140
174
  color: var(--warning-color);
141
175
  word-break: break-word;
176
+
177
+ .perf-slowest-list {
178
+ display: flex;
179
+ flex-direction: column;
180
+ gap: 2px;
181
+ min-width: 0;
182
+ }
183
+
184
+ .perf-slowest-item {
185
+ display: flex;
186
+ align-items: baseline;
187
+ gap: 6px;
188
+ min-width: 0;
189
+ }
190
+
191
+ .perf-slowest-rank {
192
+ font-weight: 700;
193
+ }
194
+
195
+ .perf-slowest-path {
196
+ min-width: 0;
197
+ overflow: hidden;
198
+ text-overflow: ellipsis;
199
+ white-space: nowrap;
200
+ flex: 1;
201
+ }
202
+
203
+ .perf-slowest-time {
204
+ font-weight: 600;
205
+ font-variant-numeric: tabular-nums;
206
+ }
142
207
  }
143
208
 
144
209
  .warning-tip {
@@ -219,7 +219,8 @@ const $Data = reactive({
219
219
  },
220
220
  productState: {
221
221
  selectedKey: "",
222
- options: []
222
+ options: [],
223
+ loading: false
223
224
  },
224
225
  uaStats: {
225
226
  deviceTypes: [],
@@ -325,6 +326,153 @@ const $Method = {
325
326
  },
326
327
  selectProduct: function (productKey) {
327
328
  $Data.productState.selectedKey = String(productKey || "");
329
+ $Method.fetchProductStats($Data.productState.selectedKey);
330
+ },
331
+ getSelectedProductName: function (selectedKey) {
332
+ if (!selectedKey || selectedKey === "all-products") {
333
+ return "";
334
+ }
335
+
336
+ const selected = $Data.productState.options.find((item) => item.key === selectedKey);
337
+
338
+ if (selected?.productName) {
339
+ return String(selected.productName);
340
+ }
341
+
342
+ return String(selectedKey);
343
+ },
344
+ applyOnlineStatsData: function (onlineStatsData) {
345
+ $Data.realtimeStats.onlineCount = Number(onlineStatsData?.onlineCount || 0);
346
+ $Data.realtimeStats.todayPv = Number(onlineStatsData?.today?.pv || 0);
347
+ $Data.realtimeStats.todayUv = Number(onlineStatsData?.today?.uv || 0);
348
+ $Data.realtimeStats.days = Array.isArray(onlineStatsData?.days) ? onlineStatsData.days : [];
349
+ },
350
+ applyInfoStatsData: function (infoStatsData) {
351
+ $Data.uaStats.deviceTypes = Array.isArray(infoStatsData?.today?.deviceTypes) ? infoStatsData.today.deviceTypes : [];
352
+ $Data.uaStats.browsers = Array.isArray(infoStatsData?.today?.browsers) ? infoStatsData.today.browsers : [];
353
+ $Data.uaStats.browserVersions = Array.isArray(infoStatsData?.today?.browserVersions) ? infoStatsData.today.browserVersions : [];
354
+ $Data.uaStats.osList = Array.isArray(infoStatsData?.today?.osList) ? infoStatsData.today.osList : [];
355
+ $Data.uaStats.osVersions = Array.isArray(infoStatsData?.today?.osVersions) ? infoStatsData.today.osVersions : [];
356
+ $Data.uaStats.deviceVendors = Array.isArray(infoStatsData?.today?.deviceVendors) ? infoStatsData.today.deviceVendors : [];
357
+ $Data.uaStats.deviceModels = Array.isArray(infoStatsData?.today?.deviceModels) ? infoStatsData.today.deviceModels : [];
358
+ $Data.uaStats.engines = Array.isArray(infoStatsData?.today?.engines) ? infoStatsData.today.engines : [];
359
+ $Data.uaStats.cpuArchitectures = Array.isArray(infoStatsData?.today?.cpuArchitectures) ? infoStatsData.today.cpuArchitectures : [];
360
+ },
361
+ mapProductOptions: function (onlineStatsData) {
362
+ if (!Array.isArray(onlineStatsData?.products)) {
363
+ return [];
364
+ }
365
+
366
+ return onlineStatsData.products.map((item) => {
367
+ return {
368
+ key: String(item?.key || item?.productName || ""),
369
+ productName: String(item?.productName || "-"),
370
+ today: {
371
+ pv: Number(item?.today?.pv || 0),
372
+ uv: Number(item?.today?.uv || 0)
373
+ },
374
+ week: {
375
+ pv: Number(item?.week?.pv || 0),
376
+ uv: Number(item?.week?.uv || 0)
377
+ },
378
+ month: {
379
+ pv: Number(item?.month?.pv || 0),
380
+ uv: Number(item?.month?.uv || 0)
381
+ },
382
+ days: Array.isArray(item?.days) ? item.days : [],
383
+ totalPv: Number(item?.totalPv || 0),
384
+ totalUv: Number(item?.totalUv || 0)
385
+ };
386
+ });
387
+ },
388
+ useSingleProductFallback: function (onlineStatsData) {
389
+ const days = Array.isArray(onlineStatsData?.days) ? onlineStatsData.days : [];
390
+
391
+ return [
392
+ {
393
+ key: $Data.productInfo.productName,
394
+ productName: $Data.productInfo.productName,
395
+ today: {
396
+ pv: Number(onlineStatsData?.today?.pv || 0),
397
+ uv: Number(onlineStatsData?.today?.uv || 0)
398
+ },
399
+ week: {
400
+ pv: Number(onlineStatsData?.week?.pv || 0),
401
+ uv: Number(onlineStatsData?.week?.uv || 0)
402
+ },
403
+ month: {
404
+ pv: Number(onlineStatsData?.month?.pv || 0),
405
+ uv: Number(onlineStatsData?.month?.uv || 0)
406
+ },
407
+ days: days,
408
+ totalPv: $Method.sumTrendField(days, "pv"),
409
+ totalUv: $Method.sumTrendField(days, "uv")
410
+ }
411
+ ];
412
+ },
413
+ applyProductOptions: function (onlineStatsData, infoStatsData) {
414
+ $Data.productState.options = $Method.mapProductOptions(onlineStatsData);
415
+
416
+ const onlyOneProduct = Array.isArray(infoStatsData?.month?.productNames) && infoStatsData.month.productNames.length === 1;
417
+
418
+ if (onlyOneProduct && $Data.productInfo.productName !== "-") {
419
+ $Data.productState.options = $Method.useSingleProductFallback(onlineStatsData);
420
+ }
421
+ },
422
+ updateSelectedProductOption: function (selectedKey, onlineStatsData) {
423
+ if (!selectedKey || selectedKey === "all-products") {
424
+ return;
425
+ }
426
+
427
+ const selectedIndex = $Data.productState.options.findIndex((item) => item.key === selectedKey);
428
+
429
+ if (selectedIndex < 0) {
430
+ return;
431
+ }
432
+
433
+ const days = Array.isArray(onlineStatsData?.days) ? onlineStatsData.days : [];
434
+ const current = $Data.productState.options[selectedIndex];
435
+
436
+ $Data.productState.options[selectedIndex] = {
437
+ key: current.key,
438
+ productName: current.productName,
439
+ today: {
440
+ pv: Number(onlineStatsData?.today?.pv || 0),
441
+ uv: Number(onlineStatsData?.today?.uv || 0)
442
+ },
443
+ week: {
444
+ pv: Number(onlineStatsData?.week?.pv || 0),
445
+ uv: Number(onlineStatsData?.week?.uv || 0)
446
+ },
447
+ month: {
448
+ pv: Number(onlineStatsData?.month?.pv || 0),
449
+ uv: Number(onlineStatsData?.month?.uv || 0)
450
+ },
451
+ days: days,
452
+ totalPv: $Method.sumTrendField(days, "pv"),
453
+ totalUv: $Method.sumTrendField(days, "uv")
454
+ };
455
+ },
456
+ fetchProductStats: async function (selectedKey) {
457
+ if ($Data.productState.loading) {
458
+ return;
459
+ }
460
+
461
+ $Data.productState.loading = true;
462
+
463
+ try {
464
+ const productName = $Method.getSelectedProductName(selectedKey);
465
+ const requestBody = productName ? { productName: productName } : {};
466
+ const [onlineStatsRes, infoStatsRes] = await Promise.all([$Http("/core/tongJi/onlineStats", requestBody, [""]), $Http("/core/tongJi/infoStats", requestBody, [""])]);
467
+
468
+ $Method.applyOnlineStatsData(onlineStatsRes.data);
469
+ $Method.applyInfoStatsData(infoStatsRes.data);
470
+ $Method.updateSelectedProductOption(selectedKey, onlineStatsRes.data);
471
+ } catch (_error) {
472
+ // 静默失败:不阻断页面展示
473
+ } finally {
474
+ $Data.productState.loading = false;
475
+ }
328
476
  },
329
477
  sumTrendField: function (list, field) {
330
478
  let total = 0;
@@ -439,68 +587,12 @@ const $Method = {
439
587
  const [overviewRes, onlineStatsRes, infoStatsRes, errorStatsRes] = await Promise.all([$Http("/core/dashboard/systemOverview", {}, [""]), $Http("/core/tongJi/onlineStats", {}, [""]), $Http("/core/tongJi/infoStats", {}, [""]), $Http("/core/tongJi/errorStats", {}, [""])]);
440
588
 
441
589
  Object.assign($Data.permissionStats, overviewRes.data);
442
- $Data.realtimeStats.onlineCount = Number(onlineStatsRes.data?.onlineCount || 0);
443
- $Data.realtimeStats.todayPv = Number(onlineStatsRes.data?.today?.pv || 0);
444
- $Data.realtimeStats.todayUv = Number(onlineStatsRes.data?.today?.uv || 0);
445
- $Data.realtimeStats.days = Array.isArray(onlineStatsRes.data?.days) ? onlineStatsRes.data.days : [];
590
+ $Method.applyOnlineStatsData(onlineStatsRes.data);
446
591
  $Data.productInfo.productName = String($Config.productName || "-");
447
592
  $Data.productInfo.productCode = String($Config.productCode || "-");
448
593
  $Data.productInfo.productVersion = String($Config.productVersion || "-");
449
- $Data.productState.options = Array.isArray(onlineStatsRes.data?.products)
450
- ? onlineStatsRes.data.products.map((item) => {
451
- return {
452
- key: String(item?.key || item?.productName || ""),
453
- productName: String(item?.productName || "-"),
454
- today: {
455
- pv: Number(item?.today?.pv || 0),
456
- uv: Number(item?.today?.uv || 0)
457
- },
458
- week: {
459
- pv: Number(item?.week?.pv || 0),
460
- uv: Number(item?.week?.uv || 0)
461
- },
462
- month: {
463
- pv: Number(item?.month?.pv || 0),
464
- uv: Number(item?.month?.uv || 0)
465
- },
466
- days: Array.isArray(item?.days) ? item.days : [],
467
- totalPv: Number(item?.totalPv || 0),
468
- totalUv: Number(item?.totalUv || 0)
469
- };
470
- })
471
- : [];
472
- if (Array.isArray(infoStatsRes.data?.month?.productNames) && infoStatsRes.data.month.productNames.length === 1 && $Data.productInfo.productName !== "-") {
473
- $Data.productState.options = [
474
- {
475
- key: $Data.productInfo.productName,
476
- productName: $Data.productInfo.productName,
477
- today: {
478
- pv: $Data.realtimeStats.todayPv,
479
- uv: $Data.realtimeStats.todayUv
480
- },
481
- week: {
482
- pv: Number(onlineStatsRes.data?.week?.pv || 0),
483
- uv: Number(onlineStatsRes.data?.week?.uv || 0)
484
- },
485
- month: {
486
- pv: Number(onlineStatsRes.data?.month?.pv || 0),
487
- uv: Number(onlineStatsRes.data?.month?.uv || 0)
488
- },
489
- days: $Data.realtimeStats.days,
490
- totalPv: $Method.sumTrendField($Data.realtimeStats.days, "pv"),
491
- totalUv: $Method.sumTrendField($Data.realtimeStats.days, "uv")
492
- }
493
- ];
494
- }
495
- $Data.uaStats.deviceTypes = Array.isArray(infoStatsRes.data?.today?.deviceTypes) ? infoStatsRes.data.today.deviceTypes : [];
496
- $Data.uaStats.browsers = Array.isArray(infoStatsRes.data?.today?.browsers) ? infoStatsRes.data.today.browsers : [];
497
- $Data.uaStats.browserVersions = Array.isArray(infoStatsRes.data?.today?.browserVersions) ? infoStatsRes.data.today.browserVersions : [];
498
- $Data.uaStats.osList = Array.isArray(infoStatsRes.data?.today?.osList) ? infoStatsRes.data.today.osList : [];
499
- $Data.uaStats.osVersions = Array.isArray(infoStatsRes.data?.today?.osVersions) ? infoStatsRes.data.today.osVersions : [];
500
- $Data.uaStats.deviceVendors = Array.isArray(infoStatsRes.data?.today?.deviceVendors) ? infoStatsRes.data.today.deviceVendors : [];
501
- $Data.uaStats.deviceModels = Array.isArray(infoStatsRes.data?.today?.deviceModels) ? infoStatsRes.data.today.deviceModels : [];
502
- $Data.uaStats.engines = Array.isArray(infoStatsRes.data?.today?.engines) ? infoStatsRes.data.today.engines : [];
503
- $Data.uaStats.cpuArchitectures = Array.isArray(infoStatsRes.data?.today?.cpuArchitectures) ? infoStatsRes.data.today.cpuArchitectures : [];
594
+ $Method.applyProductOptions(onlineStatsRes.data, infoStatsRes.data);
595
+ $Method.applyInfoStatsData(infoStatsRes.data);
504
596
  $Data.errorStats.trend = Array.isArray(errorStatsRes.data?.trend) ? errorStatsRes.data.trend : [];
505
597
  $Method.ensureSelectedProduct();
506
598
  } catch (_error) {