From 0b3cf5112bc7819b2e67817133daa7442be31cab Mon Sep 17 00:00:00 2001 From: IanShaw027 Date: Wed, 3 Dec 2025 23:37:17 -0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E4=BB=AA?= =?UTF-8?q?=E8=A1=A8=E7=9B=98=E4=BD=BF=E7=94=A8=E8=AE=B0=E5=BD=95=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E4=BB=A5=E9=81=BF=E5=85=8D=E4=B8=8EPR=20#753=E9=87=8D?= =?UTF-8?q?=E5=8F=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除了仪表盘中的使用记录展示功能,避免与PR #753的API Key详细使用记录功能重叠: - 移除DashboardView.vue中的使用记录表格UI及相关函数 - 移除dashboard.js中的/dashboard/usage-records接口 - 保留核心账户管理功能(账户过滤、限流状态、统计模态框等) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/routes/admin/dashboard.js | 138 --------- web/admin-spa/src/views/DashboardView.vue | 333 +--------------------- 2 files changed, 1 insertion(+), 470 deletions(-) diff --git a/src/routes/admin/dashboard.js b/src/routes/admin/dashboard.js index 6bcba72e..fe2cb440 100644 --- a/src/routes/admin/dashboard.js +++ b/src/routes/admin/dashboard.js @@ -704,142 +704,4 @@ router.post('/cleanup', authenticateAdmin, async (req, res) => { } }) -// 📊 获取最近的使用记录 -router.get('/dashboard/usage-records', authenticateAdmin, async (req, res) => { - try { - const { limit = 100, offset = 0 } = req.query - const limitNum = Math.min(parseInt(limit) || 100, 500) // 最多500条 - const offsetNum = Math.max(parseInt(offset) || 0, 0) - - // 获取所有API Keys - const apiKeys = await apiKeyService.getAllApiKeys() - if (!apiKeys || apiKeys.length === 0) { - return res.json({ success: true, data: { records: [], total: 0 } }) - } - - // 收集所有API Key的使用记录 - const allRecords = [] - for (const key of apiKeys) { - try { - const records = await redis.getUsageRecords(key.id, 100) // 每个key最多取100条 - if (records && records.length > 0) { - // 为每条记录添加API Key信息 - const enrichedRecords = records.map((record) => ({ - ...record, - apiKeyId: key.id, - apiKeyName: key.name || 'Unnamed Key' - })) - allRecords.push(...enrichedRecords) - } - } catch (error) { - logger.error(`Failed to get usage records for key ${key.id}:`, error) - continue - } - } - - // 按时间戳倒序排序(最新的在前) - allRecords.sort((a, b) => { - const timeA = new Date(a.timestamp).getTime() - const timeB = new Date(b.timestamp).getTime() - return timeB - timeA - }) - - // 分页 - const paginatedRecords = allRecords.slice(offsetNum, offsetNum + limitNum) - - // 获取账户名称映射 - const accountIds = [...new Set(paginatedRecords.map((r) => r.accountId).filter(Boolean))] - const accountNameMap = {} - - // 并发获取所有账户名称 - await Promise.all( - accountIds.map(async (accountId) => { - try { - // 尝试从不同类型的账户中获取 - const claudeAcc = await redis.getAccount(accountId) - if (claudeAcc && claudeAcc.name) { - accountNameMap[accountId] = claudeAcc.name - return - } - - const consoleAcc = await redis.getClaudeConsoleAccount(accountId) - if (consoleAcc && consoleAcc.name) { - accountNameMap[accountId] = consoleAcc.name - return - } - - const geminiAcc = await redis.getGeminiAccount(accountId) - if (geminiAcc && geminiAcc.name) { - accountNameMap[accountId] = geminiAcc.name - return - } - - const bedrockAcc = await redis.getBedrockAccount(accountId) - if (bedrockAcc && bedrockAcc.name) { - accountNameMap[accountId] = bedrockAcc.name - return - } - - const azureAcc = await redis.getAzureOpenaiAccount(accountId) - if (azureAcc && azureAcc.name) { - accountNameMap[accountId] = azureAcc.name - return - } - - const openaiResponsesAcc = await redis.getOpenaiResponsesAccount(accountId) - if (openaiResponsesAcc && openaiResponsesAcc.name) { - accountNameMap[accountId] = openaiResponsesAcc.name - return - } - - const droidAcc = await redis.getDroidAccount(accountId) - if (droidAcc && droidAcc.name) { - accountNameMap[accountId] = droidAcc.name - return - } - - const ccrAcc = await redis.getCcrAccount(accountId) - if (ccrAcc && ccrAcc.name) { - accountNameMap[accountId] = ccrAcc.name - return - } - - const openaiAcc = await redis.getOpenaiAccount(accountId) - if (openaiAcc && openaiAcc.name) { - accountNameMap[accountId] = openaiAcc.name - return - } - - // 降级显示ID - accountNameMap[accountId] = accountId - } catch (error) { - accountNameMap[accountId] = accountId - } - }) - ) - - // 为记录添加账户名称 - const enrichedRecords = paginatedRecords.map((record) => ({ - ...record, - accountName: record.accountId ? accountNameMap[record.accountId] || record.accountId : '-' - })) - - return res.json({ - success: true, - data: { - records: enrichedRecords, - total: allRecords.length, - limit: limitNum, - offset: offsetNum - } - }) - } catch (error) { - logger.error('❌ Failed to get usage records:', error) - return res.status(500).json({ - error: 'Failed to get usage records', - message: error.message - }) - } -}) - module.exports = router diff --git a/web/admin-spa/src/views/DashboardView.vue b/web/admin-spa/src/views/DashboardView.vue index f27c0c00..61ac8124 100644 --- a/web/admin-spa/src/views/DashboardView.vue +++ b/web/admin-spa/src/views/DashboardView.vue @@ -673,246 +673,6 @@ - - -
-
-

