fix(frontend): 修复所有页面的UTC时区日期问题并优化初始化
**问题**: - 使用 toISOString() 格式化日期导致UTC时区问题 - 在UTC+8时区凌晨时,日期会显示为前一天 - 日期范围初始化在 onMounted 中导致重复渲染和请求 **修复**: - 统一使用本地时区格式化日期 - 在变量声明时就初始化日期范围,避免延迟初始化 - 移除 initializeDateRange() 函数,直接在声明时设置正确值 - 添加 formatLocalDate() 辅助函数统一日期格式化逻辑 **影响范围**: - 用户仪表盘 (DashboardView) - 管理员仪表盘 (admin/DashboardView) - 用户使用记录 (UsageView) - 管理员使用记录 (admin/UsageView) **效果**: - 日期范围正确包含当天数据 - 避免页面加载时的重复请求 - 改善用户体验,减少不必要的重新渲染
This commit is contained in:
@@ -407,10 +407,20 @@ const trendData = ref<TrendDataPoint[]>([])
|
|||||||
const modelStats = ref<ModelStat[]>([])
|
const modelStats = ref<ModelStat[]>([])
|
||||||
const userTrend = ref<UserUsageTrendPoint[]>([])
|
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
|
// Date range
|
||||||
const granularity = ref<'day' | 'hour'>('day')
|
const granularity = ref<'day' | 'hour'>('day')
|
||||||
const startDate = ref('')
|
const startDate = ref(formatLocalDate(weekAgo))
|
||||||
const endDate = ref('')
|
const endDate = ref(formatLocalDate(now))
|
||||||
|
|
||||||
// Granularity options for Select component
|
// Granularity options for Select component
|
||||||
const granularityOptions = computed(() => [
|
const granularityOptions = computed(() => [
|
||||||
@@ -597,18 +607,6 @@ const onDateRangeChange = (range: {
|
|||||||
loadChartData()
|
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
|
// Load data
|
||||||
const loadDashboardStats = async () => {
|
const loadDashboardStats = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
@@ -649,7 +647,6 @@ const loadChartData = async () => {
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadDashboardStats()
|
loadDashboardStats()
|
||||||
initializeDateRange()
|
|
||||||
loadChartData()
|
loadChartData()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -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
|
// Date range state
|
||||||
const startDate = ref('')
|
const startDate = ref(formatLocalDate(weekAgo))
|
||||||
const endDate = ref('')
|
const endDate = ref(formatLocalDate(now))
|
||||||
|
|
||||||
const filters = ref<AdminUsageQueryParams>({
|
const filters = ref<AdminUsageQueryParams>({
|
||||||
user_id: undefined,
|
user_id: undefined,
|
||||||
@@ -752,18 +762,9 @@ const filters = ref<AdminUsageQueryParams>({
|
|||||||
end_date: undefined
|
end_date: undefined
|
||||||
})
|
})
|
||||||
|
|
||||||
// Initialize default date range (last 7 days)
|
// Initialize filters with date range
|
||||||
const initializeDateRange = () => {
|
filters.value.start_date = startDate.value
|
||||||
const now = new Date()
|
filters.value.end_date = endDate.value
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// User search with debounce
|
// User search with debounce
|
||||||
const debounceSearchUsers = () => {
|
const debounceSearchUsers = () => {
|
||||||
@@ -988,9 +989,12 @@ const loadModelOptions = async () => {
|
|||||||
const endDate = new Date()
|
const endDate = new Date()
|
||||||
const startDateRange = new Date(endDate)
|
const startDateRange = new Date(endDate)
|
||||||
startDateRange.setDate(startDateRange.getDate() - 29)
|
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({
|
const response = await adminAPI.dashboard.getModelStats({
|
||||||
start_date: startDateRange.toISOString().split('T')[0],
|
start_date: startDateStr,
|
||||||
end_date: endDate.toISOString().split('T')[0]
|
end_date: endDateStr
|
||||||
})
|
})
|
||||||
const uniqueModels = new Set<string>()
|
const uniqueModels = new Set<string>()
|
||||||
response.models?.forEach((stat) => {
|
response.models?.forEach((stat) => {
|
||||||
@@ -1022,7 +1026,13 @@ const resetFilters = () => {
|
|||||||
}
|
}
|
||||||
granularity.value = 'day'
|
granularity.value = 'day'
|
||||||
// Reset date range to default (last 7 days)
|
// 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
|
pagination.value.page = 1
|
||||||
loadApiKeys()
|
loadApiKeys()
|
||||||
loadUsageLogs()
|
loadUsageLogs()
|
||||||
@@ -1114,7 +1124,6 @@ const hideTooltip = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initializeDateRange()
|
|
||||||
loadFilterOptions()
|
loadFilterOptions()
|
||||||
loadApiKeys()
|
loadApiKeys()
|
||||||
loadUsageLogs()
|
loadUsageLogs()
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<!-- Row 1: Core Stats -->
|
<!-- Row 1: Core Stats -->
|
||||||
<div class="grid grid-cols-2 gap-4 lg:grid-cols-4">
|
<div class="grid grid-cols-2 gap-4 lg:grid-cols-4">
|
||||||
<!-- Balance -->
|
<!-- Balance -->
|
||||||
<div class="card p-4">
|
<div v-if="!authStore.isSimpleMode" class="card p-4">
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<div class="rounded-lg bg-emerald-100 p-2 dark:bg-emerald-900/30">
|
<div class="rounded-lg bg-emerald-100 p-2 dark:bg-emerald-900/30">
|
||||||
<svg
|
<svg
|
||||||
@@ -727,10 +727,20 @@ const trendChartRef = ref<ChartComponentRef | null>(null)
|
|||||||
// Recent usage
|
// Recent usage
|
||||||
const recentUsage = ref<UsageLog[]>([])
|
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
|
// Date range
|
||||||
const granularity = ref<'day' | 'hour'>('day')
|
const granularity = ref<'day' | 'hour'>('day')
|
||||||
const startDate = ref('')
|
const startDate = ref(formatLocalDate(weekAgo))
|
||||||
const endDate = ref('')
|
const endDate = ref(formatLocalDate(now))
|
||||||
|
|
||||||
// Granularity options for Select component
|
// Granularity options for Select component
|
||||||
const granularityOptions = computed(() => [
|
const granularityOptions = computed(() => [
|
||||||
@@ -963,18 +973,6 @@ const onDateRangeChange = (range: {
|
|||||||
loadChartData()
|
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
|
// Load data
|
||||||
const loadDashboardStats = async () => {
|
const loadDashboardStats = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
@@ -1015,8 +1013,11 @@ const loadChartData = async () => {
|
|||||||
const loadRecentUsage = async () => {
|
const loadRecentUsage = async () => {
|
||||||
loadingUsage.value = true
|
loadingUsage.value = true
|
||||||
try {
|
try {
|
||||||
const endDate = new Date().toISOString().split('T')[0]
|
// Use local timezone instead of UTC
|
||||||
const startDate = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]
|
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)
|
const usageResponse = await usageAPI.getByDateRange(startDate, endDate)
|
||||||
recentUsage.value = usageResponse.items.slice(0, 5)
|
recentUsage.value = usageResponse.items.slice(0, 5)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -1035,9 +1036,6 @@ onMounted(async () => {
|
|||||||
console.error('Failed to refresh subscription status:', error)
|
console.error('Failed to refresh subscription status:', error)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Initialize date range (synchronous)
|
|
||||||
initializeDateRange()
|
|
||||||
|
|
||||||
// Load chart data and recent usage in parallel (non-critical)
|
// Load chart data and recent usage in parallel (non-critical)
|
||||||
Promise.all([loadChartData(), loadRecentUsage()]).catch((error) => {
|
Promise.all([loadChartData(), loadRecentUsage()]).catch((error) => {
|
||||||
console.error('Error loading secondary data:', error)
|
console.error('Error loading secondary data:', error)
|
||||||
|
|||||||
@@ -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
|
// Date range state
|
||||||
const startDate = ref('')
|
const startDate = ref(formatLocalDate(weekAgo))
|
||||||
const endDate = ref('')
|
const endDate = ref(formatLocalDate(now))
|
||||||
|
|
||||||
const filters = ref<UsageQueryParams>({
|
const filters = ref<UsageQueryParams>({
|
||||||
api_key_id: undefined,
|
api_key_id: undefined,
|
||||||
@@ -498,18 +508,9 @@ const filters = ref<UsageQueryParams>({
|
|||||||
end_date: undefined
|
end_date: undefined
|
||||||
})
|
})
|
||||||
|
|
||||||
// Initialize default date range (last 7 days)
|
// Initialize filters with date range
|
||||||
const initializeDateRange = () => {
|
filters.value.start_date = startDate.value
|
||||||
const now = new Date()
|
filters.value.end_date = endDate.value
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle date range change from DateRangePicker
|
// Handle date range change from DateRangePicker
|
||||||
const onDateRangeChange = (range: {
|
const onDateRangeChange = (range: {
|
||||||
@@ -629,7 +630,13 @@ const resetFilters = () => {
|
|||||||
end_date: undefined
|
end_date: undefined
|
||||||
}
|
}
|
||||||
// Reset date range to default (last 7 days)
|
// 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
|
pagination.page = 1
|
||||||
loadUsageLogs()
|
loadUsageLogs()
|
||||||
loadUsageStats()
|
loadUsageStats()
|
||||||
@@ -772,7 +779,6 @@ const hideTooltip = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initializeDateRange()
|
|
||||||
loadApiKeys()
|
loadApiKeys()
|
||||||
loadUsageLogs()
|
loadUsageLogs()
|
||||||
loadUsageStats()
|
loadUsageStats()
|
||||||
|
|||||||
Reference in New Issue
Block a user