fix(admin-spa): 修复仪表板图表时区处理问题

- 修复前端时间计算逻辑,正确处理不同时区用户的时间范围选择
- 添加系统时区信息到dashboard API响应
- 修改getSystemTimezoneDay函数,确保正确处理系统时区的日期转换
- 修复"昨天"和"前天"时间范围计算,基于系统时区而非用户时区
- 添加后端调试日志以便追踪时间转换问题

问题描述:
- 选择"昨天"时显示29号7:00到30号6:00(错误)
- 选择"近24小时"时显示29号17:00到30号17:00(错误)

修复后:
- "昨天"正确显示完整一天(如29号0:00到29号23:59)
- "近24小时"正确显示从当前时间往前24小时
- 支持所有时区的用户,不再硬编码UTC+8偏移

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
shaw
2025-07-30 10:52:26 +08:00
parent 496569d110
commit a265ebf335
3 changed files with 93 additions and 70 deletions

View File

@@ -1293,7 +1293,8 @@ router.get('/dashboard', authenticateAdmin, async (req, res) => {
claudeAccountsHealthy: activeClaudeAccounts > 0,
geminiAccountsHealthy: activeGeminiAccounts > 0,
uptime: process.uptime()
}
},
systemTimezone: config.system.timezoneOffset || 8
};
res.json({ success: true, data: dashboard });
@@ -1452,6 +1453,14 @@ router.get('/usage-trend', authenticateAdmin, async (req, res) => {
// 使用自定义时间范围
startTime = new Date(startDate);
endTime = new Date(endDate);
// 调试日志
logger.info(`📊 Usage trend hour granularity - received times:`);
logger.info(` startDate (raw): ${startDate}`);
logger.info(` endDate (raw): ${endDate}`);
logger.info(` startTime (parsed): ${startTime.toISOString()}`);
logger.info(` endTime (parsed): ${endTime.toISOString()}`);
logger.info(` System timezone offset: ${config.system.timezoneOffset || 8}`);
} else {
// 默认最近24小时
endTime = new Date();
@@ -1471,7 +1480,8 @@ router.get('/usage-trend', authenticateAdmin, async (req, res) => {
currentHour.setMinutes(0, 0, 0);
while (currentHour <= endTime) {
// 使用时区转换后的时间来生成键
// 注意前端发送的时间已经是UTC时间不需要再次转换
// 直接从currentHour生成对应系统时区的日期和小时
const tzCurrentHour = redis.getDateInTimezone(currentHour);
const dateStr = redis.getDateStringInTimezone(currentHour);
const hour = String(tzCurrentHour.getUTCHours()).padStart(2, '0');
@@ -1545,11 +1555,11 @@ router.get('/usage-trend', authenticateAdmin, async (req, res) => {
hourCost = costResult.costs.total;
}
// 格式化时间标签
const tzDate = redis.getDateInTimezone(currentHour);
const month = String(tzDate.getUTCMonth() + 1).padStart(2, '0');
const day = String(tzDate.getUTCDate()).padStart(2, '0');
const hourStr = String(tzDate.getUTCHours()).padStart(2, '0');
// 格式化时间标签 - 使用系统时区的显示
const tzDateForLabel = redis.getDateInTimezone(currentHour);
const month = String(tzDateForLabel.getUTCMonth() + 1).padStart(2, '0');
const day = String(tzDateForLabel.getUTCDate()).padStart(2, '0');
const hourStr = String(tzDateForLabel.getUTCHours()).padStart(2, '0');
trendData.push({
// 对于小时粒度只返回hour字段不返回date字段