最近使用记录

- -
- -
-
-
-

正在加载使用记录...

-
- -
-

暂无使用记录

-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 时间 - - API Key - - 账户 - - 模型 - - 输入 - - 输出 - - 缓存创建 - - 缓存读取 - - 成本 -
- {{ formatRecordTime(record.timestamp) }} - -
- {{ record.apiKeyName }} -
-
-
- {{ record.accountName }} -
-
-
- {{ record.model }} -
-
- {{ formatNumber(record.inputTokens) }} - - {{ formatNumber(record.outputTokens) }} - - {{ formatNumber(record.cacheCreateTokens) }} - - {{ formatNumber(record.cacheReadTokens) }} - - ${{ formatCost(record.cost) }} -
- - -
- -
-
- 显示 {{ (usageRecordsCurrentPage - 1) * usageRecordsPageSize + 1 }} - - {{ Math.min(usageRecordsCurrentPage * usageRecordsPageSize, usageRecordsTotal) }} - 条,共 {{ usageRecordsTotal }} 条 -
-
- 每页显示: - -
-
- - -
- - - - - - - - - -
-
-
-
-
@@ -921,22 +681,12 @@ import { ref, onMounted, onUnmounted, watch, nextTick, computed } from 'vue' import { storeToRefs } from 'pinia' import { useDashboardStore } from '@/stores/dashboard' import { useThemeStore } from '@/stores/theme' -import { apiClient } from '@/config/api' -import { showToast } from '@/utils/toast' import Chart from 'chart.js/auto' const dashboardStore = useDashboardStore() const themeStore = useThemeStore() const { isDarkMode } = storeToRefs(themeStore) -// 使用记录相关 -const usageRecords = ref([]) -const usageRecordsLoading = ref(false) -const usageRecordsTotal = ref(0) -const usageRecordsCurrentPage = ref(1) -const usageRecordsPageSize = ref(20) -const usageRecordsPageSizeOptions = [10, 20, 50, 100] - const { dashboardData, costsData, @@ -1727,94 +1477,13 @@ watch(accountUsageTrendData, () => { nextTick(() => createAccountUsageTrendChart()) }) -// 加载使用记录 -async function loadUsageRecords() { - if (usageRecordsLoading.value) return - - try { - usageRecordsLoading.value = true - const offset = (usageRecordsCurrentPage.value - 1) * usageRecordsPageSize.value - - const response = await apiClient.get('/admin/dashboard/usage-records', { - params: { - limit: usageRecordsPageSize.value, - offset: offset - } - }) - - if (response.success && response.data) { - usageRecords.value = response.data.records || [] - usageRecordsTotal.value = response.data.total || 0 - } - } catch (error) { - console.error('Failed to load usage records:', error) - showToast('加载使用记录失败', 'error') - } finally { - usageRecordsLoading.value = false - } -} - -// 切换页码 -function handleUsageRecordsPageChange(page) { - usageRecordsCurrentPage.value = page - loadUsageRecords() -} - -// 切换每页数量 -function handleUsageRecordsPageSizeChange(size) { - usageRecordsPageSize.value = size - usageRecordsCurrentPage.value = 1 // 重置到第一页 - loadUsageRecords() -} - -// 计算总页数 -const usageRecordsTotalPages = computed(() => { - return Math.ceil(usageRecordsTotal.value / usageRecordsPageSize.value) || 1 -}) - -// 格式化记录时间 -function formatRecordTime(timestamp) { - if (!timestamp) return '-' - const date = new Date(timestamp) - const now = new Date() - const diff = now - date - - // 如果是今天 - if (diff < 86400000 && date.getDate() === now.getDate()) { - return date.toLocaleTimeString('zh-CN', { - hour: '2-digit', - minute: '2-digit', - second: '2-digit' - }) - } - - // 如果是昨天 - if (diff < 172800000 && date.getDate() === now.getDate() - 1) { - return '昨天 ' + date.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' }) - } - - // 其他日期 - return date.toLocaleString('zh-CN', { - month: '2-digit', - day: '2-digit', - hour: '2-digit', - minute: '2-digit' - }) -} - -// 格式化成本 -function formatCost(cost) { - if (!cost || cost === 0) return '0.000000' - return cost.toFixed(6) -} - // 刷新所有数据 async function refreshAllData() { if (isRefreshing.value) return isRefreshing.value = true try { - await Promise.all([loadDashboardData(), refreshChartsData(), loadUsageRecords()]) + await Promise.all([loadDashboardData(), refreshChartsData()]) } finally { isRefreshing.value = false }