mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-22 16:43:35 +00:00
fix: 保持仪表盘趋势图非负并纠正小时区间
- 小时粒度请求使用用户选择的起止时间,避免近24小时被截成整天 - 修正日期展示格式化逻辑,减少时区偏移导致的窗口错位 - 趋势图 Y 轴(Token/请求数/费用等)强制最小值为 0,防止出现负刻度
This commit is contained in:
@@ -306,26 +306,9 @@ export const useDashboardStore = defineStore('dashboard', () => {
|
|||||||
url += `granularity=hour`
|
url += `granularity=hour`
|
||||||
|
|
||||||
if (dateFilter.value.customRange && dateFilter.value.customRange.length === 2) {
|
if (dateFilter.value.customRange && dateFilter.value.customRange.length === 2) {
|
||||||
// 使用自定义时间范围 - 需要将系统时区时间转换为UTC
|
// 使用自定义时间范围 - 直接按系统时区字符串传递,避免额外时区偏移导致窗口错位
|
||||||
const convertToUTC = (systemTzTimeStr) => {
|
url += `&startDate=${encodeURIComponent(dateFilter.value.customRange[0])}`
|
||||||
// 固定使用UTC+8,因为后端系统时区是UTC+8
|
url += `&endDate=${encodeURIComponent(dateFilter.value.customRange[1])}`
|
||||||
const systemTz = 8
|
|
||||||
// 解析系统时区时间字符串
|
|
||||||
const [datePart, timePart] = systemTzTimeStr.split(' ')
|
|
||||||
const [year, month, day] = datePart.split('-').map(Number)
|
|
||||||
const [hours, minutes, seconds] = timePart.split(':').map(Number)
|
|
||||||
|
|
||||||
// 创建UTC时间,使其在系统时区显示为用户选择的时间
|
|
||||||
// 例如:用户选择 UTC+8 的 2025-07-25 00:00:00
|
|
||||||
// 对应的UTC时间是 2025-07-24 16:00:00
|
|
||||||
const utcDate = new Date(
|
|
||||||
Date.UTC(year, month - 1, day, hours - systemTz, minutes, seconds)
|
|
||||||
)
|
|
||||||
return utcDate.toISOString()
|
|
||||||
}
|
|
||||||
|
|
||||||
url += `&startDate=${encodeURIComponent(convertToUTC(dateFilter.value.customRange[0]))}`
|
|
||||||
url += `&endDate=${encodeURIComponent(convertToUTC(dateFilter.value.customRange[1]))}`
|
|
||||||
} else {
|
} else {
|
||||||
// 使用预设计算时间范围,与loadApiKeysTrend保持一致
|
// 使用预设计算时间范围,与loadApiKeysTrend保持一致
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
@@ -397,21 +380,9 @@ export const useDashboardStore = defineStore('dashboard', () => {
|
|||||||
// 如果是自定义时间范围或小时粒度,传递具体的时间参数
|
// 如果是自定义时间范围或小时粒度,传递具体的时间参数
|
||||||
if (dateFilter.value.type === 'custom' || currentGranularity === 'hour') {
|
if (dateFilter.value.type === 'custom' || currentGranularity === 'hour') {
|
||||||
if (dateFilter.value.customRange && dateFilter.value.customRange.length === 2) {
|
if (dateFilter.value.customRange && dateFilter.value.customRange.length === 2) {
|
||||||
// 将系统时区时间转换为UTC
|
// 按系统时区字符串直传,避免额外时区转换
|
||||||
const convertToUTC = (systemTzTimeStr) => {
|
url += `&startDate=${encodeURIComponent(dateFilter.value.customRange[0])}`
|
||||||
const systemTz = 8
|
url += `&endDate=${encodeURIComponent(dateFilter.value.customRange[1])}`
|
||||||
const [datePart, timePart] = systemTzTimeStr.split(' ')
|
|
||||||
const [year, month, day] = datePart.split('-').map(Number)
|
|
||||||
const [hours, minutes, seconds] = timePart.split(':').map(Number)
|
|
||||||
|
|
||||||
const utcDate = new Date(
|
|
||||||
Date.UTC(year, month - 1, day, hours - systemTz, minutes, seconds)
|
|
||||||
)
|
|
||||||
return utcDate.toISOString()
|
|
||||||
}
|
|
||||||
|
|
||||||
url += `&startDate=${encodeURIComponent(convertToUTC(dateFilter.value.customRange[0]))}`
|
|
||||||
url += `&endDate=${encodeURIComponent(convertToUTC(dateFilter.value.customRange[1]))}`
|
|
||||||
} else if (currentGranularity === 'hour' && dateFilter.value.type === 'preset') {
|
} else if (currentGranularity === 'hour' && dateFilter.value.type === 'preset') {
|
||||||
// 小时粒度的预设时间范围
|
// 小时粒度的预设时间范围
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
@@ -497,26 +468,9 @@ export const useDashboardStore = defineStore('dashboard', () => {
|
|||||||
url += `granularity=hour`
|
url += `granularity=hour`
|
||||||
|
|
||||||
if (dateFilter.value.customRange && dateFilter.value.customRange.length === 2) {
|
if (dateFilter.value.customRange && dateFilter.value.customRange.length === 2) {
|
||||||
// 使用自定义时间范围 - 需要将系统时区时间转换为UTC
|
// 使用自定义时间范围 - 按系统时区字符串直传
|
||||||
const convertToUTC = (systemTzTimeStr) => {
|
url += `&startDate=${encodeURIComponent(dateFilter.value.customRange[0])}`
|
||||||
// 固定使用UTC+8,因为后端系统时区是UTC+8
|
url += `&endDate=${encodeURIComponent(dateFilter.value.customRange[1])}`
|
||||||
const systemTz = 8
|
|
||||||
// 解析系统时区时间字符串
|
|
||||||
const [datePart, timePart] = systemTzTimeStr.split(' ')
|
|
||||||
const [year, month, day] = datePart.split('-').map(Number)
|
|
||||||
const [hours, minutes, seconds] = timePart.split(':').map(Number)
|
|
||||||
|
|
||||||
// 创建UTC时间,使其在系统时区显示为用户选择的时间
|
|
||||||
// 例如:用户选择 UTC+8 的 2025-07-25 00:00:00
|
|
||||||
// 对应的UTC时间是 2025-07-24 16:00:00
|
|
||||||
const utcDate = new Date(
|
|
||||||
Date.UTC(year, month - 1, day, hours - systemTz, minutes, seconds)
|
|
||||||
)
|
|
||||||
return utcDate.toISOString()
|
|
||||||
}
|
|
||||||
|
|
||||||
url += `&startDate=${encodeURIComponent(convertToUTC(dateFilter.value.customRange[0]))}`
|
|
||||||
url += `&endDate=${encodeURIComponent(convertToUTC(dateFilter.value.customRange[1]))}`
|
|
||||||
} else {
|
} else {
|
||||||
// 使用预设计算时间范围,与setDateFilterPreset保持一致
|
// 使用预设计算时间范围,与setDateFilterPreset保持一致
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
@@ -604,20 +558,8 @@ export const useDashboardStore = defineStore('dashboard', () => {
|
|||||||
url += `granularity=hour`
|
url += `granularity=hour`
|
||||||
|
|
||||||
if (dateFilter.value.customRange && dateFilter.value.customRange.length === 2) {
|
if (dateFilter.value.customRange && dateFilter.value.customRange.length === 2) {
|
||||||
const convertToUTC = (systemTzTimeStr) => {
|
url += `&startDate=${encodeURIComponent(dateFilter.value.customRange[0])}`
|
||||||
const systemTz = 8
|
url += `&endDate=${encodeURIComponent(dateFilter.value.customRange[1])}`
|
||||||
const [datePart, timePart] = systemTzTimeStr.split(' ')
|
|
||||||
const [year, month, day] = datePart.split('-').map(Number)
|
|
||||||
const [hours, minutes, seconds] = timePart.split(':').map(Number)
|
|
||||||
|
|
||||||
const utcDate = new Date(
|
|
||||||
Date.UTC(year, month - 1, day, hours - systemTz, minutes, seconds)
|
|
||||||
)
|
|
||||||
return utcDate.toISOString()
|
|
||||||
}
|
|
||||||
|
|
||||||
url += `&startDate=${encodeURIComponent(convertToUTC(dateFilter.value.customRange[0]))}`
|
|
||||||
url += `&endDate=${encodeURIComponent(convertToUTC(dateFilter.value.customRange[1]))}`
|
|
||||||
} else {
|
} else {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
let startTime
|
let startTime
|
||||||
@@ -750,17 +692,14 @@ export const useDashboardStore = defineStore('dashboard', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const formatDateForDisplay = (date) => {
|
const formatDateForDisplay = (date) => {
|
||||||
// 固定使用UTC+8来显示时间
|
// 使用本地时间直接格式化,避免多余的时区偏移导致日期错位
|
||||||
const systemTz = 8
|
const localTime = new Date(date)
|
||||||
const tzOffset = systemTz * 60 * 60 * 1000
|
const year = localTime.getFullYear()
|
||||||
const localTime = new Date(date.getTime() + tzOffset)
|
const month = String(localTime.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(localTime.getDate()).padStart(2, '0')
|
||||||
const year = localTime.getUTCFullYear()
|
const hours = String(localTime.getHours()).padStart(2, '0')
|
||||||
const month = String(localTime.getUTCMonth() + 1).padStart(2, '0')
|
const minutes = String(localTime.getMinutes()).padStart(2, '0')
|
||||||
const day = String(localTime.getUTCDate()).padStart(2, '0')
|
const seconds = String(localTime.getSeconds()).padStart(2, '0')
|
||||||
const hours = String(localTime.getUTCHours()).padStart(2, '0')
|
|
||||||
const minutes = String(localTime.getUTCMinutes()).padStart(2, '0')
|
|
||||||
const seconds = String(localTime.getUTCSeconds()).padStart(2, '0')
|
|
||||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1036,6 +1036,7 @@ function createUsageTrendChart() {
|
|||||||
type: 'linear',
|
type: 'linear',
|
||||||
display: true,
|
display: true,
|
||||||
position: 'left',
|
position: 'left',
|
||||||
|
min: 0,
|
||||||
title: {
|
title: {
|
||||||
display: true,
|
display: true,
|
||||||
text: 'Token数量',
|
text: 'Token数量',
|
||||||
@@ -1055,6 +1056,7 @@ function createUsageTrendChart() {
|
|||||||
type: 'linear',
|
type: 'linear',
|
||||||
display: true,
|
display: true,
|
||||||
position: 'right',
|
position: 'right',
|
||||||
|
min: 0,
|
||||||
title: {
|
title: {
|
||||||
display: true,
|
display: true,
|
||||||
text: '请求数',
|
text: '请求数',
|
||||||
@@ -1073,7 +1075,8 @@ function createUsageTrendChart() {
|
|||||||
y2: {
|
y2: {
|
||||||
type: 'linear',
|
type: 'linear',
|
||||||
display: false, // 隐藏费用轴,在tooltip中显示
|
display: false, // 隐藏费用轴,在tooltip中显示
|
||||||
position: 'right'
|
position: 'right',
|
||||||
|
min: 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1253,6 +1256,7 @@ function createApiKeysUsageTrendChart() {
|
|||||||
},
|
},
|
||||||
y: {
|
y: {
|
||||||
beginAtZero: true,
|
beginAtZero: true,
|
||||||
|
min: 0,
|
||||||
title: {
|
title: {
|
||||||
display: true,
|
display: true,
|
||||||
text: apiKeysTrendMetric.value === 'tokens' ? 'Token 数量' : '请求次数',
|
text: apiKeysTrendMetric.value === 'tokens' ? 'Token 数量' : '请求次数',
|
||||||
@@ -1428,6 +1432,7 @@ function createAccountUsageTrendChart() {
|
|||||||
},
|
},
|
||||||
y: {
|
y: {
|
||||||
beginAtZero: true,
|
beginAtZero: true,
|
||||||
|
min: 0,
|
||||||
title: {
|
title: {
|
||||||
display: true,
|
display: true,
|
||||||
text: '消耗金额 (USD)',
|
text: '消耗金额 (USD)',
|
||||||
|
|||||||
Reference in New Issue
Block a user