fix: 修复usage页面未显示缓存写入的问题

This commit is contained in:
shaw
2025-12-19 16:57:31 +08:00
parent 078529e51e
commit 7fd94ab78b
4 changed files with 94 additions and 22 deletions

View File

@@ -266,6 +266,8 @@ export default {
sync: 'Sync',
in: 'In',
out: 'Out',
cacheRead: 'Read',
cacheWrite: 'Write',
rate: 'Rate',
original: 'Original',
billed: 'Billed',

View File

@@ -266,6 +266,8 @@ export default {
sync: '同步',
in: '输入',
out: '输出',
cacheRead: '读取',
cacheWrite: '写入',
rate: '倍率',
original: '原始',
billed: '计费',

View File

@@ -194,17 +194,40 @@
</template>
<template #cell-tokens="{ row }">
<div class="text-sm">
<div class="flex items-center gap-1">
<span class="text-gray-500 dark:text-gray-400">{{ t('usage.in') }}</span>
<span class="font-medium text-gray-900 dark:text-white">{{ row.input_tokens.toLocaleString() }}</span>
<span class="text-gray-400 dark:text-gray-500">/</span>
<span class="text-gray-500 dark:text-gray-400">{{ t('usage.out') }}</span>
<span class="font-medium text-gray-900 dark:text-white">{{ row.output_tokens.toLocaleString() }}</span>
<div class="text-sm space-y-1.5">
<!-- Input / Output Tokens -->
<div class="flex items-center gap-2">
<!-- Input -->
<div class="inline-flex items-center gap-1">
<svg class="w-3.5 h-3.5 text-emerald-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 14l-7 7m0 0l-7-7m7 7V3" />
</svg>
<span class="font-medium text-gray-900 dark:text-white">{{ row.input_tokens.toLocaleString() }}</span>
</div>
<!-- Output -->
<div class="inline-flex items-center gap-1">
<svg class="w-3.5 h-3.5 text-violet-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 10l7-7m0 0l7 7m-7-7v18" />
</svg>
<span class="font-medium text-gray-900 dark:text-white">{{ row.output_tokens.toLocaleString() }}</span>
</div>
</div>
<div v-if="row.cache_read_tokens > 0" class="flex items-center gap-1 text-blue-600 dark:text-blue-400">
<span>{{ t('dashboard.cache') }}</span>
<span class="font-medium">{{ row.cache_read_tokens.toLocaleString() }}</span>
<!-- Cache Tokens (Read + Write) -->
<div v-if="row.cache_read_tokens > 0 || row.cache_creation_tokens > 0" class="flex items-center gap-2">
<!-- Cache Read -->
<div v-if="row.cache_read_tokens > 0" class="inline-flex items-center gap-1">
<svg class="w-3.5 h-3.5 text-sky-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4" />
</svg>
<span class="text-sky-600 dark:text-sky-400 font-medium">{{ formatCacheTokens(row.cache_read_tokens) }}</span>
</div>
<!-- Cache Write -->
<div v-if="row.cache_creation_tokens > 0" class="inline-flex items-center gap-1">
<svg class="w-3.5 h-3.5 text-amber-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
</svg>
<span class="text-amber-600 dark:text-amber-400 font-medium">{{ formatCacheTokens(row.cache_creation_tokens) }}</span>
</div>
</div>
</div>
</template>
@@ -457,6 +480,16 @@ const formatTokens = (value: number): string => {
return value.toLocaleString()
}
// Compact format for cache tokens in table cells
const formatCacheTokens = (value: number): string => {
if (value >= 1_000_000) {
return `${(value / 1_000_000).toFixed(1)}M`
} else if (value >= 1_000) {
return `${(value / 1_000).toFixed(1)}K`
}
return value.toLocaleString()
}
const formatDateTime = (dateString: string): string => {
const date = new Date(dateString)
return date.toLocaleString('en-US', {
@@ -537,7 +570,7 @@ const exportToCSV = () => {
return
}
const headers = ['User', 'API Key', 'Model', 'Type', 'Input Tokens', 'Output Tokens', 'Cache Tokens', 'Total Cost', 'Billing Type', 'Duration (ms)', 'Time']
const headers = ['User', 'API Key', 'Model', 'Type', 'Input Tokens', 'Output Tokens', 'Cache Read Tokens', 'Cache Write Tokens', 'Total Cost', 'Billing Type', 'Duration (ms)', 'Time']
const rows = usageLogs.value.map(log => [
log.user?.email || '',
log.api_key?.name || '',
@@ -546,6 +579,7 @@ const exportToCSV = () => {
log.input_tokens,
log.output_tokens,
log.cache_read_tokens,
log.cache_creation_tokens,
log.total_cost.toFixed(6),
log.billing_type === 1 ? 'Subscription' : 'Balance',
log.duration_ms,

View File

@@ -137,17 +137,40 @@
</template>
<template #cell-tokens="{ row }">
<div class="text-sm">
<div class="flex items-center gap-1">
<span class="text-gray-500 dark:text-gray-400">{{ t('usage.in') }}</span>
<span class="font-medium text-gray-900 dark:text-white">{{ row.input_tokens.toLocaleString() }}</span>
<span class="text-gray-400 dark:text-gray-500">/</span>
<span class="text-gray-500 dark:text-gray-400">{{ t('usage.out') }}</span>
<span class="font-medium text-gray-900 dark:text-white">{{ row.output_tokens.toLocaleString() }}</span>
<div class="text-sm space-y-1.5">
<!-- Input / Output Tokens -->
<div class="flex items-center gap-2">
<!-- Input -->
<div class="inline-flex items-center gap-1">
<svg class="w-3.5 h-3.5 text-emerald-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 14l-7 7m0 0l-7-7m7 7V3" />
</svg>
<span class="font-medium text-gray-900 dark:text-white">{{ row.input_tokens.toLocaleString() }}</span>
</div>
<!-- Output -->
<div class="inline-flex items-center gap-1">
<svg class="w-3.5 h-3.5 text-violet-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 10l7-7m0 0l7 7m-7-7v18" />
</svg>
<span class="font-medium text-gray-900 dark:text-white">{{ row.output_tokens.toLocaleString() }}</span>
</div>
</div>
<div v-if="row.cache_read_tokens > 0" class="flex items-center gap-1 text-blue-600 dark:text-blue-400">
<span>{{ t('dashboard.cache') }}</span>
<span class="font-medium">{{ row.cache_read_tokens.toLocaleString() }}</span>
<!-- Cache Tokens (Read + Write) -->
<div v-if="row.cache_read_tokens > 0 || row.cache_creation_tokens > 0" class="flex items-center gap-2">
<!-- Cache Read -->
<div v-if="row.cache_read_tokens > 0" class="inline-flex items-center gap-1">
<svg class="w-3.5 h-3.5 text-sky-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4" />
</svg>
<span class="text-sky-600 dark:text-sky-400 font-medium">{{ formatCacheTokens(row.cache_read_tokens) }}</span>
</div>
<!-- Cache Write -->
<div v-if="row.cache_creation_tokens > 0" class="inline-flex items-center gap-1">
<svg class="w-3.5 h-3.5 text-amber-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
</svg>
<span class="text-amber-600 dark:text-amber-400 font-medium">{{ formatCacheTokens(row.cache_creation_tokens) }}</span>
</div>
</div>
</div>
</template>
@@ -331,6 +354,16 @@ const formatTokens = (value: number): string => {
return value.toLocaleString()
}
// Compact format for cache tokens in table cells
const formatCacheTokens = (value: number): string => {
if (value >= 1_000_000) {
return `${(value / 1_000_000).toFixed(1)}M`
} else if (value >= 1_000) {
return `${(value / 1_000).toFixed(1)}K`
}
return value.toLocaleString()
}
const formatDateTime = (dateString: string): string => {
const date = new Date(dateString)
return date.toLocaleString('en-US', {
@@ -415,13 +448,14 @@ const exportToCSV = () => {
return
}
const headers = ['Model', 'Type', 'Input Tokens', 'Output Tokens', 'Cache Tokens', 'Total Cost', 'Billing Type', 'First Token (ms)', 'Duration (ms)', 'Time']
const headers = ['Model', 'Type', 'Input Tokens', 'Output Tokens', 'Cache Read Tokens', 'Cache Write Tokens', 'Total Cost', 'Billing Type', 'First Token (ms)', 'Duration (ms)', 'Time']
const rows = usageLogs.value.map(log => [
log.model,
log.stream ? 'Stream' : 'Sync',
log.input_tokens,
log.output_tokens,
log.cache_read_tokens,
log.cache_creation_tokens,
log.total_cost.toFixed(6),
log.billing_type === 1 ? 'Subscription' : 'Balance',
log.first_token_ms ?? '',