Merge pull request #1666 from touwaeriol/feat/account-cost-display

feat(usage): add account cost display to admin dashboard and usage pages
This commit is contained in:
Wesley Liddick
2026-04-15 16:43:07 +08:00
committed by GitHub
16 changed files with 191 additions and 39 deletions

View File

@@ -17,7 +17,7 @@ export interface AdminUsageStatsResponse {
total_tokens: number
total_cost: number
total_actual_cost: number
total_account_cost?: number
total_account_cost: number
average_duration_ms: number
endpoints?: EndpointStat[]
upstream_endpoints?: EndpointStat[]

View File

@@ -28,17 +28,12 @@
<div class="min-w-0 flex-1">
<p class="text-xs font-medium text-gray-500">{{ t('usage.totalCost') }}</p>
<p class="text-xl font-bold text-green-600">
${{ ((stats?.total_account_cost ?? stats?.total_actual_cost) || 0).toFixed(4) }}
${{ (stats?.total_actual_cost || 0).toFixed(4) }}
</p>
<p class="text-xs text-gray-400" v-if="stats?.total_account_cost != null">
{{ t('usage.userBilled') }}:
<span class="text-gray-300">${{ (stats?.total_actual_cost || 0).toFixed(4) }}</span>
· {{ t('usage.standardCost') }}:
<span class="text-gray-300">${{ (stats?.total_cost || 0).toFixed(4) }}</span>
</p>
<p class="text-xs text-gray-400" v-else>
{{ t('usage.standardCost') }}:
<span class="line-through">${{ (stats?.total_cost || 0).toFixed(4) }}</span>
<p class="text-xs text-gray-400">
<span class="text-orange-500">{{ t('usage.accountCost') }} ${{ (stats?.total_account_cost || 0).toFixed(4) }}</span>
<span> · </span>
<span>{{ t('usage.standardCost') }} ${{ (stats?.total_cost || 0).toFixed(4) }}</span>
</p>
</div>
</div>

View File

@@ -154,7 +154,7 @@
</div>
</div>
</div>
<div v-if="row.account_rate_multiplier != null" class="mt-0.5 text-[11px] text-gray-400">
<div v-if="row.account_rate_multiplier != null" class="mt-0.5 text-[11px] text-orange-500 dark:text-orange-400">
A ${{ accountBilled(row).toFixed(6) }}
</div>
</div>

View File

@@ -45,6 +45,7 @@
<th class="pb-2 text-right">{{ t('admin.dashboard.requests') }}</th>
<th class="pb-2 text-right">{{ t('admin.dashboard.tokens') }}</th>
<th class="pb-2 text-right">{{ t('admin.dashboard.actual') }}</th>
<th class="pb-2 text-right">{{ t('admin.dashboard.accountCost') }}</th>
<th class="pb-2 text-right">{{ t('admin.dashboard.standard') }}</th>
</tr>
</thead>
@@ -75,13 +76,16 @@
<td class="py-1.5 text-right text-green-600 dark:text-green-400">
${{ formatCost(group.actual_cost) }}
</td>
<td class="py-1.5 text-right text-orange-500 dark:text-orange-400">
${{ formatCost(group.account_cost) }}
</td>
<td class="py-1.5 text-right text-gray-400 dark:text-gray-500">
${{ formatCost(group.cost) }}
</td>
</tr>
<!-- User breakdown sub-rows -->
<tr v-if="expandedKey === `group-${group.group_id}`">
<td colspan="5" class="p-0">
<td colspan="6" class="p-0">
<UserBreakdownSubTable
:items="breakdownItems"
:loading="breakdownLoading"

View File

@@ -114,6 +114,7 @@
<th class="pb-2 text-right">{{ t('admin.dashboard.requests') }}</th>
<th class="pb-2 text-right">{{ t('admin.dashboard.tokens') }}</th>
<th class="pb-2 text-right">{{ t('admin.dashboard.actual') }}</th>
<th class="pb-2 text-right">{{ t('admin.dashboard.accountCost') }}</th>
<th class="pb-2 text-right">{{ t('admin.dashboard.standard') }}</th>
</tr>
</thead>
@@ -142,12 +143,15 @@
<td class="py-1.5 text-right text-green-600 dark:text-green-400">
${{ formatCost(model.actual_cost) }}
</td>
<td class="py-1.5 text-right text-orange-500 dark:text-orange-400">
${{ formatCost(model.account_cost) }}
</td>
<td class="py-1.5 text-right text-gray-400 dark:text-gray-500">
${{ formatCost(model.cost) }}
</td>
</tr>
<tr v-if="expandedKey === `model-${model.model}`">
<td colspan="5" class="p-0">
<td colspan="6" class="p-0">
<UserBreakdownSubTable
:items="breakdownItems"
:loading="breakdownLoading"

View File

@@ -25,6 +25,9 @@
<td class="py-1 text-right text-green-600 dark:text-green-400">
${{ formatCost(user.actual_cost) }}
</td>
<td class="py-1 text-right text-orange-500 dark:text-orange-400">
${{ formatCost(user.account_cost) }}
</td>
<td class="py-1 pr-1 text-right text-gray-400 dark:text-gray-500">
${{ formatCost(user.cost) }}
</td>

View File

@@ -732,6 +732,7 @@ export default {
totalCost: 'Total Cost',
standardCost: 'Standard',
actualCost: 'Actual',
accountCost: 'Cost',
userBilled: 'User billed',
accountBilled: 'Account billed',
accountMultiplier: 'Account rate',
@@ -1039,6 +1040,7 @@ export default {
tokens: 'Tokens',
actual: 'Actual',
standard: 'Standard',
accountCost: 'Cost',
noDataAvailable: 'No data available',
recentUsage: 'Recent Usage',
viewModelDistribution: 'Model Distribution',

View File

@@ -736,6 +736,7 @@ export default {
totalCost: '总消费',
standardCost: '标准',
actualCost: '实际',
accountCost: '成本',
userBilled: '用户扣费',
accountBilled: '账号计费',
accountMultiplier: '账号倍率',
@@ -1026,6 +1027,7 @@ export default {
totalCost: '总消费',
actual: '实际',
standard: '标准',
accountCost: '成本',
todayTokens: '今日 Token',
totalTokens: '总 Token',
input: '输入',

View File

@@ -1158,6 +1158,7 @@ export interface DashboardStats {
total_tokens: number
total_cost: number // 累计标准计费
total_actual_cost: number // 累计实际扣除
total_account_cost: number // 累计账号成本
// 今日 Token 使用统计
today_requests: number
@@ -1168,6 +1169,7 @@ export interface DashboardStats {
today_tokens: number
today_cost: number // 今日标准计费
today_actual_cost: number // 今日实际扣除
today_account_cost: number // 今日账号成本
// 系统运行统计
average_duration_ms: number // 平均响应时间
@@ -1215,6 +1217,7 @@ export interface ModelStat {
total_tokens: number
cost: number // 标准计费
actual_cost: number // 实际扣除
account_cost: number // 账号成本
}
export interface EndpointStat {
@@ -1232,6 +1235,7 @@ export interface GroupStat {
total_tokens: number
cost: number // 标准计费
actual_cost: number // 实际扣除
account_cost: number // 账号成本
}
export interface UserBreakdownItem {
@@ -1241,6 +1245,7 @@ export interface UserBreakdownItem {
total_tokens: number
cost: number
actual_cost: number
account_cost: number
}
export interface UserUsageTrendPoint {

View File

@@ -112,15 +112,21 @@
</p>
<p class="text-xs">
<span
class="text-amber-600 dark:text-amber-400"
class="text-green-600 dark:text-green-400"
:title="t('admin.dashboard.actual')"
>${{ formatCost(stats.today_actual_cost) }}</span
>
<span class="text-gray-400 dark:text-gray-500"> / </span>
<span
class="text-orange-500 dark:text-orange-400"
:title="t('admin.dashboard.accountCost')"
>${{ formatCost(stats.today_account_cost) }}</span
>
<span class="text-gray-400 dark:text-gray-500"> / </span>
<span
class="text-gray-400 dark:text-gray-500"
:title="t('admin.dashboard.standard')"
>
/ ${{ formatCost(stats.today_cost) }}</span
>${{ formatCost(stats.today_cost) }}</span
>
</p>
</div>
@@ -142,15 +148,21 @@
</p>
<p class="text-xs">
<span
class="text-indigo-600 dark:text-indigo-400"
class="text-green-600 dark:text-green-400"
:title="t('admin.dashboard.actual')"
>${{ formatCost(stats.total_actual_cost) }}</span
>
<span class="text-gray-400 dark:text-gray-500"> / </span>
<span
class="text-orange-500 dark:text-orange-400"
:title="t('admin.dashboard.accountCost')"
>${{ formatCost(stats.total_account_cost) }}</span
>
<span class="text-gray-400 dark:text-gray-500"> / </span>
<span
class="text-gray-400 dark:text-gray-500"
:title="t('admin.dashboard.standard')"
>
/ ${{ formatCost(stats.total_cost) }}</span
>${{ formatCost(stats.total_cost) }}</span
>
</p>
</div>