fix(usage): prefer explicit video billing mode over image_count

Reuse shared getDisplayBillingMode so user usage rows with billing_mode=video
are not mislabeled as image when image_count is non-zero.
This commit is contained in:
IanShaw027
2026-08-08 09:45:12 +08:00
parent bdeb13021a
commit b7863650ec
3 changed files with 33 additions and 5 deletions
@@ -0,0 +1,27 @@
import { describe, expect, it } from 'vitest'
import {
BILLING_MODE_IMAGE,
BILLING_MODE_TOKEN,
BILLING_MODE_VIDEO,
getDisplayBillingMode,
isImageUsage
} from '../billingMode'
describe('billingMode helpers', () => {
it('prefers explicit video mode over image_count', () => {
expect(
getDisplayBillingMode({ image_count: 1, billing_mode: BILLING_MODE_VIDEO })
).toBe(BILLING_MODE_VIDEO)
expect(isImageUsage({ image_count: 1, billing_mode: BILLING_MODE_VIDEO })).toBe(false)
})
it('infers image when image_count set and mode missing', () => {
expect(getDisplayBillingMode({ image_count: 2, billing_mode: null })).toBe(BILLING_MODE_IMAGE)
})
it('keeps token mode even with image_count', () => {
expect(
getDisplayBillingMode({ image_count: 1, billing_mode: BILLING_MODE_TOKEN })
).toBe(BILLING_MODE_TOKEN)
})
})
+4
View File
@@ -32,6 +32,10 @@ export function isImageUsage(row: Pick<ImageBillingRow, 'image_count' | 'billing
}
export function getDisplayBillingMode(row: Pick<ImageBillingRow, 'billing_mode' | 'image_count'> | null | undefined): string | null | undefined {
// Explicit video/token modes always win over image_count heuristics.
if (row?.billing_mode === BILLING_MODE_VIDEO || row?.billing_mode === BILLING_MODE_TOKEN) {
return row.billing_mode
}
if ((row?.image_count ?? 0) > 0 && !row?.billing_mode) {
return BILLING_MODE_IMAGE
}
+2 -5
View File
@@ -231,7 +231,7 @@ import Icon from '@/components/icons/Icon.vue'
import UserErrorRequestsTable from '@/components/user/UserErrorRequestsTable.vue'
import { getPersistedPageSize } from '@/composables/usePersistedPageSize'
import { formatReasoningEffort } from '@/utils/format'
import { BILLING_MODE_IMAGE, getBillingModeLabel } from '@/utils/billingMode'
import { getBillingModeLabel, getDisplayBillingMode as resolveDisplayBillingMode } from '@/utils/billingMode'
import { resolveUsageRequestType, requestTypeToLegacyStream } from '@/utils/usageRequestType'
import type {
ApiKey,
@@ -605,10 +605,7 @@ const getRequestTypeExportText = (log: UsageLog): string => {
const getDisplayBillingMode = (
row: Pick<UsageLog, 'billing_mode' | 'image_count'> | null | undefined
): string | null | undefined => {
if ((row?.image_count ?? 0) > 0) return BILLING_MODE_IMAGE
return row?.billing_mode
}
): string | null | undefined => resolveDisplayBillingMode(row)
const escapeCSVValue = (value: unknown): string => {
if (value == null) return ''