From 2cde31f8227e5823fccbfa5c80af6ab3776ec7e4 Mon Sep 17 00:00:00 2001 From: Orion Date: Fri, 5 Jun 2026 16:03:54 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20=E4=BC=98=E5=8C=96=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E9=A1=B5=E4=BA=A4=E4=BA=92=E4=B8=8E=E5=8E=86=E5=8F=B2?= =?UTF-8?q?=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/DataTable.vue | 11 ++- src/components/common/SmoothTrendCanvas.vue | 46 ++++------ src/i18n/locales/en-US.ts | 8 +- src/i18n/locales/zh-CN.ts | 8 +- src/views/manage/DashboardView.vue | 37 ++++++-- src/views/manage/FileManageView.vue | 97 +++++++++++++++------ 6 files changed, 131 insertions(+), 76 deletions(-) diff --git a/src/components/common/DataTable.vue b/src/components/common/DataTable.vue index 806d4ff..a07731c 100644 --- a/src/components/common/DataTable.vue +++ b/src/components/common/DataTable.vue @@ -6,9 +6,14 @@ class="border-b px-6 py-4" :class="[isDarkMode ? 'border-gray-700/80' : 'border-[#d9e4e6]']" > -

- {{ title }} -

+
+

+ {{ title }} +

+
+ +
+
diff --git a/src/components/common/SmoothTrendCanvas.vue b/src/components/common/SmoothTrendCanvas.vue index b6e46ae..96fdbf6 100644 --- a/src/components/common/SmoothTrendCanvas.vue +++ b/src/components/common/SmoothTrendCanvas.vue @@ -100,8 +100,6 @@ const formatBytes = (value: number | string | undefined) => { return `${(bytes / 1024 ** index).toFixed(index === 0 ? 0 : 1)} ${units[index]}` } -const lerp = (start: number, end: number, amount: number) => start + (end - start) * amount - const clamp = (value: number, min: number, max: number) => Math.max(min, Math.min(max, value)) const getDefaultWindow = () => { @@ -259,52 +257,38 @@ const draw = () => { if (hoverX.value !== null && points.length && total) { const hoverRatio = clamp((hoverX.value - padLeft) / width, 0, 1) - const sourceIndex = clamp(offset.value + hoverRatio * denominator, 0, total - 1) - const leftIndex = Math.floor(sourceIndex) - const rightIndex = Math.min(total - 1, Math.ceil(sourceIndex)) - const mix = sourceIndex - leftIndex - const leftRow = props.rows[leftIndex] - const rightRow = props.rows[rightIndex] || leftRow - const interpolatedX = padLeft + ((sourceIndex - offset.value) / denominator) * width - const downloads = lerp(Number(leftRow.downloads || 0), Number(rightRow.downloads || 0), mix) - const uploads = lerp(Number(leftRow.uploads || 0), Number(rightRow.uploads || 0), mix) - const downloadTraffic = lerp( - Number(leftRow.downloadTraffic || 0), - Number(rightRow.downloadTraffic || 0), - mix - ) - const uploadTraffic = lerp( - Number(leftRow.uploadTraffic || 0), - Number(rightRow.uploadTraffic || 0), - mix - ) + const sourceIndex = Math.round(clamp(offset.value + hoverRatio * denominator, 0, total - 1)) + const row = props.rows[sourceIndex] + const snapX = padLeft + ((sourceIndex - offset.value) / denominator) * width + const downloads = Number(row.downloads || 0) + const uploads = Number(row.uploads || 0) + const downloadTraffic = Number(row.downloadTraffic || 0) + const uploadTraffic = Number(row.uploadTraffic || 0) const downloadY = padTop + height - (downloads / max) * height const uploadY = padTop + height - (uploads / max) * height const anchorY = Math.min(downloadY, uploadY) const placeBelow = anchorY < 104 const tooltipInset = Math.min(mobile ? 116 : 132, Math.max(48, rect.width / 2 - 8)) - const dateText = - leftRow.date === rightRow.date ? leftRow.date : `${leftRow.date} - ${rightRow.date}` ctx.strokeStyle = props.isDarkMode ? 'rgba(148, 163, 184, 0.35)' : 'rgba(91, 121, 132, 0.28)' ctx.lineWidth = 1 ctx.beginPath() - ctx.moveTo(interpolatedX, padTop) - ctx.lineTo(interpolatedX, padTop + height) + ctx.moveTo(snapX, padTop) + ctx.lineTo(snapX, padTop + height) ctx.stroke() tooltip.value = { - left: clamp(interpolatedX, tooltipInset, rect.width - tooltipInset), + left: clamp(snapX, tooltipInset, rect.width - tooltipInset), top: placeBelow ? anchorY + 16 : anchorY - 12, - date: dateText, - downloads: Math.round(downloads), - uploads: Math.round(uploads), + date: row.date, + downloads, + uploads, downloadTraffic: formatBytes(downloadTraffic), uploadTraffic: formatBytes(uploadTraffic), transform: placeBelow ? 'translate(-50%, 0)' : 'translate(-50%, -100%)' } - drawHoverPoint({ x: interpolatedX, y: downloadY }, downloadColor) - drawHoverPoint({ x: interpolatedX, y: uploadY }, uploadColor) + drawHoverPoint({ x: snapX, y: downloadY }, downloadColor) + drawHoverPoint({ x: snapX, y: uploadY }, uploadColor) } else { tooltip.value = null } diff --git a/src/i18n/locales/en-US.ts b/src/i18n/locales/en-US.ts index 584e374..ca3bce4 100644 --- a/src/i18n/locales/en-US.ts +++ b/src/i18n/locales/en-US.ts @@ -567,10 +567,10 @@ export default { permanent: 'Permanent' }, insightActions: { - monitor: 'Keep monitoring', - extend_or_delete: 'Extend retention or clean up', - inspect_storage: 'Inspect storage path and file name', - extend_expiration: 'Extend expiration if needed' + monitor: 'No action needed', + extend_or_delete: 'Extend or clean up', + inspect_storage: 'Check storage info', + extend_expiration: 'Extend validity' }, insightReasons: { expired: 'Past expiration time', diff --git a/src/i18n/locales/zh-CN.ts b/src/i18n/locales/zh-CN.ts index db11836..f719c97 100644 --- a/src/i18n/locales/zh-CN.ts +++ b/src/i18n/locales/zh-CN.ts @@ -564,10 +564,10 @@ export default { permanent: '永久有效' }, insightActions: { - monitor: '保持观察', - extend_or_delete: '延长有效期或清理记录', - inspect_storage: '检查存储路径与文件名', - extend_expiration: '按需延长过期时间' + monitor: '无需处理', + extend_or_delete: '建议延长或清理', + inspect_storage: '检查存储信息', + extend_expiration: '建议延长有效期' }, insightReasons: { expired: '已超过过期时间', diff --git a/src/views/manage/DashboardView.vue b/src/views/manage/DashboardView.vue index 82a0ef0..4b2b5b9 100644 --- a/src/views/manage/DashboardView.vue +++ b/src/views/manage/DashboardView.vue @@ -10,11 +10,13 @@ {{ t('admin.dashboard.lastUpdated', { time: lastUpdatedText }) }}

- + - {{ isLoading ? t('admin.dashboard.refreshing') : t('admin.dashboard.refresh') }} + {{ + isDashboardRefreshing ? t('admin.dashboard.refreshing') : t('admin.dashboard.refresh') + }} @@ -260,13 +262,28 @@ />
- + 放大 - + 缩小 - + 重置
@@ -476,6 +493,7 @@ const analyticsStart = ref(daysAgo(120)) const analyticsEnd = ref(today()) const analyticsData = ref(null) const analyticsError = ref('') +const isAnalyticsLoading = ref(false) const analyticsWindowText = ref('无数据') const analyticsDailyRows = computed(() => analyticsData.value?.daily || []) const analyticsTopFiles = computed(() => analyticsData.value?.topFiles || []) @@ -497,12 +515,19 @@ const formatBytes = (value: number | string | undefined) => formatFileSize(Numbe const fetchAnalyticsData = async () => { analyticsError.value = '' + isAnalyticsLoading.value = true try { analyticsData.value = await fetchAnalytics(analyticsStart.value, analyticsEnd.value) } catch (error) { analyticsError.value = error instanceof Error ? error.message : '统计加载失败' + } finally { + isAnalyticsLoading.value = false } } +const isDashboardRefreshing = computed(() => isLoading.value || isAnalyticsLoading.value) +const refreshDashboardPage = async () => { + await Promise.all([fetchDashboardData(), fetchAnalyticsData()]) +} const healthActions = computed(() => [ { @@ -648,6 +673,6 @@ const PolicyRow = defineComponent({ }) onMounted(() => { - void Promise.all([fetchDashboardData(), fetchAnalyticsData()]) + void refreshDashboardPage() }) diff --git a/src/views/manage/FileManageView.vue b/src/views/manage/FileManageView.vue index a8d7b21..7b5a745 100644 --- a/src/views/manage/FileManageView.vue +++ b/src/views/manage/FileManageView.vue @@ -10,12 +10,6 @@

- - - {{ t('fileManage.refresh') }} - +