diff --git a/frontend/src/components/usage/UsageLatencyCell.vue b/frontend/src/components/usage/UsageLatencyCell.vue index 7024ea86d..6fd1f9b9d 100644 --- a/frontend/src/components/usage/UsageLatencyCell.vue +++ b/frontend/src/components/usage/UsageLatencyCell.vue @@ -10,6 +10,14 @@ const props = defineProps<{ }>() const latencyDetails = computed(() => usageLatencyDetails(props.record)) + +const latencyTones = { + good: 'text-cp-success-text', + warn: 'text-cp-warning-text', + // 主题的 Orange 与 Warning 共用色种,混入 Error 让相邻两档可区分 + slow: 'latency-slow', + critical: 'text-cp-error-text', +} + + diff --git a/frontend/src/components/usage/shared/presenter.ts b/frontend/src/components/usage/shared/presenter.ts index 245283588..d5e25b433 100644 --- a/frontend/src/components/usage/shared/presenter.ts +++ b/frontend/src/components/usage/shared/presenter.ts @@ -224,11 +224,26 @@ export function usageLatencyDetails(record: UsageLatencyRecord) { return { upstreamDisplay, firstOutputDisplay: formatDuration(firstTokenMs), + firstOutputSeverity: latencySeverity(firstTokenMs, [10_000, 30_000, 60_000]), totalDisplay: formatDuration(totalMs), + totalSeverity: latencySeverity(totalMs, [60_000, 180_000, 300_000]), sections, } } +function latencySeverity(ms: number | null, thresholds: readonly [number, number, number]): 'good' | 'warn' | 'slow' | 'critical' | null { + if (ms === null) + return null + // 沿用 sub2api 的固定分档,边界值进入下一档,不改变请求状态 + if (ms >= thresholds[2]) + return 'critical' + if (ms >= thresholds[1]) + return 'slow' + if (ms >= thresholds[0]) + return 'warn' + return 'good' +} + export function usageBillingText(record: Pick) { return record.billing?.totalAmountDisplay || '—' }