refactor(web): consolidate the font-weight scale to four semantic tiers

Replace the nine ad-hoc arbitrary font weights (620-820, 208 usages) with a four-tier scale: font-emphasis (650) and font-heavy (760) as new theme tokens, plus the standard font-bold (700) and font-extrabold (800). Every merge moves a weight by at most 30 units, below the perceptible threshold for UI text sizes. The SystemUpdateModal release-notes scoped styles reference the same tokens. Arbitrary font-[N] classes are now zero across the codebase; the scale is documented in the theme block.

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
zyycn
2026-07-26 22:21:36 +08:00
co-authored by Claude
parent 69f73e8c5d
commit ae46d89de6
57 changed files with 212 additions and 208 deletions
@@ -47,7 +47,7 @@ const authenticationLabel = computed(() => {
>
<Openai v-if="normalizedProvider === 'openai'" :class="iconClass" aria-hidden="true" />
<Xai v-else-if="normalizedProvider === 'xai'" :class="iconClass" aria-hidden="true" />
<span v-else class="text-[10px] font-[760] text-(--cp-text-muted)">?</span>
<span v-else class="text-[10px] font-heavy text-(--cp-text-muted)">?</span>
</span>
<span
@@ -66,7 +66,7 @@ const authenticationLabel = computed(() => {
:class="iconClass"
aria-hidden="true"
/>
<span v-else class="text-[10px] font-[760] text-(--cp-text-muted)">?</span>
<span v-else class="text-[10px] font-heavy text-(--cp-text-muted)">?</span>
</span>
<span class="sr-only">
+1 -1
View File
@@ -70,7 +70,7 @@ const loadingIconSize: Record<ButtonSize, number> = {
}
const classes = computed(() => [
'inline-flex items-center justify-center border-0 font-[720] leading-[1.15] transition-[background-color,box-shadow,color,opacity,transform] duration-150 cursor-pointer outline-none motion-safe:active:translate-y-px motion-safe:active:scale-[0.985]',
'inline-flex items-center justify-center border-0 font-bold leading-[1.15] transition-[background-color,box-shadow,color,opacity,transform] duration-150 cursor-pointer outline-none motion-safe:active:translate-y-px motion-safe:active:scale-[0.985]',
props.iconOnly ? iconOnlySizeClasses[props.size] : sizeClasses[props.size],
props.iconOnly ? '' : 'rounded-(--cp-button-radius-base)',
'focus-visible:ring-2 focus-visible:ring-(--cp-info-border) focus-visible:ring-offset-2 focus-visible:ring-offset-(--cp-bg-surface)',
+2 -2
View File
@@ -82,7 +82,7 @@ const managedHeaderLayoutClasses = computed(() => {
<div class="min-w-0 pt-0.5">
<h2
v-if="props.title || $slots.title"
class="m-0 text-xl leading-[1.15] font-[760] text-(--cp-text-primary)"
class="m-0 text-xl leading-[1.15] font-heavy text-(--cp-text-primary)"
>
<slot name="title">
{{ props.title }}
@@ -90,7 +90,7 @@ const managedHeaderLayoutClasses = computed(() => {
</h2>
<p
v-if="props.description || $slots.description"
class="mt-1.75 mb-0 text-[13px] leading-[1.15] font-[650] text-(--cp-text-secondary)"
class="mt-1.75 mb-0 text-[13px] leading-[1.15] font-emphasis text-(--cp-text-secondary)"
>
<slot name="description">
{{ props.description }}
@@ -40,7 +40,7 @@ function toggle() {
<template>
<button
type="button"
class="group inline-flex min-h-4 min-w-4 appearance-none items-center gap-2.5 border-0 bg-transparent p-0 text-[13px] leading-none font-[650] transition-opacity outline-none focus-visible:ring-2 focus-visible:ring-(--cp-info-border) focus-visible:ring-offset-2 focus-visible:ring-offset-(--cp-bg-surface)"
class="group inline-flex min-h-4 min-w-4 appearance-none items-center gap-2.5 border-0 bg-transparent p-0 text-[13px] leading-none font-emphasis transition-opacity outline-none focus-visible:ring-2 focus-visible:ring-(--cp-info-border) focus-visible:ring-offset-2 focus-visible:ring-offset-(--cp-bg-surface)"
:class="disabled ? 'cursor-not-allowed opacity-55' : 'cursor-pointer'"
role="checkbox"
:aria-checked="indeterminate ? 'mixed' : model"
@@ -63,7 +63,7 @@ function handleConfirm() {
>
<div
v-if="$slots.default"
class="text-[14px] leading-[1.55] font-[620] text-(--cp-text-secondary)"
class="text-[14px] leading-[1.55] font-emphasis text-(--cp-text-secondary)"
>
<slot />
</div>
+1 -1
View File
@@ -29,7 +29,7 @@ const resolvedIcon = computed(() => props.icon ?? Inbox)
>
<component :is="resolvedIcon" :size="compact ? 16 : 18" />
</span>
<p class="m-0 text-[13px] leading-[1.15] font-[760] text-(--cp-text-primary)">
<p class="m-0 text-[13px] leading-[1.15] font-heavy text-(--cp-text-primary)">
{{ resolvedTitle }}
</p>
<p
@@ -40,14 +40,14 @@ withDefaults(
</div>
<p
v-if="description"
class="mt-0 mb-2 text-xs leading-[1.35] font-[650] text-(--cp-text-muted)"
class="mt-0 mb-2 text-xs leading-[1.35] font-emphasis text-(--cp-text-muted)"
>
{{ description }}
</p>
<div class="min-w-0">
<slot />
</div>
<p v-if="error" class="mt-2 mb-0 text-xs leading-[1.35] font-[650] text-(--cp-danger-text)">
<p v-if="error" class="mt-2 mb-0 text-xs leading-[1.35] font-emphasis text-(--cp-danger-text)">
{{ error }}
</p>
</div>
+2 -2
View File
@@ -52,7 +52,7 @@ const iconClasses = computed(() => [
])
const inputClasses = computed(() => [
'h-full min-w-0 flex-1 border-0 bg-transparent text-[13px] font-[650] leading-[1.15] outline-0',
'h-full min-w-0 flex-1 border-0 bg-transparent text-[13px] font-emphasis leading-[1.15] outline-0',
'placeholder:text-(--cp-text-muted) disabled:cursor-not-allowed disabled:text-(--cp-disabled-text)',
props.error
? 'text-(--cp-danger-text)'
@@ -85,7 +85,7 @@ const inputClasses = computed(() => [
<slot name="suffix" />
</span>
</span>
<span v-if="error" class="text-xs font-[650] leading-[1.15] text-(--cp-danger-text)">{{
<span v-if="error" class="text-xs font-emphasis leading-[1.15] text-(--cp-danger-text)">{{
error
}}</span>
</div>
+1 -1
View File
@@ -212,7 +212,7 @@ onBeforeUnmount(() => {
</slot>
</span>
<div class="min-w-0" :class="variant === 'default' ? 'col-span-2' : ''">
<h2 class="m-0 text-lg leading-[1.15] font-[760] text-(--cp-text-primary)">
<h2 class="m-0 text-lg leading-[1.15] font-heavy text-(--cp-text-primary)">
{{ title }}
</h2>
<p
@@ -64,7 +64,7 @@ function selectOption(value: string) {
<button
v-for="option in options"
:key="option.value"
class="relative z-10 inline-flex min-w-0 items-center justify-center gap-1.5 rounded-(--cp-input-radius-base) border-0 bg-transparent px-3 text-xs leading-none font-[650] transition-colors duration-150 outline-none focus-visible:ring-2 focus-visible:ring-(--cp-info-border)"
class="relative z-10 inline-flex min-w-0 items-center justify-center gap-1.5 rounded-(--cp-input-radius-base) border-0 bg-transparent px-3 text-xs leading-none font-emphasis transition-colors duration-150 outline-none focus-visible:ring-2 focus-visible:ring-(--cp-info-border)"
:class="[
size === 'input' ? 'h-8' : 'h-7',
model === option.value
+3 -3
View File
@@ -70,7 +70,7 @@ const sizeConfig: Record<
const selectedOption = computed(() => props.options.find(option => option.value === model.value))
const triggerClasses = computed(() => [
'relative inline-flex w-full min-w-0 items-center gap-2 overflow-visible border-0 text-left font-[650] leading-none shadow-(--cp-shadow-input) outline-none transition-[background-color,box-shadow,color] duration-[160ms]',
'relative inline-flex w-full min-w-0 items-center gap-2 overflow-visible border-0 text-left font-emphasis leading-none shadow-(--cp-shadow-input) outline-none transition-[background-color,box-shadow,color] duration-[160ms]',
sizeConfig[props.size].trigger,
props.disabled
? 'cursor-not-allowed bg-(--cp-disabled-bg) text-(--cp-disabled-text) shadow-none'
@@ -228,7 +228,7 @@ function handleTriggerKeydown(event: KeyboardEvent) {
function optionClasses(option: SelectOption, index: number) {
return [
'flex w-full items-center gap-2 rounded-(--cp-input-radius-small) border-0 px-3 text-left font-[650] leading-none outline-none transition-colors',
'flex w-full items-center gap-2 rounded-(--cp-input-radius-small) border-0 px-3 text-left font-emphasis leading-none outline-none transition-colors',
sizeConfig[props.size].option,
option.disabled
? 'cursor-not-allowed bg-transparent text-(--cp-disabled-text)'
@@ -315,7 +315,7 @@ useEventListener(window, 'scroll', updatePopoverPositionThrottled, { capture: tr
>
<div
v-if="options.length === 0"
class="flex h-8.5 items-center rounded-(--cp-input-radius-small) px-3 text-[13px] leading-none font-[650] text-(--cp-text-muted)"
class="flex h-8.5 items-center rounded-(--cp-input-radius-small) px-3 text-[13px] leading-none font-emphasis text-(--cp-text-muted)"
>
{{ emptyText }}
</div>
@@ -60,7 +60,7 @@ function paginationButtonClass(disabled: boolean) {
function paginationPageClass(page: number) {
return [
'inline-flex size-8 items-center justify-center rounded-(--cp-input-radius-base) border-0 text-xs font-[720] leading-none transition-colors duration-150 outline-none',
'inline-flex size-8 items-center justify-center rounded-(--cp-input-radius-base) border-0 text-xs font-bold leading-none transition-colors duration-150 outline-none',
page === currentPage.value
? 'cursor-default bg-(--cp-info) text-(--cp-info-on)'
: 'cursor-pointer bg-(--cp-bg-subtle) text-(--cp-text-primary) hover:bg-(--cp-default-bg-hover) focus-visible:ring-2 focus-visible:ring-(--cp-info-border) focus-visible:ring-offset-2 focus-visible:ring-offset-(--cp-bg-surface)',
@@ -73,7 +73,7 @@ function paginationPageClass(page: number) {
class="mt-2 flex min-h-10 shrink-0 flex-wrap items-center justify-between gap-3 px-0 py-1"
>
<div
class="flex min-w-0 items-center gap-2.5 text-[12px] font-[650] text-(--cp-text-secondary)"
class="flex min-w-0 items-center gap-2.5 text-[12px] font-emphasis text-(--cp-text-secondary)"
>
<span class="whitespace-nowrap">共 {{ pagination.total }} 条</span>
</div>
@@ -103,7 +103,7 @@ function paginationPageClass(page: number) {
<template v-for="(item, index) in pagerItems" :key="`${item}-${index}`">
<span
v-if="item === 'ellipsis'"
class="inline-flex size-8 items-center justify-center text-xs font-[720] text-(--cp-text-muted)"
class="inline-flex size-8 items-center justify-center text-xs font-bold text-(--cp-text-muted)"
>
...
</span>
@@ -35,7 +35,7 @@ const textareaClasses = computed(() => [
'hover:bg-[var(--cp-input-current-bg-hover,var(--cp-input-context-bg-hover))] hover:shadow-(--cp-shadow-input-hover) focus:bg-(--cp-input-soft-bg-focus) focus:shadow-(--cp-shadow-input-focus)',
'disabled:cursor-not-allowed disabled:bg-(--cp-disabled-bg) disabled:text-(--cp-disabled-text) disabled:shadow-none',
sizeClasses[props.size],
'text-[13px] leading-[1.55] font-[650]',
'text-[13px] leading-[1.55] font-emphasis',
props.error ? 'bg-(--cp-input-error-soft-bg) shadow-(--cp-shadow-input-error)' : undefined,
])
</script>
@@ -51,7 +51,7 @@ const textareaClasses = computed(() => [
:aria-label="ariaLabel"
:aria-invalid="error ? 'true' : undefined"
/>
<span v-if="error" class="text-xs leading-[1.15] font-[650] text-(--cp-danger-text)">
<span v-if="error" class="text-xs leading-[1.15] font-emphasis text-(--cp-danger-text)">
{{ error }}
</span>
</div>
+1 -1
View File
@@ -40,7 +40,7 @@ const PANEL_CLASS = [
'pl-3',
'text-xs',
'leading-[1.15]',
'font-[760]',
'font-heavy',
'text-(--cp-text-secondary)',
].join(' ')
const MARK_CLASS = [
@@ -53,15 +53,15 @@ const linkItems = [
<div class="grid gap-5">
<section class="flex min-w-0 items-center gap-3">
<span
class="inline-flex size-9 shrink-0 items-center justify-center rounded-(--cp-icon-button-radius) bg-(--cp-bg-subtle) font-mono text-[15px] leading-none font-[820] text-(--cp-text-primary)"
class="inline-flex size-9 shrink-0 items-center justify-center rounded-(--cp-icon-button-radius) bg-(--cp-bg-subtle) font-mono text-[15px] leading-none font-extrabold text-(--cp-text-primary)"
>
Z
</span>
<div class="min-w-0">
<p class="m-0 truncate text-[15px] leading-none font-[780] text-(--cp-text-primary)">
<p class="m-0 truncate text-[15px] leading-none font-heavy text-(--cp-text-primary)">
{{ author }}
</p>
<p class="mt-1.5 mb-0 text-[12px] leading-none font-[650] text-(--cp-text-secondary)">
<p class="mt-1.5 mb-0 text-[12px] leading-none font-emphasis text-(--cp-text-secondary)">
Built by Zyy · Codex Proxy RS
</p>
</div>
@@ -80,11 +80,11 @@ const linkItems = [
<component :is="item.icon" class="size-5" />
</span>
<div class="min-w-0">
<p class="m-0 text-[11px] leading-none font-[760] text-(--cp-text-muted)">
<p class="m-0 text-[11px] leading-none font-heavy text-(--cp-text-muted)">
{{ item.label }}
</p>
<p
class="mt-2 mb-0 truncate font-mono text-[12px] leading-none font-[720] text-(--cp-text-primary)"
class="mt-2 mb-0 truncate font-mono text-[12px] leading-none font-bold text-(--cp-text-primary)"
:title="item.value"
>
{{ item.value }}
@@ -104,7 +104,7 @@ const linkItems = [
</div>
</section>
<p class="m-0 font-mono text-[11px] leading-none font-[650] text-(--cp-text-muted)">
<p class="m-0 font-mono text-[11px] leading-none font-emphasis text-(--cp-text-muted)">
{{ versionLine }}
</p>
</div>
@@ -353,17 +353,17 @@ onBeforeUnmount(() => {
ref="brandLabelEl"
class="grid min-w-33 content-center overflow-hidden"
>
<strong class="text-base leading-[1.1] font-[760] text-(--cp-text-primary)">
<strong class="text-base leading-[1.1] font-heavy text-(--cp-text-primary)">
Codex Proxy
</strong>
<span class="mt-1.5 flex h-4.5 min-w-0 items-center gap-2">
<span class="shrink-0 text-xs leading-none font-[650] text-(--cp-text-secondary)">
<span class="shrink-0 text-xs leading-none font-emphasis text-(--cp-text-secondary)">
Rust build
</span>
<button
v-if="hasVersionLabel"
type="button"
class="inline-flex h-4.5 min-w-0 cursor-pointer items-center gap-1 rounded-(--cp-input-radius-small) border-0 px-1.5 font-mono text-[10px] leading-none font-[720] transition-colors outline-none focus-visible:ring-2 focus-visible:ring-(--cp-info-border) focus-visible:ring-offset-2 focus-visible:ring-offset-(--cp-bg-surface)"
class="inline-flex h-4.5 min-w-0 cursor-pointer items-center gap-1 rounded-(--cp-input-radius-small) border-0 px-1.5 font-mono text-[10px] leading-none font-bold transition-colors outline-none focus-visible:ring-2 focus-visible:ring-(--cp-info-border) focus-visible:ring-offset-2 focus-visible:ring-offset-(--cp-bg-surface)"
:class="[
hasUpdate
? 'bg-(--cp-success-bg) text-(--cp-success-text) hover:bg-(--cp-success-bg-hover)'
@@ -427,7 +427,7 @@ onBeforeUnmount(() => {
>
<span
v-if="!isCollapsed"
class="inline-flex whitespace-nowrap h-7 items-center gap-1.5 rounded-lg bg-(--cp-success-bg) px-2.5 text-xs leading-none font-[650] text-(--cp-success-text)"
class="inline-flex whitespace-nowrap h-7 items-center gap-1.5 rounded-lg bg-(--cp-success-bg) px-2.5 text-xs leading-none font-emphasis text-(--cp-success-text)"
>
<i class="size-1.5 rounded-full bg-(--cp-success)" />
在线
@@ -328,15 +328,15 @@ watch(
<section class="grid gap-4 rounded-(--cp-card-radius) bg-(--cp-bg-subtle) px-4 py-4">
<div class="flex flex-wrap items-center justify-between gap-3">
<div class="min-w-0">
<p class="m-0 text-[11px] leading-none font-[760] text-(--cp-text-muted)">
<p class="m-0 text-[11px] leading-none font-heavy text-(--cp-text-muted)">
Codex Proxy RS
</p>
<p class="mt-2 mb-0 text-lg leading-none font-[780] text-(--cp-text-primary)">
<p class="mt-2 mb-0 text-lg leading-none font-heavy text-(--cp-text-primary)">
应用包更新
</p>
</div>
<span
class="inline-flex h-7 shrink-0 items-center gap-1.5 rounded-full px-2.5 text-[12px] font-[760]"
class="inline-flex h-7 shrink-0 items-center gap-1.5 rounded-full px-2.5 text-[12px] font-heavy"
:class="statusView.badge"
>
<component :is="statusView.icon" class="size-3.5" :class="statusView.iconClass" />
@@ -351,7 +351,7 @@ watch(
class="min-w-0 rounded-(--cp-input-radius-base) bg-(--cp-bg-surface) px-3 py-2.5"
>
<div class="flex min-w-0 items-center justify-between gap-2">
<p class="m-0 truncate text-[11px] leading-none font-[760] text-(--cp-text-muted)">
<p class="m-0 truncate text-[11px] leading-none font-heavy text-(--cp-text-muted)">
{{ item.label }}
</p>
<a
@@ -359,14 +359,14 @@ watch(
:href="item.releaseUrl"
target="_blank"
rel="noreferrer"
class="inline-flex shrink-0 items-center gap-1 text-[11px] leading-none font-[720] text-(--cp-info-text) transition-colors hover:text-(--cp-info)"
class="inline-flex shrink-0 items-center gap-1 text-[11px] leading-none font-bold text-(--cp-info-text) transition-colors hover:text-(--cp-info)"
>
发布页
<ExternalLink class="size-3" />
</a>
</div>
<p
class="mt-2 mb-0 truncate font-mono text-[13px] leading-none font-[720] text-(--cp-text-primary)"
class="mt-2 mb-0 truncate font-mono text-[13px] leading-none font-bold text-(--cp-text-primary)"
:title="item.title || item.value"
>
{{ item.value }}
@@ -376,7 +376,7 @@ watch(
<p
v-if="updateError || updateInfo?.warning"
class="m-0 rounded-(--cp-input-radius-base) bg-(--cp-danger-bg) px-3 py-2 text-[12px] leading-normal font-[720] text-(--cp-danger-text)"
class="m-0 rounded-(--cp-input-radius-base) bg-(--cp-danger-bg) px-3 py-2 text-[12px] leading-normal font-bold text-(--cp-danger-text)"
>
{{ updateError || updateInfo?.warning }}
</p>
@@ -387,10 +387,10 @@ watch(
class="grid gap-2 rounded-(--cp-card-radius) bg-(--cp-bg-subtle) px-4 py-3.5"
>
<div class="flex items-center justify-between gap-3">
<p class="m-0 text-[13px] font-[760] text-(--cp-text-primary)">
<p class="m-0 text-[13px] font-heavy text-(--cp-text-primary)">
发布说明
</p>
<span class="font-mono text-[11px] font-[650] text-(--cp-text-muted)">
<span class="font-mono text-[11px] font-emphasis text-(--cp-text-muted)">
{{ displayValue(updateInfo?.latestVersion) }}
</span>
</div>
@@ -406,12 +406,12 @@ watch(
<header class="flex items-center justify-between gap-3 px-4 pt-3.5 pb-2.5">
<div class="flex min-w-0 items-center gap-2">
<Terminal class="size-4 shrink-0 text-(--cp-success)" />
<p class="m-0 text-[13px] leading-none font-[760] text-(--cp-text-primary)">
<p class="m-0 text-[13px] leading-none font-heavy text-(--cp-text-primary)">
更新进度
</p>
</div>
<span
class="inline-flex h-6 items-center gap-1.5 rounded-full bg-(--cp-bg-subtle) px-2 text-[11px] leading-none font-[720] text-(--cp-text-secondary)"
class="inline-flex h-6 items-center gap-1.5 rounded-full bg-(--cp-bg-subtle) px-2 text-[11px] leading-none font-bold text-(--cp-text-secondary)"
:title="updateStreamError || streamStatusLabel"
>
<i
@@ -509,17 +509,17 @@ watch(
:key="item.key"
class="flex min-w-0 items-center justify-between gap-3"
>
<span class="text-[12px] leading-none font-[720] text-(--cp-text-muted)">
<span class="text-[12px] leading-none font-bold text-(--cp-text-muted)">
{{ item.label }}
</span>
<span
class="truncate font-mono text-[13px] leading-none font-[760] text-(--cp-text-primary)"
class="truncate font-mono text-[13px] leading-none font-heavy text-(--cp-text-primary)"
>
{{ item.value }}
</span>
</div>
</div>
<p class="m-0 text-[12px] leading-relaxed font-[650] text-(--cp-text-muted)">
<p class="m-0 text-[12px] leading-relaxed font-emphasis text-(--cp-text-muted)">
点击确认后弹窗会关闭,并按远端最新目标版本开始更新
</p>
</div>
@@ -530,7 +530,7 @@ watch(
.release-notes {
color: var(--cp-text-primary);
font-size: 12px;
font-weight: 620;
font-weight: var(--font-weight-emphasis);
line-height: 1.65;
overflow-wrap: anywhere;
}
@@ -554,7 +554,7 @@ watch(
margin: 12px 0 6px;
color: var(--cp-text-primary);
font-size: 12px;
font-weight: 780;
font-weight: var(--font-weight-heavy);
line-height: 1.4;
}
@@ -574,7 +574,7 @@ watch(
.release-notes :deep(a) {
color: var(--cp-info-text);
font-weight: 720;
font-weight: 700;
text-decoration: none;
}
+4
View File
@@ -6,6 +6,10 @@
--font-sans:
'Inter Variable', Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--font-mono: 'JetBrains Mono Variable', 'JetBrains Mono', 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
/* 界面字重刻度:正文强调 650 / 加粗 700(font-bold) / 重标题 760 / 极重 800(font-extrabold)。
新代码从这四档取值,不再使用任意字重。 */
--font-weight-emphasis: 650;
--font-weight-heavy: 760;
--color-cp-page: var(--cp-bg-page);
--color-cp-surface: var(--cp-bg-surface);
--color-cp-subtle: var(--cp-bg-subtle);
@@ -63,7 +63,7 @@ function connectionLogClass(tone: string) {
<section class="rounded-(--cp-card-radius) bg-(--cp-bg-subtle) px-4 py-3">
<div class="grid gap-2">
<div class="flex min-h-8 items-center justify-between gap-3">
<span class="text-[12px] font-[760] text-(--cp-text-muted)">
<span class="text-[12px] font-heavy text-(--cp-text-muted)">
测试模型
</span>
<BaseButton
@@ -105,18 +105,18 @@ function connectionLogClass(tone: string) {
/>
</span>
<div class="min-w-0">
<p class="m-0 text-[16px] font-[780] text-(--cp-text-primary)">
<p class="m-0 text-[16px] font-heavy text-(--cp-text-primary)">
{{ statusView.label }}
</p>
<p
class="mt-1.5 mb-0 text-[13px] leading-normal font-[650] text-(--cp-text-secondary)"
class="mt-1.5 mb-0 text-[13px] leading-normal font-emphasis text-(--cp-text-secondary)"
>
{{ statusView.description }}
</p>
</div>
</div>
<span
class="inline-flex h-7 shrink-0 items-center rounded-full px-2.5 text-[12px] font-[760]"
class="inline-flex h-7 shrink-0 items-center rounded-full px-2.5 text-[12px] font-heavy"
:class="statusView.badge"
>
{{ status === 'running' ? '检测中' : statusView.label }}
@@ -125,37 +125,37 @@ function connectionLogClass(tone: string) {
<div class="mt-4 grid gap-3 sm:grid-cols-3">
<div class="rounded-lg bg-(--cp-bg-surface) px-3 py-2.5">
<p class="m-0 text-[11px] font-[760] text-(--cp-text-muted)">
<p class="m-0 text-[11px] font-heavy text-(--cp-text-muted)">
开始时间
</p>
<p class="mt-1.5 mb-0 font-mono text-[12px] font-[650] text-(--cp-text-primary)">
<p class="mt-1.5 mb-0 font-mono text-[12px] font-emphasis text-(--cp-text-primary)">
{{ startedAt || '-' }}
</p>
</div>
<div class="rounded-lg bg-(--cp-bg-surface) px-3 py-2.5">
<p class="m-0 text-[11px] font-[760] text-(--cp-text-muted)">
<p class="m-0 text-[11px] font-heavy text-(--cp-text-muted)">
完成时间
</p>
<p class="mt-1.5 mb-0 font-mono text-[12px] font-[650] text-(--cp-text-primary)">
<p class="mt-1.5 mb-0 font-mono text-[12px] font-emphasis text-(--cp-text-primary)">
{{ finishedAt || '-' }}
</p>
</div>
<div class="rounded-lg bg-(--cp-bg-surface) px-3 py-2.5">
<p class="m-0 text-[11px] font-[760] text-(--cp-text-muted)">
<p class="m-0 text-[11px] font-heavy text-(--cp-text-muted)">
响应耗时
</p>
<p class="mt-1.5 mb-0 font-mono text-[12px] font-[650] text-(--cp-text-primary)">
<p class="mt-1.5 mb-0 font-mono text-[12px] font-emphasis text-(--cp-text-primary)">
{{ durationMs !== null ? `${durationMs}ms` : '-' }}
</p>
</div>
</div>
<div class="mt-3 rounded-lg bg-(--cp-bg-surface) px-3 py-2.5">
<p class="m-0 text-[11px] font-[760] text-(--cp-text-muted)">
<p class="m-0 text-[11px] font-heavy text-(--cp-text-muted)">
测试模型
</p>
<p
class="mt-1.5 mb-0 truncate font-mono text-[12px] font-[650] text-(--cp-text-primary)"
class="mt-1.5 mb-0 truncate font-mono text-[12px] font-emphasis text-(--cp-text-primary)"
:title="model || '-'"
>
{{ model || '-' }}
@@ -163,18 +163,18 @@ function connectionLogClass(tone: string) {
</div>
<div class="mt-3 rounded-lg bg-(--cp-bg-surface) px-3 py-2.5">
<p class="m-0 text-[11px] font-[760] text-(--cp-text-muted)">
<p class="m-0 text-[11px] font-heavy text-(--cp-text-muted)">
事件轨迹
</p>
<BaseScrollbar max-height="260px" view-class="pt-2 pr-2">
<div v-if="logs.length === 0" class="text-[12px] font-[650] text-(--cp-text-muted)">
<div v-if="logs.length === 0" class="text-[12px] font-emphasis text-(--cp-text-muted)">
-
</div>
<div v-else class="flex flex-col gap-1.5">
<div
v-for="item in logs"
:key="item.key"
class="grid grid-cols-[54px_minmax(0,1fr)] gap-2 text-[12px] leading-[1.45] font-[650]"
class="grid grid-cols-[54px_minmax(0,1fr)] gap-2 text-[12px] leading-[1.45] font-emphasis"
>
<span class="font-mono text-(--cp-text-muted)">{{ item.time }}</span>
<div class="min-w-0">
@@ -184,7 +184,7 @@ function connectionLogClass(tone: string) {
<div v-if="item.detail" class="mt-2 rounded-lg bg-(--cp-bg-subtle) px-3 py-2">
<BaseScrollbar max-height="138px" view-class="pr-2">
<pre
class="m-0 whitespace-pre-wrap wrap-break-word font-mono text-[11px] leading-[1.6] font-[620] text-(--cp-text-primary)"
class="m-0 whitespace-pre-wrap wrap-break-word font-mono text-[11px] leading-[1.6] font-emphasis text-(--cp-text-primary)"
>{{ item.detail }}</pre>
</BaseScrollbar>
</div>
@@ -195,12 +195,12 @@ function connectionLogClass(tone: string) {
</div>
<div v-if="error" class="mt-3 rounded-lg bg-(--cp-danger-bg) px-3 py-2.5">
<p class="m-0 text-[11px] font-[760] text-(--cp-danger-text)">
<p class="m-0 text-[11px] font-heavy text-(--cp-danger-text)">
错误信息
</p>
<BaseScrollbar max-height="118px" view-class="pt-1.5 pr-2">
<p
class="m-0 wrap-break-word text-[12px] leading-[1.55] font-[650] text-(--cp-danger-text)"
class="m-0 wrap-break-word text-[12px] leading-[1.55] font-emphasis text-(--cp-danger-text)"
>
{{ error }}
</p>
@@ -227,7 +227,7 @@ async function copyText(value: string, successText: string) {
<KeyRound class="size-4" />
</div>
<div class="min-w-0 flex-1">
<p class="m-0 text-[13px] font-[720] text-(--cp-text-primary)">
<p class="m-0 text-[13px] font-bold text-(--cp-text-primary)">
{{ oauthPanelTitle }}
</p>
<p class="m-0 mt-1 text-[12px] leading-[1.55] font-medium text-(--cp-text-secondary)">
@@ -268,7 +268,7 @@ async function copyText(value: string, successText: string) {
view-class="rounded-(--cp-input-radius-base) bg-(--cp-input-current-bg,var(--cp-input-context-bg)) px-3.5 py-3 shadow-(--cp-shadow-input)"
>
<pre
class="m-0 whitespace-pre-wrap wrap-break-word font-mono text-[12px] leading-[1.6] font-[650] text-(--cp-text-secondary)"
class="m-0 whitespace-pre-wrap wrap-break-word font-mono text-[12px] leading-[1.6] font-emphasis text-(--cp-text-secondary)"
>{{ oauthAuthUrl }}</pre>
</BaseScrollbar>
</BaseFormItem>
@@ -70,14 +70,14 @@ const avatarClass = computed(() => {
<template>
<div class="flex min-w-0 items-center gap-3">
<span
class="inline-flex shrink-0 items-center justify-center rounded-lg font-[820]"
class="inline-flex shrink-0 items-center justify-center rounded-lg font-extrabold"
:class="[avatarSizeClass, avatarClass]"
>
{{ initial }}
</span>
<div class="min-w-0 flex-1">
<div class="flex min-w-0 items-center gap-2">
<span class="min-w-0 flex-1 truncate text-[14px] font-[760] text-(--cp-text-primary)">
<span class="min-w-0 flex-1 truncate text-[14px] font-heavy text-(--cp-text-primary)">
{{ displayTitle }}
</span>
<span
@@ -95,7 +95,7 @@ const avatarClass = computed(() => {
<slot name="meta" />
<AccountPlanBadge v-if="showPlan" :plan-type="account.planType" size="sm" />
</div>
<div v-else-if="secondaryText" class="truncate font-[650]" :class="secondaryClass">
<div v-else-if="secondaryText" class="truncate font-emphasis" :class="secondaryClass">
{{ secondaryText }}
</div>
</div>
@@ -70,15 +70,15 @@ function overviewIconClass(tone: string) {
>
<div class="flex h-full items-stretch justify-between gap-3 px-5 py-3">
<div class="flex min-w-0 flex-col justify-between">
<p class="m-0 text-[12px] leading-none font-[760] text-(--cp-text-secondary)">
<p class="m-0 text-[12px] leading-none font-heavy text-(--cp-text-secondary)">
{{ item.label }}
</p>
<strong
class="block font-mono text-[26px] leading-none font-[820] text-(--cp-text-primary)"
class="block font-mono text-[26px] leading-none font-extrabold text-(--cp-text-primary)"
>
{{ item.value }}
</strong>
<p class="m-0 truncate text-[12px] leading-none font-[650] text-(--cp-text-muted)">
<p class="m-0 truncate text-[12px] leading-none font-emphasis text-(--cp-text-muted)">
{{ item.caption }}
</p>
</div>
@@ -23,8 +23,8 @@ const label = computed(() => props.planType?.trim() || 'Free')
const sizeClass = computed(() =>
props.size === 'sm'
? 'h-5 rounded-full px-1.75 text-[11px] font-[720]'
: 'h-5.5 rounded-full px-2 text-[11px] font-[760]',
? 'h-5 rounded-full px-1.75 text-[11px] font-bold'
: 'h-5.5 rounded-full px-2 text-[11px] font-heavy',
)
const paletteClass = computed(() => {
@@ -24,11 +24,11 @@ const quotaWindows = computed(() => orderedPanelQuotaWindows(props.account.quota
<section class="rounded-lg bg-(--cp-bg-surface) p-4 shadow-(--cp-shadow-control)">
<div class="mb-3 flex items-center justify-between gap-3">
<div>
<h3 class="m-0 text-[14px] font-[760] text-(--cp-text-primary)">
<h3 class="m-0 text-[14px] font-heavy text-(--cp-text-primary)">
账号额度
</h3>
<p
class="m-0 mt-1 flex flex-wrap items-center gap-x-1.5 gap-y-1 text-[12px] font-[620] text-(--cp-text-secondary)"
class="m-0 mt-1 flex flex-wrap items-center gap-x-1.5 gap-y-1 text-[12px] font-emphasis text-(--cp-text-secondary)"
>
<span>{{ account.provider === 'xai' ? 'xAI 用量窗口' : 'Codex 额度' }}</span>
<template v-if="account.provider === 'openai'">
@@ -52,14 +52,14 @@ const dotClass = computed(() => {
<template>
<span
v-if="variant === 'pill'"
class="inline-flex h-7 shrink-0 items-center rounded-full px-2.5 text-[12px] font-[760]"
class="inline-flex h-7 shrink-0 items-center rounded-full px-2.5 text-[12px] font-heavy"
:class="textClass"
>
{{ label }}
</span>
<span
v-else
class="inline-flex min-w-16 items-center gap-1.5 text-[12px] leading-none font-[650]"
class="inline-flex min-w-16 items-center gap-1.5 text-[12px] leading-none font-emphasis"
:class="textClass"
>
<span class="size-1.5 rounded-full" :class="dotClass" />
@@ -54,7 +54,7 @@ const canReauthorize = computed(() => props.account.provider === 'openai')
<template #default="{ close }">
<button
type="button"
class="flex h-8.5 w-full items-center gap-2 rounded-(--cp-input-radius-small) border-0 bg-transparent px-3 text-left text-[13px] leading-none font-[650] text-(--cp-text-primary) transition-colors hover:bg-(--cp-default-bg-hover) disabled:cursor-not-allowed disabled:text-(--cp-disabled-text)"
class="flex h-8.5 w-full items-center gap-2 rounded-(--cp-input-radius-small) border-0 bg-transparent px-3 text-left text-[13px] leading-none font-emphasis text-(--cp-text-primary) transition-colors hover:bg-(--cp-default-bg-hover) disabled:cursor-not-allowed disabled:text-(--cp-disabled-text)"
:disabled="testing"
@click.stop="(close(), emit('test', account))"
>
@@ -65,7 +65,7 @@ const canReauthorize = computed(() => props.account.provider === 'openai')
<button
v-if="canRefreshToken"
type="button"
class="flex h-8.5 w-full items-center gap-2 rounded-(--cp-input-radius-small) border-0 bg-transparent px-3 text-left text-[13px] leading-none font-[650] text-(--cp-text-primary) transition-colors hover:bg-(--cp-default-bg-hover) disabled:cursor-not-allowed disabled:text-(--cp-disabled-text)"
class="flex h-8.5 w-full items-center gap-2 rounded-(--cp-input-radius-small) border-0 bg-transparent px-3 text-left text-[13px] leading-none font-emphasis text-(--cp-text-primary) transition-colors hover:bg-(--cp-default-bg-hover) disabled:cursor-not-allowed disabled:text-(--cp-disabled-text)"
:disabled="refreshing"
@click.stop="(close(), emit('refresh', account.id))"
>
@@ -78,7 +78,7 @@ const canReauthorize = computed(() => props.account.provider === 'openai')
<button
v-if="canReauthorize"
type="button"
class="flex h-8.5 w-full items-center gap-2 rounded-(--cp-input-radius-small) border-0 bg-transparent px-3 text-left text-[13px] leading-none font-[650] text-(--cp-text-primary) transition-colors hover:bg-(--cp-default-bg-hover)"
class="flex h-8.5 w-full items-center gap-2 rounded-(--cp-input-radius-small) border-0 bg-transparent px-3 text-left text-[13px] leading-none font-emphasis text-(--cp-text-primary) transition-colors hover:bg-(--cp-default-bg-hover)"
@click.stop="(close(), emit('reauthorize', account))"
>
<KeyRound class="size-3.5 text-(--cp-text-muted)" />
@@ -86,7 +86,7 @@ const canReauthorize = computed(() => props.account.provider === 'openai')
</button>
<button
type="button"
class="flex h-8.5 w-full items-center gap-2 rounded-(--cp-input-radius-small) border-0 bg-transparent px-3 text-left text-[13px] leading-none font-[650] text-(--cp-text-primary) transition-colors hover:bg-(--cp-default-bg-hover) disabled:cursor-not-allowed disabled:text-(--cp-disabled-text)"
class="flex h-8.5 w-full items-center gap-2 rounded-(--cp-input-radius-small) border-0 bg-transparent px-3 text-left text-[13px] leading-none font-emphasis text-(--cp-text-primary) transition-colors hover:bg-(--cp-default-bg-hover) disabled:cursor-not-allowed disabled:text-(--cp-disabled-text)"
:disabled="updatingStatus"
@click.stop="(close(), emit('toggleSchedule', account))"
>
@@ -11,7 +11,7 @@ defineProps<{
class="grid gap-4 rounded-lg bg-(--cp-bg-surface) p-4 shadow-(--cp-shadow-control) xl:grid-cols-[0.52fr_1.48fr]"
>
<div>
<h3 class="m-0 mb-3 text-[14px] font-[760] text-(--cp-text-primary)">
<h3 class="m-0 mb-3 text-[14px] font-heavy text-(--cp-text-primary)">
Token 结构
</h3>
<div class="grid gap-2">
@@ -52,13 +52,13 @@ defineProps<{
class="min-w-0 pt-4 shadow-[inset_0_1px_0_var(--cp-divider-subtle)] xl:pt-0 xl:pl-4 xl:shadow-[inset_1px_0_0_var(--cp-divider-subtle)]"
>
<div class="mb-3 flex items-center justify-between">
<h3 class="m-0 text-[14px] font-[760] text-(--cp-text-primary)">
<h3 class="m-0 text-[14px] font-heavy text-(--cp-text-primary)">
模型使用排行
</h3>
</div>
<div
class="grid grid-cols-[1.2fr_0.7fr_0.8fr_1fr_1fr_1fr_1fr_1fr_1.4fr] gap-3 pb-2 text-[11px] font-[760] text-(--cp-text-secondary) shadow-[inset_0_-1px_0_var(--cp-divider-subtle)]"
class="grid grid-cols-[1.2fr_0.7fr_0.8fr_1fr_1fr_1fr_1fr_1fr_1.4fr] gap-3 pb-2 text-[11px] font-heavy text-(--cp-text-secondary) shadow-[inset_0_-1px_0_var(--cp-divider-subtle)]"
>
<span>模型</span>
<span>调用</span>
@@ -72,7 +72,7 @@ defineProps<{
</div>
<div
v-if="account.usage.models.length === 0"
class="pt-3 text-[12px] font-[650] text-(--cp-text-muted)"
class="pt-3 text-[12px] font-emphasis text-(--cp-text-muted)"
>
-
</div>
@@ -80,7 +80,7 @@ defineProps<{
<div
v-for="model in account.usage.models"
:key="model.model"
class="grid grid-cols-[1.2fr_0.7fr_0.8fr_1fr_1fr_1fr_1fr_1fr_1.4fr] gap-3 pt-3 text-[12px] font-[650] text-(--cp-text-primary)"
class="grid grid-cols-[1.2fr_0.7fr_0.8fr_1fr_1fr_1fr_1fr_1fr_1.4fr] gap-3 pt-3 text-[12px] font-emphasis text-(--cp-text-primary)"
>
<span class="truncate">{{ model.model }}</span>
<span>{{ model.requestCountDisplay }}</span>
@@ -60,16 +60,16 @@ const rootClass = computed(() =>
)
const headerClass = computed(() =>
isCompact.value
? 'mb-1 flex items-center justify-between gap-2 text-[11px] leading-none font-[720]'
: 'flex items-center justify-between gap-3 text-[12px] font-[720]',
? 'mb-1 flex items-center justify-between gap-2 text-[11px] leading-none font-bold'
: 'flex items-center justify-between gap-3 text-[12px] font-bold',
)
const labelClass = computed(() =>
isCompact.value ? 'text-(--cp-text-muted)' : 'text-(--cp-text-secondary)',
)
const valueClass = computed(() =>
isCompact.value
? 'text-[10px] leading-none font-[780]'
: 'text-[12px] font-[780]',
? 'text-[10px] leading-none font-heavy'
: 'text-[12px] font-heavy',
)
const trackShapeClass = computed(() =>
isCompact.value
@@ -177,7 +177,7 @@ const requestBars = computed(() => {
</div>
<div
v-if="!isCompact && window.resetAtDisplay !== '—'"
class="mt-3 text-[12px] font-[620] text-(--cp-text-secondary)"
class="mt-3 text-[12px] font-emphasis text-(--cp-text-secondary)"
>
重置时间: {{ window.resetAtDisplay }}
</div>
@@ -13,7 +13,7 @@ defineProps<{
<span class="text-[13px] font-bold text-(--cp-text-primary)">
{{ apiKey.name }}
</span>
<span v-if="apiKey.label" class="text-[12px] font-[650] text-(--cp-text-tertiary)">
<span v-if="apiKey.label" class="text-[12px] font-emphasis text-(--cp-text-tertiary)">
{{ apiKey.label }}
</span>
</div>
@@ -15,7 +15,7 @@ const emit = defineEmits<{
<template>
<div class="flex items-center gap-2">
<code class="block min-w-0 truncate font-mono text-[12px] font-[650] text-(--cp-text-primary)">
<code class="block min-w-0 truncate font-mono text-[12px] font-emphasis text-(--cp-text-primary)">
{{ prefix }}••••••••••••••••
</code>
<BaseButton
@@ -89,7 +89,7 @@ const visibleFiles = computed(() => [
>
<div class="flex items-center justify-between gap-3 px-4 py-2.5">
<span
class="min-w-0 truncate font-mono text-[12px] font-[650] text-(--cp-text-secondary)"
class="min-w-0 truncate font-mono text-[12px] font-emphasis text-(--cp-text-secondary)"
>
{{ file.path }}
</span>
@@ -108,7 +108,7 @@ const visibleFiles = computed(() => [
view-class="mx-3 mb-3 rounded-(--cp-input-radius-base) bg-(--cp-bg-surface) px-3.5 py-3 shadow-(--cp-shadow-input)"
>
<pre
class="m-0 whitespace-pre-wrap wrap-break-word font-mono text-[12px] leading-[1.65] font-[650] text-(--cp-text-primary)"
class="m-0 whitespace-pre-wrap wrap-break-word font-mono text-[12px] leading-[1.65] font-emphasis text-(--cp-text-primary)"
>{{ file.content }}</pre>
</BaseScrollbar>
</section>
+2 -2
View File
@@ -33,7 +33,7 @@ export const apiKeyColumns = [
sortKey: 'createdAt',
width: '176px',
minWidth: '176px',
cellClass: 'font-mono text-[12px] font-[650] tabular-nums text-(--cp-text-secondary)',
cellClass: 'font-mono text-[12px] font-emphasis tabular-nums text-(--cp-text-secondary)',
},
{
key: 'lastUsedAtDisplay',
@@ -42,7 +42,7 @@ export const apiKeyColumns = [
sortKey: 'lastUsedAt',
width: '176px',
minWidth: '176px',
cellClass: 'font-mono text-[12px] font-[650] tabular-nums text-(--cp-text-secondary)',
cellClass: 'font-mono text-[12px] font-emphasis tabular-nums text-(--cp-text-secondary)',
},
{
key: 'actions',
@@ -158,7 +158,7 @@ const statusBars = computed(() => {
class="grid px-4 pt-5 pb-6 lg:px-7 lg:pt-6 xl:grid-cols-[minmax(0,0.9fr)_minmax(0,1.28fr)_minmax(280px,0.9fr)] xl:gap-7 xl:pb-0"
>
<section class="min-w-0 w-full pb-6 xl:h-100.5 xl:pb-0">
<h2 class="m-0 text-xl leading-[1.15] font-[760] text-(--cp-text-primary)">
<h2 class="m-0 text-xl leading-[1.15] font-heavy text-(--cp-text-primary)">
账号调度
</h2>
<p class="mt-1.75 mb-0 text-[13px] leading-[1.15] font-semibold text-(--cp-text-secondary)">
@@ -167,13 +167,13 @@ const statusBars = computed(() => {
<div class="mt-6.75 grid gap-4 xl:h-82.5 xl:grid-rows-[122px_90px_minmax(0,1fr)]">
<div class="grid h-30.5 content-between rounded-[14px] bg-(--cp-bg-subtle) p-4 xl:h-auto">
<span class="block h-3.5 text-xs leading-[1.15] font-[650] text-(--cp-text-secondary)">槽位占用</span>
<span class="block h-3.5 text-xs leading-[1.15] font-emphasis text-(--cp-text-secondary)">槽位占用</span>
<div>
<div class="grid h-8.5 grid-cols-[minmax(0,1fr)_auto] items-start gap-4">
<strong
class="font-mono text-[32px] leading-[1.05] font-[760] tabular-nums text-(--cp-text-primary)"
class="font-mono text-[32px] leading-[1.05] font-heavy tabular-nums text-(--cp-text-primary)"
>{{ usedRatio }}</strong>
<span class="mt-3.5 text-xs leading-[1.15] font-[650] text-(--cp-text-secondary)">
<span class="mt-3.5 text-xs leading-[1.15] font-emphasis text-(--cp-text-secondary)">
{{ occupancyLabel }}
</span>
</div>
@@ -190,18 +190,18 @@ const statusBars = computed(() => {
class="grid h-22.5 grid-cols-3 gap-4 rounded-[14px] bg-(--cp-bg-subtle) p-4 xl:h-auto"
>
<div v-for="stat in scheduleStats" :key="stat.label" class="grid content-between">
<span class="text-xs leading-[1.15] font-[650] text-(--cp-text-secondary)">{{
<span class="text-xs leading-[1.15] font-emphasis text-(--cp-text-secondary)">{{
stat.label
}}</span>
<strong
class="block font-mono text-[21px] leading-[1.1] font-[760] tabular-nums text-(--cp-text-primary)"
class="block font-mono text-[21px] leading-[1.1] font-heavy tabular-nums text-(--cp-text-primary)"
>{{ stat.value }}</strong>
</div>
</div>
<div class="grid h-20.5 content-between rounded-[14px] bg-(--cp-bg-subtle) p-4 xl:h-auto">
<span class="text-xs leading-[1.15] font-[650] text-(--cp-text-secondary)">分配策略</span>
<strong class="block text-[17px] leading-[1.15] font-[650] text-(--cp-text-primary)">{{
<span class="text-xs leading-[1.15] font-emphasis text-(--cp-text-secondary)">分配策略</span>
<strong class="block text-[17px] leading-[1.15] font-emphasis text-(--cp-text-primary)">{{
strategyLabel
}}</strong>
</div>
@@ -209,7 +209,7 @@ const statusBars = computed(() => {
</section>
<section class="min-w-0 w-full">
<h2 class="m-0 text-xl leading-[1.15] font-[760] text-(--cp-text-primary)">
<h2 class="m-0 text-xl leading-[1.15] font-heavy text-(--cp-text-primary)">
活跃账号用量
</h2>
<p class="mt-1.75 mb-0 text-[13px] leading-[1.15] font-semibold text-(--cp-text-secondary)">
@@ -252,18 +252,18 @@ const statusBars = computed(() => {
class="grid min-w-0 grid-cols-[minmax(0,0.82fr)_minmax(0,0.64fr)_minmax(104px,1fr)] items-end gap-3 xl:contents"
>
<span class="grid min-w-0 gap-1">
<span class="text-[11px] leading-none font-[720] text-(--cp-text-muted)">
<span class="text-[11px] leading-none font-bold text-(--cp-text-muted)">
{{ account.metricLabel }}
</span>
<strong
class="font-mono text-sm leading-[1.15] font-[780] tabular-nums text-(--cp-text-primary)"
class="font-mono text-sm leading-[1.15] font-heavy tabular-nums text-(--cp-text-primary)"
>{{ account.metricValue }}</strong>
</span>
<span class="grid min-w-0 gap-1">
<span class="text-[11px] leading-none font-[720] text-(--cp-text-muted)">最近</span>
<span class="text-[11px] leading-none font-bold text-(--cp-text-muted)">最近</span>
<span
class="min-w-0 truncate text-xs leading-[1.15] font-[680] text-(--cp-text-secondary) xl:whitespace-nowrap"
class="min-w-0 truncate text-xs leading-[1.15] font-bold text-(--cp-text-secondary) xl:whitespace-nowrap"
>
{{ account.lastUsed }}
</span>
@@ -284,16 +284,16 @@ const statusBars = computed(() => {
<section class="min-w-0 w-full pt-6 xl:h-100.5 xl:pt-0">
<header class="flex h-12.5 items-start justify-between">
<div>
<h2 class="m-0 text-xl leading-[1.15] font-[760] text-(--cp-text-primary)">
<h2 class="m-0 text-xl leading-[1.15] font-heavy text-(--cp-text-primary)">
账号状态
</h2>
<p class="mt-1 mb-0 text-[13px] leading-[1.15] font-[650] text-(--cp-text-secondary)">
<p class="mt-1 mb-0 text-[13px] leading-[1.15] font-emphasis text-(--cp-text-secondary)">
账号池健康结构
</p>
</div>
<div class="grid justify-items-end">
<strong
class="font-mono text-2xl leading-[1.05] font-[760] tabular-nums text-(--cp-success-text)"
class="font-mono text-2xl leading-[1.05] font-heavy tabular-nums text-(--cp-success-text)"
>{{ availabilityRate }}</strong>
<span class="mt-0.5 text-xs leading-[1.15] font-bold text-(--cp-text-secondary)">可用率</span>
</div>
@@ -301,8 +301,8 @@ const statusBars = computed(() => {
<div class="mt-5.5 h-10.5 w-full">
<div class="flex h-4 items-center justify-between">
<span class="text-xs leading-[1.15] font-[650] text-(--cp-text-secondary)">状态分布</span>
<span class="text-xs leading-[1.15] font-[650] text-(--cp-danger-text)">不可用 {{ statusRows[3]?.value || '0' }}</span>
<span class="text-xs leading-[1.15] font-emphasis text-(--cp-text-secondary)">状态分布</span>
<span class="text-xs leading-[1.15] font-emphasis text-(--cp-danger-text)">不可用 {{ statusRows[3]?.value || '0' }}</span>
</div>
<div class="mt-2.5 flex h-3 w-full overflow-hidden rounded-full bg-(--cp-bg-muted)">
<i
@@ -328,15 +328,15 @@ const statusBars = computed(() => {
<component :is="row.icon" :size="16" />
</span>
<span class="col-start-3 grid gap-1">
<strong class="text-sm leading-[1.15] font-[650] text-(--cp-text-primary)">{{
<strong class="text-sm leading-[1.15] font-emphasis text-(--cp-text-primary)">{{
row.label
}}</strong>
<span class="text-xs leading-[1.15] font-[650] text-(--cp-text-secondary)">{{
<span class="text-xs leading-[1.15] font-emphasis text-(--cp-text-secondary)">{{
row.description
}}</span>
</span>
<strong
class="col-start-4 text-right font-mono text-[17px] leading-[1.15] font-[760] tabular-nums"
class="col-start-4 text-right font-mono text-[17px] leading-[1.15] font-heavy tabular-nums"
:class="toneValueClass(row.tone)"
>{{ row.value }}</strong>
</div>
@@ -70,17 +70,17 @@ const metricItems = outcomeMeta
<header class="flex items-center justify-between gap-3 bg-(--cp-bg-subtle) px-3.5 py-3">
<div class="flex min-w-0 items-center gap-2">
<span class="size-2 shrink-0 rounded-full" :class="status.cellClass" />
<strong class="font-mono text-[13px] leading-none font-[780] text-(--cp-text-primary)">
<strong class="font-mono text-[13px] leading-none font-heavy text-(--cp-text-primary)">
{{ point.time }}
</strong>
<span
class="inline-flex h-5 items-center rounded-full px-2 text-[10px] leading-none font-[760]"
class="inline-flex h-5 items-center rounded-full px-2 text-[10px] leading-none font-heavy"
:class="status.badgeClass"
>
{{ status.label }}
</span>
</div>
<span class="shrink-0 text-[10px] leading-none font-[650] text-(--cp-text-muted)">
<span class="shrink-0 text-[10px] leading-none font-emphasis text-(--cp-text-muted)">
15 分钟
</span>
</header>
@@ -88,22 +88,22 @@ const metricItems = outcomeMeta
<div class="grid gap-3.5 px-3.5 py-3.5">
<div class="flex items-end justify-between gap-4">
<div>
<p class="m-0 text-[11px] leading-none font-[650] text-(--cp-text-muted)">
<p class="m-0 text-[11px] leading-none font-emphasis text-(--cp-text-muted)">
有效请求可用性
</p>
<strong
class="mt-2 block font-mono text-[25px] leading-none font-[790] tabular-nums"
class="mt-2 block font-mono text-[25px] leading-none font-heavy tabular-nums"
:class="healthReliabilityValueClass(point.successRequests, point.failedRequests)"
>
{{ point.reliabilityDisplay }}
</strong>
</div>
<div class="text-right">
<span class="block text-[10px] leading-none font-[650] text-(--cp-text-muted)">
<span class="block text-[10px] leading-none font-emphasis text-(--cp-text-muted)">
有效请求
</span>
<strong
class="mt-2 block font-mono text-[15px] leading-none font-[760] tabular-nums text-(--cp-text-primary)"
class="mt-2 block font-mono text-[15px] leading-none font-heavy tabular-nums text-(--cp-text-primary)"
>
{{ formatHealthCount(eligibleRequests) }}
</strong>
@@ -130,11 +130,11 @@ const metricItems = outcomeMeta
class="grid grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-2 rounded-(--cp-input-radius-base) bg-(--cp-bg-subtle) px-2.5 py-2.5"
>
<span class="size-1.5 rounded-full" :class="item.dotClass" />
<span class="truncate text-[10px] leading-none font-[650] text-(--cp-text-secondary)">
<span class="truncate text-[10px] leading-none font-emphasis text-(--cp-text-secondary)">
{{ item.label }}
</span>
<strong
class="font-mono text-[12px] leading-none font-[760] tabular-nums"
class="font-mono text-[12px] leading-none font-heavy tabular-nums"
:class="item.valueClass"
>
{{ formatHealthCount(item.value) }}
@@ -143,7 +143,7 @@ const metricItems = outcomeMeta
</div>
<p
class="m-0 border-t border-(--cp-divider-subtle) pt-3 text-[10px] leading-[1.45] font-[650] text-(--cp-text-muted)"
class="m-0 border-t border-(--cp-divider-subtle) pt-3 text-[10px] leading-[1.45] font-emphasis text-(--cp-text-muted)"
>
客户端取消与调用方错误单独记录,不计入可用性。
</p>
@@ -78,14 +78,14 @@ const sparklineOption = computed<EChartsOption | null>(() => {
>
<component :is="metric.icon" :size="18" />
</BaseMotionIcon>
<span class="mt-1 text-[13px] leading-[1.15] font-[650] text-(--cp-text-secondary)">{{
<span class="mt-1 text-[13px] leading-[1.15] font-emphasis text-(--cp-text-secondary)">{{
metric.title
}}</span>
</div>
<div class="mt-3.25 flex h-7.75 items-end gap-2">
<strong
class="font-mono text-[28px] leading-[1.05] font-[780] tabular-nums text-(--cp-text-primary)"
class="font-mono text-[28px] leading-[1.05] font-heavy tabular-nums text-(--cp-text-primary)"
>
<AnimatedMetricValue
:value="metric.value"
@@ -115,7 +115,7 @@ const sparklineOption = computed<EChartsOption | null>(() => {
<span
class="inline-grid min-w-0 w-full grid-cols-[auto_minmax(0,1fr)] items-baseline gap-2.5"
>
<span class="shrink-0 text-[11px] leading-none font-[650] text-(--cp-text-muted)">{{
<span class="shrink-0 text-[11px] leading-none font-emphasis text-(--cp-text-muted)">{{
metric.details[0]?.label
}}</span>
<b
@@ -128,7 +128,7 @@ const sparklineOption = computed<EChartsOption | null>(() => {
<span
class="inline-grid min-w-0 w-full grid-cols-[auto_minmax(0,auto)] items-baseline justify-end gap-2.5"
>
<span class="shrink-0 text-[11px] leading-none font-[650] text-(--cp-text-muted)">{{
<span class="shrink-0 text-[11px] leading-none font-emphasis text-(--cp-text-muted)">{{
metric.details[1]?.label
}}</span>
<b
@@ -216,7 +216,7 @@ onBeforeUnmount(() => {
<template #actions>
<div class="flex w-full flex-wrap items-center justify-between gap-x-4 gap-y-2">
<div
class="flex max-w-full flex-wrap items-center gap-x-2 gap-y-1 text-[11px] leading-none font-[650] text-(--cp-text-muted)"
class="flex max-w-full flex-wrap items-center gap-x-2 gap-y-1 text-[11px] leading-none font-emphasis text-(--cp-text-muted)"
>
<span
v-for="item in healthLegend"
@@ -233,7 +233,7 @@ onBeforeUnmount(() => {
</div>
<div class="flex shrink-0 items-center gap-3">
<strong
class="font-mono text-sm leading-none font-[760] tabular-nums"
class="font-mono text-sm leading-none font-heavy tabular-nums"
:class="healthReliabilityValueClass(timeline.successRequests, timeline.failedRequests)"
>
{{ timeline.reliabilityDisplay }}
@@ -79,11 +79,11 @@ const {
]"
/>
<span class="grid min-w-0 gap-1">
<span class="truncate text-[10px] leading-none font-[680] text-(--cp-text-secondary)">
<span class="truncate text-[10px] leading-none font-bold text-(--cp-text-secondary)">
{{ item.label }}
</span>
<strong
class="truncate font-mono text-[15px] leading-none font-[760] tabular-nums text-(--cp-text-primary)"
class="truncate font-mono text-[15px] leading-none font-heavy tabular-nums text-(--cp-text-primary)"
:title="item.value"
>
{{ item.value }}
@@ -209,10 +209,10 @@ function providerLabel(provider: string) {
>
<Box aria-hidden="true" class="size-3.75 text-(--cp-text-secondary)" />
</span>
<span class="truncate text-[11px] leading-none font-[760]">{{ profile.product }}</span>
<span class="truncate text-[11px] leading-none font-heavy">{{ profile.product }}</span>
</div>
<span
class="inline-flex h-7 shrink-0 items-center gap-1.5 rounded-lg px-2.5 text-[12px] leading-none font-[720]"
class="inline-flex h-7 shrink-0 items-center gap-1.5 rounded-lg px-2.5 text-[12px] leading-none font-bold"
:class="releaseStatus.tone"
:title="releaseStatus.title"
>
@@ -224,14 +224,14 @@ function providerLabel(provider: string) {
<div class="grid min-h-0 content-center">
<div class="flex min-w-0 flex-wrap items-baseline gap-x-2.5 gap-y-1.5">
<strong
class="block max-w-full wrap-break-word font-mono text-[27px] leading-[1.05] font-[790] tabular-nums text-(--cp-text-primary)"
class="block max-w-full wrap-break-word font-mono text-[27px] leading-[1.05] font-heavy tabular-nums text-(--cp-text-primary)"
:title="profile.version"
>
{{ profile.version }}
</strong>
<span
v-if="profile.build"
class="shrink-0 font-mono text-[10px] leading-none font-[650] tabular-nums text-(--cp-text-muted)"
class="shrink-0 font-mono text-[10px] leading-none font-emphasis tabular-nums text-(--cp-text-muted)"
>
Build {{ profile.build }}
</span>
@@ -246,13 +246,13 @@ function providerLabel(provider: string) {
>
<div v-if="profile.provider === 'xai'" class="min-w-0">
<dt
class="flex items-center gap-1.5 text-[10px] leading-none font-[720] text-(--cp-text-muted)"
class="flex items-center gap-1.5 text-[10px] leading-none font-bold text-(--cp-text-muted)"
>
<ShieldCheck aria-hidden="true" class="size-3.25 text-(--cp-info)" />
认证协议
</dt>
<dd
class="mt-2 mb-0 truncate font-mono text-[14px] leading-none font-[720] tabular-nums text-(--cp-text-primary)"
class="mt-2 mb-0 truncate font-mono text-[14px] leading-none font-bold tabular-nums text-(--cp-text-primary)"
:title="authProtocol"
>
{{ authProtocol }}
@@ -261,19 +261,19 @@ function providerLabel(provider: string) {
<div class="min-w-0">
<dt
class="flex items-center gap-1.5 text-[10px] leading-none font-[720] text-(--cp-text-muted)"
class="flex items-center gap-1.5 text-[10px] leading-none font-bold text-(--cp-text-muted)"
>
<Monitor aria-hidden="true" class="size-3.25 text-(--cp-normal)" />
{{ profile.provider === 'openai' ? '模拟运行环境' : '运行环境' }}
</dt>
<dd
class="mt-2 mb-0 truncate font-mono text-[14px] leading-none font-[720] tabular-nums text-(--cp-text-primary)"
class="mt-2 mb-0 truncate font-mono text-[14px] leading-none font-bold tabular-nums text-(--cp-text-primary)"
:title="runtimeEnvironment.title"
>
{{ runtimeEnvironment.primary }}
<span
v-if="runtimeEnvironment.details.length"
class="text-[11px] font-[650] text-(--cp-text-secondary)"
class="text-[11px] font-emphasis text-(--cp-text-secondary)"
>
<template v-for="detail in runtimeEnvironment.details" :key="detail">
· {{ detail }}
@@ -284,13 +284,13 @@ function providerLabel(provider: string) {
<div class="min-w-0">
<dt
class="flex items-center gap-1.5 text-[10px] leading-none font-[720] text-(--cp-text-muted)"
class="flex items-center gap-1.5 text-[10px] leading-none font-bold text-(--cp-text-muted)"
>
<Terminal aria-hidden="true" class="size-3.25 text-(--cp-info)" />
{{ profile.provider === 'openai' ? 'Codex Core' : 'Grok Client' }}
</dt>
<dd
class="mt-2 mb-0 truncate font-mono text-[16px] leading-none font-[760] tabular-nums text-(--cp-text-primary)"
class="mt-2 mb-0 truncate font-mono text-[16px] leading-none font-heavy tabular-nums text-(--cp-text-primary)"
:title="clientIdentity"
>
{{ clientIdentity }}
@@ -300,7 +300,7 @@ function providerLabel(provider: string) {
<footer
v-if="verifiedLabel || checkedLabel"
class="flex min-w-0 flex-wrap items-center justify-between gap-x-4 gap-y-1 text-[10px] leading-none font-[650] text-(--cp-text-muted)"
class="flex min-w-0 flex-wrap items-center justify-between gap-x-4 gap-y-1 text-[10px] leading-none font-emphasis text-(--cp-text-muted)"
>
<span v-if="verifiedLabel" :title="profile.userAgent">{{ verifiedLabel }}</span>
<span v-if="checkedLabel">{{ checkedLabel }}</span>
@@ -70,11 +70,11 @@ const emit = defineEmits<{
<KeyRound class="size-4" />
</BaseMotionIcon>
<div class="min-w-0">
<p class="m-0 text-[13px] leading-[1.15] font-[720] text-(--cp-text-primary)">
<p class="m-0 text-[13px] leading-[1.15] font-bold text-(--cp-text-primary)">
{{ status.exists ? '已启用' : '未生成' }}
</p>
<p
class="mt-1.5 mb-0 truncate text-[12px] leading-[1.15] font-[650] text-(--cp-text-secondary)"
class="mt-1.5 mb-0 truncate text-[12px] leading-[1.15] font-emphasis text-(--cp-text-secondary)"
>
{{
loading
@@ -89,12 +89,12 @@ const emit = defineEmits<{
</div>
<div v-if="generatedKey" class="grid gap-2">
<p class="m-0 text-[13px] leading-[1.15] font-[650] text-(--cp-text-secondary)">
<p class="m-0 text-[13px] leading-[1.15] font-emphasis text-(--cp-text-secondary)">
完整 Key 仅显示一次,请立即保存
</p>
<div class="flex min-w-0 items-center gap-2">
<code
class="min-w-0 flex-1 rounded-(--cp-input-radius-base) bg-(--cp-bg-subtle) px-3 py-2.5 font-mono text-[12px] leading-normal font-[650] break-all text-(--cp-text-primary)"
class="min-w-0 flex-1 rounded-(--cp-input-radius-base) bg-(--cp-bg-subtle) px-3 py-2.5 font-mono text-[12px] leading-normal font-emphasis break-all text-(--cp-text-primary)"
>
{{ generatedKey }}
</code>
@@ -40,28 +40,28 @@ const rows = computed(() => props.mappings)
</template>
添加映射
</BaseButton>
<span v-if="error" class="text-xs font-[650] text-(--cp-danger-text)">{{ error }}</span>
<span v-if="error" class="text-xs font-emphasis text-(--cp-danger-text)">{{ error }}</span>
</div>
<div class="flex items-center gap-2 text-[12px] font-[650] text-(--cp-text-secondary)">
<div class="flex items-center gap-2 text-[12px] font-emphasis text-(--cp-text-secondary)">
<GitBranch class="size-4 text-(--cp-info)" />
全局模型映射
</div>
<div
v-if="loading"
class="rounded-(--cp-input-radius-base) bg-(--cp-bg-subtle) px-4 py-4 text-[13px] font-[650] text-(--cp-text-muted)"
class="rounded-(--cp-input-radius-base) bg-(--cp-bg-subtle) px-4 py-4 text-[13px] font-emphasis text-(--cp-text-muted)"
>
正在加载模型映射...
</div>
<div
v-else-if="rows.length === 0"
class="rounded-(--cp-input-radius-base) bg-(--cp-bg-subtle) px-4 py-4 text-[13px] font-[650] text-(--cp-text-muted)"
class="rounded-(--cp-input-radius-base) bg-(--cp-bg-subtle) px-4 py-4 text-[13px] font-emphasis text-(--cp-text-muted)"
>
暂无模型映射
</div>
<div v-else class="grid gap-3">
<div class="grid grid-cols-[1fr_auto_1fr_auto] items-center gap-3 px-1 text-[12px] font-[700] text-(--cp-text-muted)">
<div class="grid grid-cols-[1fr_auto_1fr_auto] items-center gap-3 px-1 text-[12px] font-bold text-(--cp-text-muted)">
<span>请求模型</span>
<span />
<span>上游模型</span>
@@ -43,9 +43,9 @@ const model = defineModel<RotationStrategy | ''>({ required: true })
:class="model === option.value ? 'bg-(--cp-info) opacity-100' : 'opacity-0'"
/>
</span>
<span class="text-[14px] leading-[1.15] font-[760]">{{ option.label }}</span>
<span class="text-[14px] leading-[1.15] font-heavy">{{ option.label }}</span>
</span>
<span class="mt-2 block text-[13px] leading-normal font-[650] text-(--cp-text-secondary)">
<span class="mt-2 block text-[13px] leading-normal font-emphasis text-(--cp-text-secondary)">
{{ option.description }}
</span>
</button>
@@ -65,7 +65,7 @@ function latencyDisplay(value: unknown) {
上游 {{ display(record.upstreamStatusCode) }}
</span>
</div>
<p class="mt-3 mb-0 text-[13px] leading-relaxed font-[680] text-(--cp-text-primary)">
<p class="mt-3 mb-0 text-[13px] leading-relaxed font-bold text-(--cp-text-primary)">
{{ display(record.message) }}
</p>
</section>
@@ -83,7 +83,7 @@ function latencyDisplay(value: unknown) {
{{ field.label }}
</dt>
<dd
class="mt-1.5 mb-0 truncate font-mono text-[12px] leading-normal font-[650] text-(--cp-text-primary)"
class="mt-1.5 mb-0 truncate font-mono text-[12px] leading-normal font-emphasis text-(--cp-text-primary)"
:title="display(field.value)"
>
{{ display(field.value) }}
@@ -95,7 +95,7 @@ function latencyDisplay(value: unknown) {
v-if="metadataText"
class="mt-3 rounded-(--cp-card-radius) bg-(--cp-bg-subtle) px-4 py-3.5"
>
<h3 class="m-0 text-[12px] leading-none font-[780] text-(--cp-text-secondary)">
<h3 class="m-0 text-[12px] leading-none font-heavy text-(--cp-text-secondary)">
Metadata
</h3>
<BaseScrollbar
@@ -94,7 +94,7 @@ function showDetail(record: Awaited<ReturnType<typeof getOpsErrors>>['items'][nu
/>
</template>
<template #failureClass="{ row }">
<span class="font-mono text-[12px] font-[680] text-(--cp-danger-text)">
<span class="font-mono text-[12px] font-bold text-(--cp-danger-text)">
{{ row.failureClass || '—' }}
</span>
</template>
@@ -50,7 +50,7 @@ function itemValueClass(tone?: string, accent?: boolean) {
<template>
<div class="flex items-center justify-end gap-1.5">
<span class="font-mono text-[12px] font-[760] tabular-nums text-(--cp-success-text)">
<span class="font-mono text-[12px] font-heavy tabular-nums text-(--cp-success-text)">
{{ usageBillingText(record) }}
</span>
@@ -58,7 +58,7 @@ function itemValueClass(tone?: string, accent?: boolean) {
<div class="grid gap-1.5 text-(--cp-text-secondary)">
<div v-for="item in amountItems" :key="item.label" class="flex justify-between gap-4">
<span>{{ item.label }}</span>
<span class="font-mono font-[760]" :class="itemValueClass(undefined, item.accent)">
<span class="font-mono font-heavy" :class="itemValueClass(undefined, item.accent)">
{{ item.value }}
</span>
</div>
@@ -66,7 +66,7 @@ function itemValueClass(tone?: string, accent?: boolean) {
<div class="mt-1 grid gap-1.5 rounded-(--cp-input-radius-base) bg-(--cp-bg-subtle) p-2 text-(--cp-text-secondary)">
<div v-for="item in billingItems" :key="item.label" class="flex justify-between gap-4">
<span>{{ item.label }}</span>
<span class="font-mono font-[760]" :class="itemValueClass(item.tone)">
<span class="font-mono font-heavy" :class="itemValueClass(item.tone)">
{{ item.value }}
</span>
</div>
@@ -8,7 +8,7 @@ defineProps<{
content: string
}>()
const panelTitleClass = 'm-0 text-[12px] leading-none font-[780] text-(--cp-text-secondary)'
const panelTitleClass = 'm-0 text-[12px] leading-none font-heavy text-(--cp-text-secondary)'
const codeBlockViewClass = 'rounded-(--cp-input-radius-base) bg-(--cp-bg-surface) px-3 py-2.5'
const codeBlockClass
= 'm-0 whitespace-pre-wrap wrap-break-word font-mono text-[12px] leading-[1.65] text-(--cp-text-primary)'
@@ -30,7 +30,7 @@ defineProps<{
</template>
<div class="grid gap-2 text-[12px] leading-none">
<p class="m-0 font-[760] text-(--cp-text-primary)">
<p class="m-0 font-heavy text-(--cp-text-primary)">
{{ title }}
</p>
<slot />
@@ -147,7 +147,7 @@ function diagnosticNameDisplay(name: string) {
<template #nameDisplay="{ row }">
<div class="inline-grid max-w-full min-w-0 gap-1" :title="row.nameDisplay.full">
<code
class="block max-w-full truncate font-mono text-[12px] leading-none font-[760] text-(--cp-text-primary)"
class="block max-w-full truncate font-mono text-[12px] leading-none font-heavy text-(--cp-text-primary)"
>
{{ row.nameDisplay.primary }}
</code>
@@ -172,10 +172,10 @@ function diagnosticNameDisplay(name: string) {
class="grid justify-items-end gap-1 font-mono leading-none tabular-nums"
:title="`成功 ${formatCompactNumber(row.successCount)}`"
>
<strong class="font-[720] text-(--cp-text-primary)">
<strong class="font-bold text-(--cp-text-primary)">
{{ formatCompactNumber(row.requestCount) }}
</strong>
<small class="text-[10px] font-[650] text-(--cp-text-muted)">
<small class="text-[10px] font-emphasis text-(--cp-text-muted)">
{{ formatPercent(row.requestShare) }}
</small>
</span>
@@ -184,13 +184,13 @@ function diagnosticNameDisplay(name: string) {
<template #errorCount="{ row }">
<span class="grid justify-items-end gap-1 font-mono leading-none tabular-nums">
<strong
class="font-[720]"
class="font-bold"
:class="row.errorCount > 0 ? 'text-(--cp-danger-text)' : 'text-(--cp-text-primary)'"
>
{{ formatCompactNumber(row.errorCount) }}
</strong>
<small
class="text-[10px] font-[650]"
class="text-[10px] font-emphasis"
:class="row.errorRate > 0 ? 'text-(--cp-danger-text)' : 'text-(--cp-text-muted)'"
>
{{ formatPercent(row.errorRate) }}
@@ -199,13 +199,13 @@ function diagnosticNameDisplay(name: string) {
</template>
<template #latencyP95Ms="{ row }">
<span class="font-mono font-[680] tabular-nums text-(--cp-warning-text)">
<span class="font-mono font-bold tabular-nums text-(--cp-warning-text)">
{{ formatDuration(row.latencyP95Ms) }}
</span>
</template>
<template #estimatedCost="{ row }">
<span class="font-mono font-[680] tabular-nums text-(--cp-success-text)">
<span class="font-mono font-bold tabular-nums text-(--cp-success-text)">
{{ formatUsd(row.estimatedCost) }}
</span>
</template>
@@ -15,7 +15,7 @@ const latencyDetails = computed(() => usageLatencyDetails(props.record))
<template>
<div class="flex items-center justify-end gap-1.5">
<div
class="grid grid-cols-[auto_auto] items-center justify-end gap-x-2 gap-y-1.5 font-mono text-[12px] leading-none font-[760] tabular-nums"
class="grid grid-cols-[auto_auto] items-center justify-end gap-x-2 gap-y-1.5 font-mono text-[12px] leading-none font-heavy tabular-nums"
>
<span class="text-[11px] text-(--cp-text-muted)">{{ latencyDetails.firstOutputLabel }}</span>
<span class="text-(--cp-text-secondary)">{{ latencyDetails.firstOutputDisplay }}</span>
@@ -34,7 +34,7 @@ const latencyDetails = computed(() => usageLatencyDetails(props.record))
class="flex justify-between gap-4"
>
<span class="whitespace-nowrap">{{ item.label }}</span>
<span class="whitespace-nowrap font-mono font-[760] text-(--cp-text-primary)">
<span class="whitespace-nowrap font-mono font-heavy text-(--cp-text-primary)">
{{ item.value }}
</span>
</div>
@@ -45,7 +45,7 @@ const latencyDetails = computed(() => usageLatencyDetails(props.record))
<div class="flex justify-between border-t border-(--cp-divider-subtle) pt-2">
<span class="whitespace-nowrap text-(--cp-text-secondary)">总耗时</span>
<span class="whitespace-nowrap font-mono font-[760] text-(--cp-info-text)">
<span class="whitespace-nowrap font-mono font-heavy text-(--cp-info-text)">
{{ latencyDetails.totalDisplay }}
</span>
</div>
@@ -54,7 +54,7 @@ const latencyDetails = computed(() => usageLatencyDetails(props.record))
v-if="latencyDetails.transportItems.length"
class="grid gap-1.5 border-t border-(--cp-divider-subtle) pt-2 text-(--cp-text-secondary)"
>
<p class="m-0 font-[760] text-(--cp-text-primary)">
<p class="m-0 font-heavy text-(--cp-text-primary)">
传输观测
</p>
<div
@@ -63,7 +63,7 @@ const latencyDetails = computed(() => usageLatencyDetails(props.record))
class="flex justify-between gap-4"
>
<span class="whitespace-nowrap">{{ item.label }}</span>
<span class="whitespace-nowrap font-mono font-[760] text-(--cp-text-primary)">
<span class="whitespace-nowrap font-mono font-heavy text-(--cp-text-primary)">
{{ item.value }}
</span>
</div>
@@ -15,7 +15,7 @@ const modelDisplay = computed(() => usageModelDisplay(props.record))
<template>
<div class="inline-grid max-w-full gap-1">
<code
class="block max-w-full truncate font-mono text-[12px] leading-none font-[760] text-(--cp-text-primary)"
class="block max-w-full truncate font-mono text-[12px] leading-none font-heavy text-(--cp-text-primary)"
>
{{ modelDisplay.primary }}
</code>
@@ -11,7 +11,7 @@ defineProps<{
<template>
<span
class="inline-flex items-center gap-1 whitespace-nowrap text-[12px] font-[720] text-(--cp-text-primary)"
class="inline-flex items-center gap-1 whitespace-nowrap text-[12px] font-bold text-(--cp-text-primary)"
>
<span>{{ usageReasoningEffort(record) }}</span>
<span
@@ -44,7 +44,7 @@ const billing = computed(() => props.record ? usageBilling(props.record) : null)
const latencyDetails = computed(() => props.record ? usageLatencyDetails(props.record) : null)
const panelClass = 'rounded-(--cp-card-radius) bg-(--cp-bg-subtle) px-4 py-3.5'
const panelTitleClass = 'm-0 text-[12px] leading-none font-[780] text-(--cp-text-secondary)'
const panelTitleClass = 'm-0 text-[12px] leading-none font-heavy text-(--cp-text-secondary)'
const accountDisplay = computed(() => props.record ? usageAccountText(props.record) : '—')
const overviewItems = computed(() => [
@@ -229,7 +229,7 @@ const tokenDonutOption = computed<EChartsOption>(() => {
<div class="min-w-0">
<span :class="fieldLabelClass">账号</span>
<p
class="mt-1.5 mb-0 truncate font-mono text-[13px] leading-none font-[760] text-(--cp-text-primary)"
class="mt-1.5 mb-0 truncate font-mono text-[13px] leading-none font-heavy text-(--cp-text-primary)"
:title="displayValue(accountDisplay)"
>
{{ displayValue(accountDisplay) }}
@@ -38,7 +38,7 @@ defineProps<{
<template #accountEmail="{ row }">
<span
class="block max-w-full truncate font-mono text-[12px] leading-none font-[720] text-(--cp-text-primary)"
class="block max-w-full truncate font-mono text-[12px] leading-none font-bold text-(--cp-text-primary)"
:title="usageAccountText(row)"
>
{{ usageAccountText(row) }}
@@ -59,7 +59,7 @@ defineProps<{
<template #route="{ row }">
<div class="inline-flex max-w-full items-center gap-1.5 whitespace-nowrap">
<code class="font-mono text-[12px] font-[650]">{{ row.route || '—' }}</code>
<code class="font-mono text-[12px] font-emphasis">{{ row.route || '—' }}</code>
<span
v-if="usageIsCompact(row)"
class="inline-flex shrink-0 text-(--cp-warning-text)"
@@ -75,7 +75,7 @@ const items = computed(() => [
>
{{ item.value }}
</strong>
<span class="block truncate text-[12px] leading-none font-[650] text-(--cp-text-secondary)">
<span class="block truncate text-[12px] leading-none font-emphasis text-(--cp-text-secondary)">
{{ item.detail }}
</span>
</div>
@@ -43,14 +43,14 @@ const tokenItems = computed(() => [
<div class="grid gap-1.5 text-(--cp-text-secondary)">
<div v-for="item in tokenItems" :key="item.label" class="flex justify-between gap-4">
<span class="whitespace-nowrap">{{ item.label }}</span>
<span class="whitespace-nowrap font-mono font-[760] text-(--cp-text-primary)">
<span class="whitespace-nowrap font-mono font-heavy text-(--cp-text-primary)">
{{ item.value }}
</span>
</div>
</div>
<div class="mt-1 flex justify-between border-t border-(--cp-divider-subtle) pt-2">
<span class="whitespace-nowrap text-(--cp-text-secondary)">总 Token</span>
<span class="whitespace-nowrap font-mono font-[760] text-(--cp-info-text)">
<span class="whitespace-nowrap font-mono font-heavy text-(--cp-info-text)">
{{ tokenDetails.totalTokensDisplay }}
</span>
</div>
+11 -11
View File
@@ -26,14 +26,14 @@ export const usageRecordColumns = [
label: '推理强度',
width: '98px',
ellipsis: false,
cellClass: 'whitespace-nowrap text-[12px] font-[700] text-(--cp-text-primary)',
cellClass: 'whitespace-nowrap text-[12px] font-bold text-(--cp-text-primary)',
},
{
key: 'route',
label: '端点',
width: '185px',
ellipsis: false,
cellClass: 'font-mono text-[12px] font-[650]',
cellClass: 'font-mono text-[12px] font-emphasis',
},
{
key: 'recordType',
@@ -69,7 +69,7 @@ export const usageRecordColumns = [
width: '190px',
ellipsis: false,
cellClass:
'whitespace-nowrap font-mono text-[12px] font-[650] tabular-nums text-(--cp-text-secondary)',
'whitespace-nowrap font-mono text-[12px] font-emphasis tabular-nums text-(--cp-text-secondary)',
},
{
key: 'clientIp',
@@ -83,7 +83,7 @@ export const usageRecordColumns = [
width: '340px',
ellipsis: false,
cellClass:
'whitespace-normal break-words text-[12px] leading-[1.45] font-[650] text-(--cp-text-secondary)',
'whitespace-normal break-words text-[12px] leading-[1.45] font-emphasis text-(--cp-text-secondary)',
},
{
key: 'actions',
@@ -101,44 +101,44 @@ export const opsErrorColumns = [
label: '时间',
width: '190px',
cellClass:
'whitespace-nowrap font-mono text-[12px] font-[650] tabular-nums text-(--cp-text-secondary)',
'whitespace-nowrap font-mono text-[12px] font-emphasis tabular-nums text-(--cp-text-secondary)',
},
{ key: 'upstreamStatusCode', label: '上游状态', width: '96px', align: 'center' as const },
{
key: 'failureClass',
label: '失败分类',
width: '170px',
cellClass: 'font-mono text-[12px] font-[650]',
cellClass: 'font-mono text-[12px] font-emphasis',
},
{
key: 'kind',
label: '事件',
width: '170px',
cellClass: 'font-mono text-[12px] font-[650]',
cellClass: 'font-mono text-[12px] font-emphasis',
},
{
key: 'route',
label: '端点',
width: '190px',
cellClass: 'font-mono text-[12px] font-[650]',
cellClass: 'font-mono text-[12px] font-emphasis',
},
{
key: 'model',
label: '模型',
width: '180px',
cellClass: 'font-mono text-[12px] font-[650]',
cellClass: 'font-mono text-[12px] font-emphasis',
},
{
key: 'accountId',
label: '账号 ID',
width: '230px',
cellClass: 'font-mono text-[12px] font-[650]',
cellClass: 'font-mono text-[12px] font-emphasis',
},
{
key: 'requestId',
label: '请求 ID',
width: '250px',
cellClass: 'font-mono text-[12px] font-[650]',
cellClass: 'font-mono text-[12px] font-emphasis',
},
{ key: 'message', label: '消息', minWidth: '300px', flex: 1 },
{
+2 -2
View File
@@ -87,11 +87,11 @@ watch(timeRange, () => {
<template #header>
<div class="flex flex-wrap items-center justify-between gap-3">
<div>
<h2 class="m-0 text-xl leading-[1.15] font-[760] text-(--cp-text-primary)">
<h2 class="m-0 text-xl leading-[1.15] font-heavy text-(--cp-text-primary)">
请求明细
</h2>
<p
class="mt-1.75 mb-0 text-[13px] leading-[1.15] font-[650] text-(--cp-text-secondary)"
class="mt-1.75 mb-0 text-[13px] leading-[1.15] font-emphasis text-(--cp-text-secondary)"
>
成功请求与失败请求明细
</p>
+1 -1
View File
@@ -1,7 +1,7 @@
// 详情弹窗共享的字段展示约定:占位符、标签/值样式,供弹窗与其子组件复用。
export const fieldLabelClass = 'text-[11px] leading-none font-bold text-(--cp-text-muted)'
export const fieldValueBaseClass
= 'mt-1.5 mb-0 min-w-0 truncate text-[12px] leading-none font-[700] text-(--cp-text-primary)'
= 'mt-1.5 mb-0 min-w-0 truncate text-[12px] leading-none font-bold text-(--cp-text-primary)'
export function displayValue(value: unknown) {
if (value === undefined || value === null || value === '')