From dad3b97dfccd0088b6b18000344e558718eaef3e Mon Sep 17 00:00:00 2001 From: Orion Date: Fri, 10 Jul 2026 11:40:11 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=88=20=E4=BF=AE=E5=A4=8D=E8=B6=8B?= =?UTF-8?q?=E5=8A=BF=E5=9D=90=E6=A0=87=E8=BD=B4=E4=B8=8E=E7=A7=BB=E5=8A=A8?= =?UTF-8?q?=E6=97=A5=E6=9C=9F=E9=80=89=E6=8B=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/NativeDateSelect.vue | 26 ++++++++++++++++ src/components/common/SmoothTrendCanvas.vue | 33 +++++++++++++++------ src/views/manage/DashboardView.vue | 10 +++---- 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/src/components/common/NativeDateSelect.vue b/src/components/common/NativeDateSelect.vue index 58eb5ad..229a6b2 100644 --- a/src/components/common/NativeDateSelect.vue +++ b/src/components/common/NativeDateSelect.vue @@ -212,6 +212,32 @@ const updatePart = (part: DatePart, value: string) => { pointer-events: none; } +@media (max-width: 639px) { + .native-date-strip { + min-height: 2.35rem; + padding-inline: 0.35ch; + } + + .native-date-part { + height: 2.25rem; + font-size: 0.82rem; + } + + .native-date-year { + width: 3.7ch; + } + + .native-date-month, + .native-date-day { + width: 1.8ch; + } + + .native-date-separator { + margin-inline: 0.15ch; + font-size: 0.82rem; + } +} + .dark .native-date-strip { background: rgba(38, 57, 65, 0.62); color: #d8e3e5; diff --git a/src/components/common/SmoothTrendCanvas.vue b/src/components/common/SmoothTrendCanvas.vue index 9fb7cde..158b187 100644 --- a/src/components/common/SmoothTrendCanvas.vue +++ b/src/components/common/SmoothTrendCanvas.vue @@ -44,10 +44,11 @@ const emit = defineEmits<{ }>() type DragState = { - startX: number + startOffset: number lastX: number time: number pointerType: string + isTimeline: boolean moved: boolean } @@ -162,10 +163,11 @@ const draw = (timestamp = performance.now()) => { const padBottom = mobile ? 42 : 36 const width = Math.max(1, rect.width - padLeft - padRight) const height = Math.max(1, rect.height - padTop - padBottom) - const max = Math.max( - 1, + const rawMax = Math.max( + 0, ...visible.flatMap((row) => [Number(row.downloads || 0), Number(row.uploads || 0)]) ) + const max = rawMax <= 2 ? 3 : Math.ceil(rawMax / 3) * 3 const muted = props.isDarkMode ? '#9ca3af' : '#6b7280' const border = props.isDarkMode ? '#374151' : '#e5e7eb' const downloadColor = props.isDarkMode ? '#8fb6c5' : '#5f8fa3' @@ -185,17 +187,23 @@ const draw = (timestamp = performance.now()) => { } const denominator = Math.max(1, windowSize.value - 1) + const plotLeft = padLeft + const plotRight = padLeft + width const buildPoints = (field: 'downloads' | 'uploads') => visible .map((row, index) => { const sourceIndex = start + index return { - x: padLeft + ((sourceIndex - offset.value) / denominator) * width, + x: clamp( + padLeft + ((sourceIndex - offset.value) / denominator) * width, + plotLeft, + plotRight + ), y: padTop + height - (Number(row[field] || 0) / max) * height, row } }) - .filter((point) => point.x >= padLeft - 50 && point.x <= padLeft + width + 50) + .filter((point) => point.x >= plotLeft && point.x <= plotRight) const drawSeries = (points: ChartPoint[], color: string) => { ctx.strokeStyle = color @@ -392,17 +400,21 @@ const setHoverFromClientX = (clientX: number) => { } const handlePointerDown = (event: PointerEvent) => { + const rect = canvasRef.value?.getBoundingClientRect() canvasRef.value?.setPointerCapture(event.pointerId) cancelInertia() velocity.value = 0 setHoverFromClientX(event.clientX) + const isTimeline = Boolean(rect && event.clientY - rect.top >= rect.height - 52) drag.value = { - startX: event.clientX, + startOffset: offset.value, lastX: event.clientX, time: event.timeStamp || performance.now(), pointerType: event.pointerType, + isTimeline, moved: false } + if (isTimeline) canvasRef.value!.style.touchAction = 'none' } const handlePointerMove = (event: PointerEvent) => { @@ -416,12 +428,12 @@ const handlePointerMove = (event: PointerEvent) => { return } - if (drag.value.pointerType === 'touch') { + if (drag.value.pointerType === 'touch' && !drag.value.isTimeline) { scheduleDraw() return } - const totalDistance = Math.abs(latestEvent.clientX - drag.value.startX) + const totalDistance = Math.abs(latestEvent.clientX - drag.value.lastX) const threshold = 3 if (!drag.value.moved && totalDistance < threshold) { scheduleDraw() @@ -440,15 +452,18 @@ const handlePointerMove = (event: PointerEvent) => { } const handlePointerUp = () => { + const timelineDrag = drag.value?.isTimeline const shouldInertia = Boolean(drag.value?.moved) drag.value = null + if (canvasRef.value) canvasRef.value.style.touchAction = '' cancelInertia() - if (shouldInertia) inertiaRafId.value = window.requestAnimationFrame(applyInertia) + if (shouldInertia && !timelineDrag) inertiaRafId.value = window.requestAnimationFrame(applyInertia) else scheduleDraw() } const handlePointerCancel = () => { drag.value = null + if (canvasRef.value) canvasRef.value.style.touchAction = '' } const handlePointerLeave = () => { diff --git a/src/views/manage/DashboardView.vue b/src/views/manage/DashboardView.vue index bc68f8a..ce7da59 100644 --- a/src/views/manage/DashboardView.vue +++ b/src/views/manage/DashboardView.vue @@ -239,10 +239,9 @@

{{ analyticsSummaryText }}

-

轻触或滑动查看数据,使用下方按钮调整范围

+

轻触或滑动查看数据;拖动底部日期轴平移图表

-
-
+
- @@ -262,7 +261,7 @@ @change="fetchAnalyticsData" />
-
+ -