fix: hide Grok prepaid and used/limit when they are empty

Skip the prepaid chip without a positive balance, and skip used/limit when monthly limit is 0.
This commit is contained in:
IanShaw027
2026-08-18 14:55:08 +08:00
parent 269fbcac0e
commit fd42d3722d
2 changed files with 109 additions and 14 deletions
@@ -397,12 +397,16 @@
class="flex flex-wrap items-center gap-1 text-[10px] text-gray-500 dark:text-gray-400"
>
<span
v-if="grokPrepaidMoneyLine.showPrepaid"
class="rounded bg-emerald-50 px-1 py-0.5 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-300"
:title="t('admin.accounts.usageWindow.grokPrepaid')"
>
{{ t('admin.accounts.usageWindow.grokPrepaid') }} ${{ grokPrepaidMoneyLine.prepaid }}
</span>
<span :title="t('admin.accounts.usageWindow.grokMonthlyLimit')">
<span
v-if="grokPrepaidMoneyLine.showUsedLimit"
:title="t('admin.accounts.usageWindow.grokMonthlyLimit')"
>
{{ t('admin.accounts.usageWindow.grokUsed') }}
{{ grokPrepaidMoneyLine.used }}/{{ grokPrepaidMoneyLine.limit }}
</span>
@@ -1164,30 +1168,33 @@ const formatGrokMoney = (value?: number | null) => {
if (value >= 10) return value.toFixed(1)
return value.toFixed(2)
}
// Prepaid money line for paid Grok: show when prepaid_balance is present.
// Monthly used/limit numbers are optional context; primary progress is the 30d bar.
// Prepaid chip only when there is a positive prepaid balance.
// Used/limit only when monthly limit is a positive number (0 means unlimited / unset).
const grokPrepaidMoneyLine = computed(() => {
const billing = grokBilling.value
if (!billing) return null
const prepaid = billing.prepaid_balance
// "只针对预付": only render when prepaid field exists (including $0.00).
if (prepaid == null || !Number.isFinite(prepaid)) return null
const showPrepaid = prepaid != null && Number.isFinite(prepaid) && prepaid > 0
const limitRaw =
billing.monthly_limit != null
? billing.monthly_limit
: billing.monthly_limit_cents != null
? billing.monthly_limit_cents / 100
: null
const showUsedLimit = limitRaw != null && Number.isFinite(limitRaw) && limitRaw > 0
if (!showPrepaid && !showUsedLimit) return null
const used =
billing.monthly_used != null
? billing.monthly_used
: billing.used_cents != null
? billing.used_cents / 100
: 0
const limit =
billing.monthly_limit != null
? billing.monthly_limit
: billing.monthly_limit_cents != null
? billing.monthly_limit_cents / 100
: 0
return {
prepaid: formatGrokMoney(prepaid),
used: formatGrokMoney(used),
limit: formatGrokMoney(limit)
showPrepaid,
showUsedLimit,
prepaid: showPrepaid ? formatGrokMoney(prepaid) : null,
used: showUsedLimit ? formatGrokMoney(used) : null,
limit: showUsedLimit ? formatGrokMoney(limitRaw) : null
}
})
const grokPlanLabelIsFree = (value: string) => value.includes('free') || value.includes('basic')
@@ -1168,6 +1168,94 @@ describe('AccountUsageCell', () => {
expect(wrapper.text()).toContain('30d|8|4400000')
})
it('Grok paid hides zero prepaid and hides used/limit when monthly limit is 0', async () => {
getUsage.mockResolvedValue({
subscription_tier: 'SuperGrok',
grok_billing: {
period_type: 'weekly',
usage_percent: 20,
prepaid_balance: 0,
monthly_limit: 0,
monthly_used: 3.5,
plan: 'SuperGrok'
}
})
const wrapper = mount(AccountUsageCell, {
props: {
account: makeAccount({ id: 4413, platform: 'grok', type: 'oauth', extra: {} })
},
global: {
stubs: {
UsageProgressBar: true,
AccountQuotaInfo: true
}
}
})
await flushPromises()
expect(wrapper.text()).not.toContain('admin.accounts.usageWindow.grokPrepaid')
expect(wrapper.text()).not.toContain('admin.accounts.usageWindow.grokUsed')
expect(wrapper.text()).not.toContain('3.5/0')
})
it('Grok paid shows used/limit without prepaid, and prepaid without a zero monthly limit', async () => {
getUsage.mockResolvedValueOnce({
subscription_tier: 'SuperGrok',
grok_billing: {
period_type: 'weekly',
usage_percent: 20,
monthly_limit: 25,
monthly_used: 3.5,
plan: 'SuperGrok'
}
})
const usedOnly = mount(AccountUsageCell, {
props: {
account: makeAccount({ id: 4414, platform: 'grok', type: 'oauth', extra: {} })
},
global: {
stubs: {
UsageProgressBar: true,
AccountQuotaInfo: true
}
}
})
await flushPromises()
expect(usedOnly.text()).not.toContain('admin.accounts.usageWindow.grokPrepaid')
expect(usedOnly.text()).toContain('admin.accounts.usageWindow.grokUsed')
expect(usedOnly.text()).toContain('3.50/25.0')
getUsage.mockResolvedValueOnce({
subscription_tier: 'SuperGrok Heavy',
grok_billing: {
period_type: 'weekly',
usage_percent: 20,
prepaid_balance: 12.5,
monthly_limit: 0,
monthly_used: 8,
plan: 'SuperGrok Heavy'
}
})
const prepaidOnly = mount(AccountUsageCell, {
props: {
account: makeAccount({ id: 4415, platform: 'grok', type: 'oauth', extra: {} })
},
global: {
stubs: {
UsageProgressBar: true,
AccountQuotaInfo: true
}
}
})
await flushPromises()
expect(prepaidOnly.text()).toContain('admin.accounts.usageWindow.grokPrepaid')
expect(prepaidOnly.text()).toContain('$12.5')
expect(prepaidOnly.text()).not.toContain('admin.accounts.usageWindow.grokUsed')
expect(prepaidOnly.text()).not.toContain('8.00/0')
})
it('Key 账号在 today stats loading 时显示骨架屏', async () => {
const wrapper = mount(AccountUsageCell, {
props: {