From a5d6035c28c9251e031cace33ceb77cec4241dc2 Mon Sep 17 00:00:00 2001 From: IanShaw027 <131567472+IanShaw027@users.noreply.github.com> Date: Mon, 29 Dec 2025 03:18:06 +0800 Subject: [PATCH] =?UTF-8?q?fix(frontend):=20=E4=BF=AE=E5=A4=8D=E6=89=80?= =?UTF-8?q?=E6=9C=89=E9=A1=B5=E9=9D=A2=E7=9A=84UTC=E6=97=B6=E5=8C=BA?= =?UTF-8?q?=E6=97=A5=E6=9C=9F=E9=97=AE=E9=A2=98=E5=B9=B6=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **问题**: - 使用 toISOString() 格式化日期导致UTC时区问题 - 在UTC+8时区凌晨时,日期会显示为前一天 - 日期范围初始化在 onMounted 中导致重复渲染和请求 **修复**: - 统一使用本地时区格式化日期 - 在变量声明时就初始化日期范围,避免延迟初始化 - 移除 initializeDateRange() 函数,直接在声明时设置正确值 - 添加 formatLocalDate() 辅助函数统一日期格式化逻辑 **影响范围**: - 用户仪表盘 (DashboardView) - 管理员仪表盘 (admin/DashboardView) - 用户使用记录 (UsageView) - 管理员使用记录 (admin/UsageView) **效果**: - 日期范围正确包含当天数据 - 避免页面加载时的重复请求 - 改善用户体验,减少不必要的重新渲染 --- frontend/src/views/admin/DashboardView.vue | 27 ++++++------- frontend/src/views/admin/UsageView.vue | 45 +++++++++++++--------- frontend/src/views/user/DashboardView.vue | 38 +++++++++--------- frontend/src/views/user/UsageView.vue | 38 ++++++++++-------- 4 files changed, 79 insertions(+), 69 deletions(-) diff --git a/frontend/src/views/admin/DashboardView.vue b/frontend/src/views/admin/DashboardView.vue index ec98cc0d..8c0ca817 100644 --- a/frontend/src/views/admin/DashboardView.vue +++ b/frontend/src/views/admin/DashboardView.vue @@ -407,10 +407,20 @@ const trendData = ref([]) const modelStats = ref([]) const userTrend = ref([]) +// Helper function to format date in local timezone +const formatLocalDate = (date: Date): string => { + return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}` +} + +// Initialize date range immediately +const now = new Date() +const weekAgo = new Date(now) +weekAgo.setDate(weekAgo.getDate() - 6) + // Date range const granularity = ref<'day' | 'hour'>('day') -const startDate = ref('') -const endDate = ref('') +const startDate = ref(formatLocalDate(weekAgo)) +const endDate = ref(formatLocalDate(now)) // Granularity options for Select component const granularityOptions = computed(() => [ @@ -597,18 +607,6 @@ const onDateRangeChange = (range: { loadChartData() } -// Initialize default date range -const initializeDateRange = () => { - const now = new Date() - const today = now.toISOString().split('T')[0] - const weekAgo = new Date(now) - weekAgo.setDate(weekAgo.getDate() - 6) - - startDate.value = weekAgo.toISOString().split('T')[0] - endDate.value = today - granularity.value = 'day' -} - // Load data const loadDashboardStats = async () => { loading.value = true @@ -649,7 +647,6 @@ const loadChartData = async () => { onMounted(() => { loadDashboardStats() - initializeDateRange() loadChartData() }) diff --git a/frontend/src/views/admin/UsageView.vue b/frontend/src/views/admin/UsageView.vue index 2165bf2a..142a09cd 100644 --- a/frontend/src/views/admin/UsageView.vue +++ b/frontend/src/views/admin/UsageView.vue @@ -736,9 +736,19 @@ const groupOptions = computed(() => { ] }) +// Helper function to format date in local timezone +const formatLocalDate = (date: Date): string => { + return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}` +} + +// Initialize date range immediately +const now = new Date() +const weekAgo = new Date(now) +weekAgo.setDate(weekAgo.getDate() - 6) + // Date range state -const startDate = ref('') -const endDate = ref('') +const startDate = ref(formatLocalDate(weekAgo)) +const endDate = ref(formatLocalDate(now)) const filters = ref({ user_id: undefined, @@ -752,18 +762,9 @@ const filters = ref({ end_date: undefined }) -// Initialize default date range (last 7 days) -const initializeDateRange = () => { - const now = new Date() - const today = now.toISOString().split('T')[0] - const weekAgo = new Date(now) - weekAgo.setDate(weekAgo.getDate() - 6) - - startDate.value = weekAgo.toISOString().split('T')[0] - endDate.value = today - filters.value.start_date = startDate.value - filters.value.end_date = endDate.value -} +// Initialize filters with date range +filters.value.start_date = startDate.value +filters.value.end_date = endDate.value // User search with debounce const debounceSearchUsers = () => { @@ -988,9 +989,12 @@ const loadModelOptions = async () => { const endDate = new Date() const startDateRange = new Date(endDate) startDateRange.setDate(startDateRange.getDate() - 29) + // Use local timezone instead of UTC + const endDateStr = `${endDate.getFullYear()}-${String(endDate.getMonth() + 1).padStart(2, '0')}-${String(endDate.getDate()).padStart(2, '0')}` + const startDateStr = `${startDateRange.getFullYear()}-${String(startDateRange.getMonth() + 1).padStart(2, '0')}-${String(startDateRange.getDate()).padStart(2, '0')}` const response = await adminAPI.dashboard.getModelStats({ - start_date: startDateRange.toISOString().split('T')[0], - end_date: endDate.toISOString().split('T')[0] + start_date: startDateStr, + end_date: endDateStr }) const uniqueModels = new Set() response.models?.forEach((stat) => { @@ -1022,7 +1026,13 @@ const resetFilters = () => { } granularity.value = 'day' // Reset date range to default (last 7 days) - initializeDateRange() + const now = new Date() + const weekAgo = new Date(now) + weekAgo.setDate(weekAgo.getDate() - 6) + startDate.value = formatLocalDate(weekAgo) + endDate.value = formatLocalDate(now) + filters.value.start_date = startDate.value + filters.value.end_date = endDate.value pagination.value.page = 1 loadApiKeys() loadUsageLogs() @@ -1114,7 +1124,6 @@ const hideTooltip = () => { } onMounted(() => { - initializeDateRange() loadFilterOptions() loadApiKeys() loadUsageLogs() diff --git a/frontend/src/views/user/DashboardView.vue b/frontend/src/views/user/DashboardView.vue index d660e1a0..1ef4f0d2 100644 --- a/frontend/src/views/user/DashboardView.vue +++ b/frontend/src/views/user/DashboardView.vue @@ -10,7 +10,7 @@
-
+
(null) // Recent usage const recentUsage = ref([]) +// Helper function to format date in local timezone +const formatLocalDate = (date: Date): string => { + return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}` +} + +// Initialize date range immediately (not in onMounted) +const now = new Date() +const weekAgo = new Date(now) +weekAgo.setDate(weekAgo.getDate() - 6) + // Date range const granularity = ref<'day' | 'hour'>('day') -const startDate = ref('') -const endDate = ref('') +const startDate = ref(formatLocalDate(weekAgo)) +const endDate = ref(formatLocalDate(now)) // Granularity options for Select component const granularityOptions = computed(() => [ @@ -963,18 +973,6 @@ const onDateRangeChange = (range: { loadChartData() } -// Initialize default date range -const initializeDateRange = () => { - const now = new Date() - const today = now.toISOString().split('T')[0] - const weekAgo = new Date(now) - weekAgo.setDate(weekAgo.getDate() - 6) - - startDate.value = weekAgo.toISOString().split('T')[0] - endDate.value = today - granularity.value = 'day' -} - // Load data const loadDashboardStats = async () => { loading.value = true @@ -1015,8 +1013,11 @@ const loadChartData = async () => { const loadRecentUsage = async () => { loadingUsage.value = true try { - const endDate = new Date().toISOString().split('T')[0] - const startDate = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0] + // Use local timezone instead of UTC + const now = new Date() + const endDate = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}` + const weekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) + const startDate = `${weekAgo.getFullYear()}-${String(weekAgo.getMonth() + 1).padStart(2, '0')}-${String(weekAgo.getDate()).padStart(2, '0')}` const usageResponse = await usageAPI.getByDateRange(startDate, endDate) recentUsage.value = usageResponse.items.slice(0, 5) } catch (error) { @@ -1035,9 +1036,6 @@ onMounted(async () => { console.error('Failed to refresh subscription status:', error) }) - // Initialize date range (synchronous) - initializeDateRange() - // Load chart data and recent usage in parallel (non-critical) Promise.all([loadChartData(), loadRecentUsage()]).catch((error) => { console.error('Error loading secondary data:', error) diff --git a/frontend/src/views/user/UsageView.vue b/frontend/src/views/user/UsageView.vue index b326b4c5..53e6aa0b 100644 --- a/frontend/src/views/user/UsageView.vue +++ b/frontend/src/views/user/UsageView.vue @@ -488,9 +488,19 @@ const apiKeyOptions = computed(() => { ] }) +// Helper function to format date in local timezone +const formatLocalDate = (date: Date): string => { + return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}` +} + +// Initialize date range immediately +const now = new Date() +const weekAgo = new Date(now) +weekAgo.setDate(weekAgo.getDate() - 6) + // Date range state -const startDate = ref('') -const endDate = ref('') +const startDate = ref(formatLocalDate(weekAgo)) +const endDate = ref(formatLocalDate(now)) const filters = ref({ api_key_id: undefined, @@ -498,18 +508,9 @@ const filters = ref({ end_date: undefined }) -// Initialize default date range (last 7 days) -const initializeDateRange = () => { - const now = new Date() - const today = now.toISOString().split('T')[0] - const weekAgo = new Date(now) - weekAgo.setDate(weekAgo.getDate() - 6) - - startDate.value = weekAgo.toISOString().split('T')[0] - endDate.value = today - filters.value.start_date = startDate.value - filters.value.end_date = endDate.value -} +// Initialize filters with date range +filters.value.start_date = startDate.value +filters.value.end_date = endDate.value // Handle date range change from DateRangePicker const onDateRangeChange = (range: { @@ -629,7 +630,13 @@ const resetFilters = () => { end_date: undefined } // Reset date range to default (last 7 days) - initializeDateRange() + const now = new Date() + const weekAgo = new Date(now) + weekAgo.setDate(weekAgo.getDate() - 6) + startDate.value = formatLocalDate(weekAgo) + endDate.value = formatLocalDate(now) + filters.value.start_date = startDate.value + filters.value.end_date = endDate.value pagination.page = 1 loadUsageLogs() loadUsageStats() @@ -772,7 +779,6 @@ const hideTooltip = () => { } onMounted(() => { - initializeDateRange() loadApiKeys() loadUsageLogs() loadUsageStats()