mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-14 12:02:27 +08:00
Merge pull request #6843 from ouchihao/codex/issue-6841-usage-cost-precision
fix(usage): show eight decimal places in cost details
This commit is contained in:
@@ -410,19 +410,19 @@
|
||||
<div class="text-xs font-semibold text-gray-300 mb-1">{{ t('usage.costDetails') }}</div>
|
||||
<div v-if="tooltipData && tooltipData.input_cost > 0" class="flex items-center justify-between gap-4">
|
||||
<span class="text-gray-400">{{ t('admin.usage.inputCost') }}</span>
|
||||
<span class="font-medium text-white">${{ tooltipData.input_cost.toFixed(6) }}</span>
|
||||
<span class="font-medium text-white">${{ tooltipData.input_cost.toFixed(8) }}</span>
|
||||
</div>
|
||||
<div v-if="tooltipData && hasImageInputCost(tooltipData)" class="flex items-center justify-between gap-4">
|
||||
<span class="text-gray-400">{{ t('usage.imageInputCost') }}</span>
|
||||
<span class="font-medium text-fuchsia-300">${{ tooltipData.image_input_cost.toFixed(6) }}</span>
|
||||
<span class="font-medium text-fuchsia-300">${{ tooltipData.image_input_cost.toFixed(8) }}</span>
|
||||
</div>
|
||||
<div v-if="tooltipData && tooltipData.output_cost > 0" class="flex items-center justify-between gap-4">
|
||||
<span class="text-gray-400">{{ t('admin.usage.outputCost') }}</span>
|
||||
<span class="font-medium text-white">${{ tooltipData.output_cost.toFixed(6) }}</span>
|
||||
<span class="font-medium text-white">${{ tooltipData.output_cost.toFixed(8) }}</span>
|
||||
</div>
|
||||
<div v-if="tooltipData && hasImageOutputCost(tooltipData)" class="flex items-center justify-between gap-4">
|
||||
<span class="text-gray-400">{{ t('usage.imageOutputCost') }}</span>
|
||||
<span class="font-medium text-pink-300">${{ tooltipData.image_output_cost.toFixed(6) }}</span>
|
||||
<span class="font-medium text-pink-300">${{ tooltipData.image_output_cost.toFixed(8) }}</span>
|
||||
</div>
|
||||
<!-- Token billing: show unit prices per 1M tokens -->
|
||||
<template v-if="tooltipData && !isImageUsage(tooltipData) && (!tooltipData.billing_mode || tooltipData.billing_mode === BILLING_MODE_TOKEN)">
|
||||
@@ -470,24 +470,24 @@
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<span class="text-gray-400">{{ t('usage.imageUnitPrice') }}</span>
|
||||
<span class="font-medium text-sky-300">${{ imageUnitPrice(tooltipData).toFixed(6) }}</span>
|
||||
<span class="font-medium text-sky-300">${{ imageUnitPrice(tooltipData).toFixed(8) }}</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<span class="text-gray-400">{{ t('usage.imageTotalPrice') }}</span>
|
||||
<span class="font-medium text-white">${{ tooltipData.total_cost?.toFixed(6) || '0.000000' }}</span>
|
||||
<span class="font-medium text-white">${{ tooltipData.total_cost?.toFixed(8) || '0.00000000' }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else class="flex items-center justify-between gap-4">
|
||||
<span class="text-gray-400">{{ t('usage.unitPrice') }}</span>
|
||||
<span class="font-medium text-sky-300">${{ tooltipData?.total_cost?.toFixed(6) || '0.000000' }}</span>
|
||||
<span class="font-medium text-sky-300">${{ tooltipData?.total_cost?.toFixed(8) || '0.00000000' }}</span>
|
||||
</div>
|
||||
<div v-if="tooltipData && tooltipData.cache_creation_cost > 0" class="flex items-center justify-between gap-4">
|
||||
<span class="text-gray-400">{{ t('admin.usage.cacheCreationCost') }}</span>
|
||||
<span class="font-medium text-white">${{ tooltipData.cache_creation_cost.toFixed(6) }}</span>
|
||||
<span class="font-medium text-white">${{ tooltipData.cache_creation_cost.toFixed(8) }}</span>
|
||||
</div>
|
||||
<div v-if="tooltipData && tooltipData.cache_read_cost > 0" class="flex items-center justify-between gap-4">
|
||||
<span class="text-gray-400">{{ t('admin.usage.cacheReadCost') }}</span>
|
||||
<span class="font-medium text-white">${{ tooltipData.cache_read_cost.toFixed(6) }}</span>
|
||||
<span class="font-medium text-white">${{ tooltipData.cache_read_cost.toFixed(8) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Rate and Summary -->
|
||||
@@ -501,11 +501,11 @@
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-6">
|
||||
<span class="text-gray-400">{{ t('usage.original') }}</span>
|
||||
<span class="font-medium text-white">${{ tooltipData?.total_cost?.toFixed(6) || '0.000000' }}</span>
|
||||
<span class="font-medium text-white">${{ tooltipData?.total_cost?.toFixed(8) || '0.00000000' }}</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-6">
|
||||
<span class="text-gray-400">{{ t('usage.userBilled') }}</span>
|
||||
<span class="font-semibold text-green-400">${{ tooltipData?.actual_cost?.toFixed(6) || '0.000000' }}</span>
|
||||
<span class="font-semibold text-green-400">${{ tooltipData?.actual_cost?.toFixed(8) || '0.00000000' }}</span>
|
||||
</div>
|
||||
<!-- Account billing (separated from user billing) -->
|
||||
<template v-if="showAccountBilling">
|
||||
@@ -520,7 +520,7 @@
|
||||
total_cost: tooltipData?.total_cost,
|
||||
account_stats_cost: tooltipData?.account_stats_cost,
|
||||
account_rate_multiplier: tooltipData?.account_rate_multiplier,
|
||||
}).toFixed(6) }}
|
||||
}).toFixed(8) }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -275,6 +275,53 @@ describe('admin UsageTable tooltip', () => {
|
||||
expect(text).toContain('$0.069568')
|
||||
})
|
||||
|
||||
it.each(['token', 'image', 'per_request'])('keeps eight decimal places in %s cost details', async (billingMode) => {
|
||||
const row = {
|
||||
...baseImageRow,
|
||||
billing_mode: billingMode,
|
||||
image_count: billingMode === 'image' ? 2 : 0,
|
||||
input_cost: 0.00000001,
|
||||
image_input_cost: 0.00000002,
|
||||
output_cost: 0.00000003,
|
||||
image_output_cost: 0.00000004,
|
||||
cache_creation_cost: 0.00000005,
|
||||
cache_read_cost: 0.00000006,
|
||||
total_cost: 0.00000022,
|
||||
actual_cost: 0.00000042,
|
||||
account_stats_cost: 0.00000012,
|
||||
account_rate_multiplier: 1.5,
|
||||
}
|
||||
const wrapper = mount(UsageTable, {
|
||||
props: { data: [row], loading: false, columns: [] },
|
||||
global: { stubs: { DataTable: DataTableStub, EmptyState: true, Icon: true, Teleport: true } },
|
||||
})
|
||||
const triggers = wrapper.findAll('.group.relative')
|
||||
await triggers[triggers.length - 1].trigger('mouseenter')
|
||||
const amounts = wrapper.get('.fixed').findAll('span').map(span => span.text())
|
||||
expect(amounts).toEqual(expect.arrayContaining([
|
||||
'$0.00000001', '$0.00000002', '$0.00000003', '$0.00000004',
|
||||
'$0.00000005', '$0.00000006', '$0.00000022', '$0.00000042', '$0.00000018',
|
||||
]))
|
||||
if (billingMode === 'image') expect(amounts).toContain('$0.00000011')
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('uses eight decimal places for missing cost values', async () => {
|
||||
const wrapper = mount(UsageTable, {
|
||||
props: {
|
||||
data: [{ ...baseImageRow, billing_mode: 'per_request', image_count: 0, total_cost: undefined, actual_cost: undefined }],
|
||||
loading: false,
|
||||
columns: [],
|
||||
},
|
||||
global: { stubs: { DataTable: DataTableStub, EmptyState: true, Icon: true, Teleport: true } },
|
||||
})
|
||||
const triggers = wrapper.findAll('.group.relative')
|
||||
await triggers[triggers.length - 1].trigger('mouseenter')
|
||||
const amounts = wrapper.get('.fixed').findAll('span').map(span => span.text()).filter(text => text.startsWith('$'))
|
||||
expect(amounts).toEqual(['$0.00000000', '$0.00000000', '$0.00000000', '$0.00000000'])
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('shows requested and upstream models separately for admin rows', () => {
|
||||
const row = {
|
||||
request_id: 'req-admin-model-1',
|
||||
|
||||
Reference in New Issue
Block a user