mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 00:53:33 +00:00
feat: API Keys页面添加全部时间选项和UI改进
- 添加"全部时间"选项到时间范围下拉菜单,可查看所有历史使用数据 - 统一费用显示列,根据选择的时间范围动态显示对应标签 - 支持自定义日期范围查询(最多31天) - 优化日期选择器高度与其他控件对齐(38px) - 使用更通用的标签名称(累计费用、总费用等) - 移除调试console.log语句 后端改进: - 添加自定义日期范围查询支持 - 日期范围验证和31天限制 - 支持all时间范围查询 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -122,7 +122,7 @@ router.get('/api-keys/:keyId/cost-debug', authenticateAdmin, async (req, res) =>
|
||||
// 获取所有API Keys
|
||||
router.get('/api-keys', authenticateAdmin, async (req, res) => {
|
||||
try {
|
||||
const { timeRange = 'all' } = req.query // all, 7days, monthly
|
||||
const { timeRange = 'all', startDate, endDate } = req.query // all, 7days, monthly, custom
|
||||
const apiKeys = await apiKeyService.getAllApiKeys()
|
||||
|
||||
// 获取用户服务来补充owner信息
|
||||
@@ -132,7 +132,32 @@ router.get('/api-keys', authenticateAdmin, async (req, res) => {
|
||||
const now = new Date()
|
||||
const searchPatterns = []
|
||||
|
||||
if (timeRange === 'today') {
|
||||
if (timeRange === 'custom' && startDate && endDate) {
|
||||
// 自定义日期范围
|
||||
const redisClient = require('../models/redis')
|
||||
const start = new Date(startDate)
|
||||
const end = new Date(endDate)
|
||||
|
||||
// 确保日期范围有效
|
||||
if (start > end) {
|
||||
return res.status(400).json({ error: 'Start date must be before or equal to end date' })
|
||||
}
|
||||
|
||||
// 限制最大范围为31天
|
||||
const daysDiff = Math.ceil((end - start) / (1000 * 60 * 60 * 24)) + 1
|
||||
if (daysDiff > 31) {
|
||||
return res.status(400).json({ error: 'Date range cannot exceed 31 days' })
|
||||
}
|
||||
|
||||
// 生成日期范围内每天的搜索模式
|
||||
const currentDate = new Date(start)
|
||||
while (currentDate <= end) {
|
||||
const tzDate = redisClient.getDateInTimezone(currentDate)
|
||||
const dateStr = `${tzDate.getUTCFullYear()}-${String(tzDate.getUTCMonth() + 1).padStart(2, '0')}-${String(tzDate.getUTCDate()).padStart(2, '0')}`
|
||||
searchPatterns.push(`usage:daily:*:${dateStr}`)
|
||||
currentDate.setDate(currentDate.getDate() + 1)
|
||||
}
|
||||
} else if (timeRange === 'today') {
|
||||
// 今日 - 使用时区日期
|
||||
const redisClient = require('../models/redis')
|
||||
const tzDate = redisClient.getDateInTimezone(now)
|
||||
@@ -233,7 +258,7 @@ router.get('/api-keys', authenticateAdmin, async (req, res) => {
|
||||
apiKey.usage.total.formattedCost = CostCalculator.formatCost(totalCost)
|
||||
}
|
||||
} else {
|
||||
// 7天或本月:重新计算统计数据
|
||||
// 7天、本月或自定义日期范围:重新计算统计数据
|
||||
const tempUsage = {
|
||||
requests: 0,
|
||||
tokens: 0,
|
||||
@@ -274,12 +299,28 @@ router.get('/api-keys', authenticateAdmin, async (req, res) => {
|
||||
const tzDate = redisClient.getDateInTimezone(now)
|
||||
const tzMonth = `${tzDate.getUTCFullYear()}-${String(tzDate.getUTCMonth() + 1).padStart(2, '0')}`
|
||||
|
||||
const modelKeys =
|
||||
timeRange === 'today'
|
||||
? await client.keys(`usage:${apiKey.id}:model:daily:*:${tzToday}`)
|
||||
: timeRange === '7days'
|
||||
? await client.keys(`usage:${apiKey.id}:model:daily:*:*`)
|
||||
: await client.keys(`usage:${apiKey.id}:model:monthly:*:${tzMonth}`)
|
||||
let modelKeys = []
|
||||
if (timeRange === 'custom' && startDate && endDate) {
|
||||
// 自定义日期范围:获取范围内所有日期的模型统计
|
||||
const start = new Date(startDate)
|
||||
const end = new Date(endDate)
|
||||
const currentDate = new Date(start)
|
||||
|
||||
while (currentDate <= end) {
|
||||
const tzDateForKey = redisClient.getDateInTimezone(currentDate)
|
||||
const dateStr = `${tzDateForKey.getUTCFullYear()}-${String(tzDateForKey.getUTCMonth() + 1).padStart(2, '0')}-${String(tzDateForKey.getUTCDate()).padStart(2, '0')}`
|
||||
const dayKeys = await client.keys(`usage:${apiKey.id}:model:daily:*:${dateStr}`)
|
||||
modelKeys = modelKeys.concat(dayKeys)
|
||||
currentDate.setDate(currentDate.getDate() + 1)
|
||||
}
|
||||
} else {
|
||||
modelKeys =
|
||||
timeRange === 'today'
|
||||
? await client.keys(`usage:${apiKey.id}:model:daily:*:${tzToday}`)
|
||||
: timeRange === '7days'
|
||||
? await client.keys(`usage:${apiKey.id}:model:daily:*:*`)
|
||||
: await client.keys(`usage:${apiKey.id}:model:monthly:*:${tzMonth}`)
|
||||
}
|
||||
|
||||
const modelStatsMap = new Map()
|
||||
|
||||
@@ -295,8 +336,8 @@ router.get('/api-keys', authenticateAdmin, async (req, res) => {
|
||||
continue
|
||||
}
|
||||
}
|
||||
} else if (timeRange === 'today') {
|
||||
// today选项已经在查询时过滤了,不需要额外处理
|
||||
} else if (timeRange === 'today' || timeRange === 'custom') {
|
||||
// today和custom选项已经在查询时过滤了,不需要额外处理
|
||||
}
|
||||
|
||||
const modelMatch = key.match(
|
||||
|
||||
Reference in New Issue
Block a user