mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-09-06 17:46:23 +00:00
feat(stat): enhance log stat cards with compact number formatting and improved layout
This commit is contained in:
@@ -18,8 +18,9 @@ For commercial licensing, please contact support@quantumnous.com
|
|||||||
*/
|
*/
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useAuthStore } from '@/stores/auth-store'
|
import { useAuthStore } from '@/stores/auth-store'
|
||||||
import { formatNumber, formatQuota } from '@/lib/format'
|
import { formatCompactNumber, formatNumber, formatQuota } from '@/lib/format'
|
||||||
import { computeTimeRange } from '@/lib/time'
|
import { computeTimeRange } from '@/lib/time'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
import { Skeleton } from '@/components/ui/skeleton'
|
import { Skeleton } from '@/components/ui/skeleton'
|
||||||
import { getUserQuotaDates } from '@/features/dashboard/api'
|
import { getUserQuotaDates } from '@/features/dashboard/api'
|
||||||
import { useModelStatCardsConfig } from '@/features/dashboard/hooks/use-dashboard-config'
|
import { useModelStatCardsConfig } from '@/features/dashboard/hooks/use-dashboard-config'
|
||||||
@@ -38,6 +39,21 @@ interface LogStatCardsProps {
|
|||||||
onDataUpdate?: (data: QuotaDataItem[], loading: boolean) => void
|
onDataUpdate?: (data: QuotaDataItem[], loading: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MAX_INLINE_STAT_CHARS = 9
|
||||||
|
|
||||||
|
function formatStatNumber(value: number) {
|
||||||
|
const fullValue = formatNumber(value)
|
||||||
|
const displayValue =
|
||||||
|
fullValue.length > MAX_INLINE_STAT_CHARS
|
||||||
|
? formatCompactNumber(value)
|
||||||
|
: fullValue
|
||||||
|
|
||||||
|
return {
|
||||||
|
displayValue,
|
||||||
|
fullValue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function LogStatCards(props: LogStatCardsProps) {
|
export function LogStatCards(props: LogStatCardsProps) {
|
||||||
const statCardsConfig = useModelStatCardsConfig()
|
const statCardsConfig = useModelStatCardsConfig()
|
||||||
const user = useAuthStore((state) => state.auth.user)
|
const user = useAuthStore((state) => state.auth.user)
|
||||||
@@ -100,27 +116,41 @@ export function LogStatCards(props: LogStatCardsProps) {
|
|||||||
tpm: stats?.totalTokens ?? 0,
|
tpm: stats?.totalTokens ?? 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
const items = statCardsConfig.map((config) => ({
|
const items = statCardsConfig.map((config) => {
|
||||||
title: config.title,
|
const rawValue = config.getValue(adaptedStats, timeRangeMinutes)
|
||||||
value:
|
const formatted =
|
||||||
config.key === 'quota'
|
config.key === 'quota'
|
||||||
? formatQuota(config.getValue(adaptedStats, timeRangeMinutes))
|
? {
|
||||||
: formatNumber(config.getValue(adaptedStats, timeRangeMinutes)),
|
displayValue: formatQuota(rawValue),
|
||||||
desc: config.description,
|
fullValue: formatQuota(rawValue),
|
||||||
icon: config.icon,
|
}
|
||||||
}))
|
: formatStatNumber(rawValue)
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: config.title,
|
||||||
|
value: formatted.displayValue,
|
||||||
|
fullValue: formatted.fullValue,
|
||||||
|
desc: config.description,
|
||||||
|
icon: config.icon,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='overflow-hidden rounded-lg border'>
|
<div className='overflow-hidden rounded-lg border'>
|
||||||
<div className='divide-border/60 grid grid-cols-2 divide-x sm:grid-cols-3 lg:grid-cols-5'>
|
<div className='divide-border/60 grid min-w-0 grid-cols-2 divide-x sm:grid-cols-3 lg:grid-cols-5'>
|
||||||
{items.map((it, idx) => {
|
{items.map((it, idx) => {
|
||||||
const Icon = it.icon
|
const Icon = it.icon
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={it.title}
|
key={it.title}
|
||||||
className={`px-3 py-2.5 sm:px-5 sm:py-4 ${idx === items.length - 1 && items.length % 2 !== 0 ? 'col-span-2 sm:col-span-1' : ''}`}
|
className={cn(
|
||||||
|
'min-w-0 px-3 py-2.5 sm:px-5 sm:py-4',
|
||||||
|
idx === items.length - 1 &&
|
||||||
|
items.length % 2 !== 0 &&
|
||||||
|
'col-span-2 sm:col-span-1'
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<div className='flex items-center gap-2'>
|
<div className='flex min-w-0 items-center gap-2'>
|
||||||
<Icon className='text-muted-foreground/60 size-3.5 shrink-0' />
|
<Icon className='text-muted-foreground/60 size-3.5 shrink-0' />
|
||||||
<div className='text-muted-foreground truncate text-xs font-medium tracking-wider uppercase'>
|
<div className='text-muted-foreground truncate text-xs font-medium tracking-wider uppercase'>
|
||||||
{it.title}
|
{it.title}
|
||||||
@@ -128,7 +158,7 @@ export function LogStatCards(props: LogStatCardsProps) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className='mt-2 space-y-1.5'>
|
<div className='mt-2 flex flex-col gap-1.5'>
|
||||||
<Skeleton className='h-7 w-20' />
|
<Skeleton className='h-7 w-20' />
|
||||||
<Skeleton className='h-3.5 w-28' />
|
<Skeleton className='h-3.5 w-28' />
|
||||||
</div>
|
</div>
|
||||||
@@ -143,7 +173,10 @@ export function LogStatCards(props: LogStatCardsProps) {
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className='text-foreground mt-1.5 font-mono text-lg font-bold tracking-tight tabular-nums sm:mt-2 sm:text-2xl'>
|
<div
|
||||||
|
className='text-foreground mt-1.5 max-w-full truncate font-mono text-lg font-bold tracking-tight tabular-nums sm:mt-2 sm:text-2xl'
|
||||||
|
title={it.fullValue}
|
||||||
|
>
|
||||||
{it.value}
|
{it.value}
|
||||||
</div>
|
</div>
|
||||||
<div className='text-muted-foreground/60 mt-1 hidden text-xs md:block'>
|
<div className='text-muted-foreground/60 mt-1 hidden text-xs md:block'>
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ function formatCompactLatency(ms: number): string {
|
|||||||
|
|
||||||
function formatCompactThroughput(tps: number): string {
|
function formatCompactThroughput(tps: number): string {
|
||||||
if (!Number.isFinite(tps) || tps <= 0) return '—'
|
if (!Number.isFinite(tps) || tps <= 0) return '—'
|
||||||
if (tps >= 1_000) return `${formatCompactNumber(tps / 1_000)}Ktps`
|
if (tps >= 1_000) return `${formatCompactNumber(tps / 1_000)}Kt`
|
||||||
return `${formatCompactNumber(tps)}tps`
|
return `${formatCompactNumber(tps)}t`
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ModelPerfBadge = memo(function ModelPerfBadge(
|
export const ModelPerfBadge = memo(function ModelPerfBadge(
|
||||||
|
|||||||
Reference in New Issue
Block a user