fix(frontend): 修复所有页面的UTC时区日期问题并优化初始化

**问题**:
- 使用 toISOString() 格式化日期导致UTC时区问题
- 在UTC+8时区凌晨时,日期会显示为前一天
- 日期范围初始化在 onMounted 中导致重复渲染和请求

**修复**:
- 统一使用本地时区格式化日期
- 在变量声明时就初始化日期范围,避免延迟初始化
- 移除 initializeDateRange() 函数,直接在声明时设置正确值
- 添加 formatLocalDate() 辅助函数统一日期格式化逻辑

**影响范围**:
- 用户仪表盘 (DashboardView)
- 管理员仪表盘 (admin/DashboardView)
- 用户使用记录 (UsageView)
- 管理员使用记录 (admin/UsageView)

**效果**:
- 日期范围正确包含当天数据
- 避免页面加载时的重复请求
- 改善用户体验,减少不必要的重新渲染
This commit is contained in:
IanShaw027
2025-12-29 03:18:06 +08:00
parent ecfad788d9
commit a5d6035c28
4 changed files with 79 additions and 69 deletions

View File

@@ -407,10 +407,20 @@ const trendData = ref<TrendDataPoint[]>([])
const modelStats = ref<ModelStat[]>([])
const userTrend = ref<UserUsageTrendPoint[]>([])
// 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()
})
</script>

View File

@@ -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<AdminUsageQueryParams>({
user_id: undefined,
@@ -752,18 +762,9 @@ const filters = ref<AdminUsageQueryParams>({
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<string>()
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()

View File

@@ -10,7 +10,7 @@
<!-- Row 1: Core Stats -->
<div class="grid grid-cols-2 gap-4 lg:grid-cols-4">
<!-- Balance -->
<div class="card p-4">
<div v-if="!authStore.isSimpleMode" class="card p-4">
<div class="flex items-center gap-3">
<div class="rounded-lg bg-emerald-100 p-2 dark:bg-emerald-900/30">
<svg
@@ -727,10 +727,20 @@ const trendChartRef = ref<ChartComponentRef | null>(null)
// Recent usage
const recentUsage = ref<UsageLog[]>([])
// 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)

View File

@@ -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<UsageQueryParams>({
api_key_id: undefined,
@@ -498,18 +508,9 @@ const filters = ref<UsageQueryParams>({
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()