mirror of
https://github.com/zyycn/codex-proxy-rs.git
synced 2026-11-06 08:06:19 +00:00
fix(theme): restore semantic color roles
Separate semantic text on neutral surfaces from high-contrast text on tinted backgrounds, derive each role against its actual surfaces, and migrate badges and alerts to explicit on-background tokens. Restore vivid usage-table accents and align input hover, active, and error outlines across light and dark themes. Validated with semantic contrast checks across presets and custom seeds, frontend typecheck, lint and production build. Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
@@ -35,7 +35,7 @@ const variantClasses: Record<ButtonVariant, string> = {
|
||||
'bg-cp-fill-tertiary text-cp-text shadow-cp-tertiary hover:bg-cp-bg-text-active active:bg-cp-bg-text-active',
|
||||
ghost:
|
||||
'bg-transparent text-cp-text-secondary shadow-none hover:bg-cp-fill-quaternary hover:text-cp-text active:bg-cp-fill-tertiary',
|
||||
destructive: 'bg-cp-error-bg text-cp-error-text shadow-none hover:bg-cp-error-bg-hover active:bg-cp-error-bg-active',
|
||||
destructive: 'bg-cp-error-bg text-cp-error-text-on-bg shadow-none hover:bg-cp-error-bg-hover active:bg-cp-error-bg-active',
|
||||
}
|
||||
|
||||
const sizeClasses: Record<ButtonSize, string> = {
|
||||
|
||||
@@ -36,10 +36,10 @@ const variantClasses: Record<IconButtonVariant, string> = {
|
||||
secondary:
|
||||
'bg-cp-bg-container text-cp-text-secondary shadow-cp-tertiary hover:bg-cp-bg-text-hover hover:text-cp-text active:bg-cp-bg-text-active',
|
||||
success:
|
||||
'bg-cp-success-bg text-cp-success-text shadow-none hover:bg-cp-success-bg-hover active:bg-cp-success-bg-active',
|
||||
'bg-cp-success-bg text-cp-success-text-on-bg shadow-none hover:bg-cp-success-bg-hover active:bg-cp-success-bg-active',
|
||||
ghost:
|
||||
'bg-transparent text-cp-text-secondary shadow-none hover:bg-cp-fill-quaternary hover:text-cp-text active:bg-cp-fill-tertiary',
|
||||
destructive: 'bg-transparent text-cp-error-text shadow-none hover:bg-cp-error-bg-hover active:bg-cp-error-bg-active',
|
||||
destructive: 'bg-transparent text-cp-error-text shadow-none hover:bg-cp-error-bg-hover hover:text-cp-error-text-on-bg active:bg-cp-error-bg-active active:text-cp-error-text-on-bg',
|
||||
}
|
||||
|
||||
const sizeClasses: Record<IconButtonSize, string> = {
|
||||
|
||||
@@ -26,7 +26,7 @@ const classes = computed(() => [
|
||||
'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-cp-control-outline',
|
||||
'disabled:cursor-not-allowed disabled:text-cp-text-disabled',
|
||||
props.tone === 'destructive'
|
||||
? 'text-cp-error-text hover:bg-cp-error-bg-hover'
|
||||
? 'text-cp-error-text hover:bg-cp-error-bg-hover hover:text-cp-error-text-on-bg'
|
||||
: 'text-cp-text hover:bg-cp-bg-text-hover',
|
||||
])
|
||||
</script>
|
||||
|
||||
@@ -98,7 +98,7 @@ const triggerClasses = computed(() => [
|
||||
props.disabled
|
||||
? 'cursor-not-allowed bg-cp-bg-container-disabled text-cp-text-disabled shadow-none'
|
||||
: invalid.value
|
||||
? 'cursor-pointer bg-(--cp-input-error-active-bg) text-cp-error-text shadow-cp-input-error-active'
|
||||
? 'cursor-pointer bg-(--cp-input-error-active-bg) text-cp-error-text-on-bg shadow-cp-input-error-active'
|
||||
: open.value
|
||||
? 'cursor-pointer bg-(--cp-input-active-bg) text-cp-text shadow-cp-input-active'
|
||||
: [
|
||||
|
||||
@@ -342,7 +342,7 @@ onBeforeUnmount(() => {
|
||||
class="inline-flex h-4.5 min-w-0 cursor-pointer items-center gap-1 rounded-cp-sm 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-control-outline focus-visible:ring-offset-2 focus-visible:ring-offset-cp-bg-container"
|
||||
:class="[
|
||||
hasUpdate
|
||||
? 'bg-cp-success-bg text-cp-success-text hover:bg-cp-success-bg-hover'
|
||||
? 'bg-cp-success-bg text-cp-success-text-on-bg hover:bg-cp-success-bg-hover'
|
||||
: 'bg-cp-fill-quaternary text-cp-text-quaternary hover:bg-cp-fill-tertiary hover:text-cp-text-secondary',
|
||||
]"
|
||||
:title="updateButtonLabel"
|
||||
@@ -399,7 +399,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-emphasis 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-on-bg"
|
||||
>
|
||||
<i class="size-1.5 rounded-full bg-cp-success" />
|
||||
在线
|
||||
|
||||
@@ -257,7 +257,7 @@ watch(
|
||||
|
||||
<p
|
||||
v-if="updateError || updateInfo?.warning"
|
||||
class="m-0 rounded-cp bg-cp-error-bg px-3 py-2 text-cp-sm leading-normal font-bold text-cp-error-text"
|
||||
class="m-0 rounded-cp bg-cp-error-bg px-3 py-2 text-cp-sm leading-normal font-bold text-cp-error-text-on-bg"
|
||||
>
|
||||
{{ updateError || updateInfo?.warning }}
|
||||
</p>
|
||||
|
||||
@@ -47,7 +47,7 @@ function resolveStatus(input: SystemUpdatePresentationInput) {
|
||||
return {
|
||||
label: input.restarting ? '重启中' : '更新中',
|
||||
icon: RefreshCw,
|
||||
badge: 'bg-cp-info-bg text-cp-info-text',
|
||||
badge: 'bg-cp-info-bg text-cp-info-text-on-bg',
|
||||
iconClass: 'text-cp-info',
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,7 @@ function resolveStatus(input: SystemUpdatePresentationInput) {
|
||||
return {
|
||||
label: '异常',
|
||||
icon: XCircle,
|
||||
badge: 'bg-cp-error-bg text-cp-error-text',
|
||||
badge: 'bg-cp-error-bg text-cp-error-text-on-bg',
|
||||
iconClass: 'text-cp-error',
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,7 @@ function resolveStatus(input: SystemUpdatePresentationInput) {
|
||||
return {
|
||||
label: input.updateSuccess ? '已更新' : input.hasUpdate ? '有新版本' : '已是最新',
|
||||
icon: input.hasUpdate ? ArrowUpCircle : CheckCircle2,
|
||||
badge: 'bg-cp-success-bg text-cp-success-text',
|
||||
badge: 'bg-cp-success-bg text-cp-success-text-on-bg',
|
||||
iconClass: 'text-cp-success',
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
--color-cp-info-active: var(--cp-color-info-active);
|
||||
--color-cp-info-text-hover: var(--cp-color-info-text-hover);
|
||||
--color-cp-info-text: var(--cp-color-info-text);
|
||||
--color-cp-info-text-on-bg: var(--cp-color-info-text-on-bg);
|
||||
--color-cp-info-text-active: var(--cp-color-info-text-active);
|
||||
--color-cp-success-bg: var(--cp-color-success-bg);
|
||||
--color-cp-success-bg-hover: var(--cp-color-success-bg-hover);
|
||||
@@ -83,6 +84,7 @@
|
||||
--color-cp-success-active: var(--cp-color-success-active);
|
||||
--color-cp-success-text-hover: var(--cp-color-success-text-hover);
|
||||
--color-cp-success-text: var(--cp-color-success-text);
|
||||
--color-cp-success-text-on-bg: var(--cp-color-success-text-on-bg);
|
||||
--color-cp-success-text-active: var(--cp-color-success-text-active);
|
||||
--color-cp-warning-bg: var(--cp-color-warning-bg);
|
||||
--color-cp-warning-bg-hover: var(--cp-color-warning-bg-hover);
|
||||
@@ -94,6 +96,7 @@
|
||||
--color-cp-warning-active: var(--cp-color-warning-active);
|
||||
--color-cp-warning-text-hover: var(--cp-color-warning-text-hover);
|
||||
--color-cp-warning-text: var(--cp-color-warning-text);
|
||||
--color-cp-warning-text-on-bg: var(--cp-color-warning-text-on-bg);
|
||||
--color-cp-warning-text-active: var(--cp-color-warning-text-active);
|
||||
--color-cp-error-bg: var(--cp-color-error-bg);
|
||||
--color-cp-error-bg-hover: var(--cp-color-error-bg-hover);
|
||||
@@ -105,6 +108,7 @@
|
||||
--color-cp-error-active: var(--cp-color-error-active);
|
||||
--color-cp-error-text-hover: var(--cp-color-error-text-hover);
|
||||
--color-cp-error-text: var(--cp-color-error-text);
|
||||
--color-cp-error-text-on-bg: var(--cp-color-error-text-on-bg);
|
||||
--color-cp-error-text-active: var(--cp-color-error-text-active);
|
||||
|
||||
/* 颜色 · 预设(色系按字母排序,角色顺序固定) */
|
||||
|
||||
@@ -100,7 +100,7 @@ function deriveThemeMap(
|
||||
const aliases = deriveThemeAliasMap(surfaces)
|
||||
const primary = deriveThemePrimaryMap(seed, name, surfaces.colorBgContainer)
|
||||
const link = deriveThemeLinkMap(seedTokens.colorLink, name, surfaces.colorBgContainer)
|
||||
const semantics = deriveThemeSemanticMap(name, surfaces.colorBgContainer, seedTokens)
|
||||
const semantics = deriveThemeSemanticMap(name, surfaces, seedTokens)
|
||||
|
||||
return {
|
||||
surfaces,
|
||||
|
||||
@@ -38,6 +38,7 @@ const FUNCTIONAL_TOKEN_ROLES = [
|
||||
['active', '-active'],
|
||||
['textHover', '-text-hover'],
|
||||
['text', '-text'],
|
||||
['textOnBackground', '-text-on-bg'],
|
||||
['textActive', '-text-active'],
|
||||
] as const satisfies readonly (readonly [keyof FunctionalColorMap, FunctionalTokenSuffix])[]
|
||||
|
||||
|
||||
@@ -133,16 +133,51 @@ export function deriveThemeLinkMap(
|
||||
|
||||
export function deriveThemeSemanticMap(
|
||||
theme: ThemeName,
|
||||
containerBg: string,
|
||||
surfaces: ThemeSurfaceMap,
|
||||
seedTokens: ResolvedThemeSeedTokens,
|
||||
): ThemeSemanticMap {
|
||||
const recipe = THEME_COLOR_ROLE_RECIPES[theme].semantic
|
||||
const containerBg = surfaces.colorBgContainer
|
||||
const textBackgrounds = [
|
||||
surfaces.colorBgLayout,
|
||||
surfaces.colorBgContainer,
|
||||
surfaces.colorBgElevated,
|
||||
surfaces.colorBgTextHover,
|
||||
surfaces.colorBgTextActive,
|
||||
surfaces.colorFillSecondary,
|
||||
surfaces.colorFillTertiary,
|
||||
surfaces.colorFillQuaternary,
|
||||
]
|
||||
|
||||
return {
|
||||
info: deriveColorRoleMap(seedTokens.colorInfo, theme, containerBg, recipe),
|
||||
success: deriveColorRoleMap(seedTokens.colorSuccess, theme, containerBg, recipe),
|
||||
warning: deriveColorRoleMap(seedTokens.colorWarning, theme, containerBg, recipe),
|
||||
error: deriveColorRoleMap(seedTokens.colorError, theme, containerBg, recipe),
|
||||
info: deriveColorRoleMap(
|
||||
seedTokens.colorInfo,
|
||||
theme,
|
||||
containerBg,
|
||||
recipe,
|
||||
textBackgrounds,
|
||||
),
|
||||
success: deriveColorRoleMap(
|
||||
seedTokens.colorSuccess,
|
||||
theme,
|
||||
containerBg,
|
||||
recipe,
|
||||
textBackgrounds,
|
||||
),
|
||||
warning: deriveColorRoleMap(
|
||||
seedTokens.colorWarning,
|
||||
theme,
|
||||
containerBg,
|
||||
recipe,
|
||||
textBackgrounds,
|
||||
),
|
||||
error: deriveColorRoleMap(
|
||||
seedTokens.colorError,
|
||||
theme,
|
||||
containerBg,
|
||||
recipe,
|
||||
textBackgrounds,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,6 +444,7 @@ function deriveColorRoleMap(
|
||||
theme: ThemeName,
|
||||
containerBg: string,
|
||||
recipe: ThemeColorRoleRecipe,
|
||||
textBackgrounds: string | readonly string[] = containerBg,
|
||||
): FunctionalColorMap {
|
||||
const normalizedSeed = normalizeHexColor(seed) ?? DEFAULT_CUSTOM_THEME_COLOR
|
||||
const palette = generateColorPalette(normalizedSeed, theme, containerBg)
|
||||
@@ -421,13 +457,16 @@ function deriveColorRoleMap(
|
||||
const background = mix(containerBg, color, recipe.backgroundMix)
|
||||
const backgroundHover = mix(containerBg, hover, recipe.backgroundHoverMix)
|
||||
const backgroundActive = mix(containerBg, active, recipe.backgroundActiveMix)
|
||||
const textBackgrounds = [containerBg, background, backgroundHover, backgroundActive]
|
||||
const resolveText = (source: ThemePaletteSource): string => {
|
||||
const semanticBackgrounds = [background, backgroundHover, backgroundActive]
|
||||
const resolveText = (
|
||||
source: ThemePaletteSource,
|
||||
backgrounds: string | readonly string[] = textBackgrounds,
|
||||
): string => {
|
||||
const value = resolve(source)
|
||||
const toned = recipe.minimumTextLightness === undefined
|
||||
? value
|
||||
: ensureLightness(value, recipe.minimumTextLightness)
|
||||
return ensureContrast(toned, textBackgrounds, 4.5)
|
||||
return ensureContrast(toned, backgrounds, 4.5)
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -445,6 +484,10 @@ function deriveColorRoleMap(
|
||||
: ensureContrast(active, containerBg, recipe.activeContrast),
|
||||
textHover: resolveText(recipe.textHover),
|
||||
text: resolveText(recipe.text),
|
||||
textOnBackground: resolveText(
|
||||
recipe.textOnBackground ?? recipe.text,
|
||||
semanticBackgrounds,
|
||||
),
|
||||
textActive: resolveText(recipe.textActive),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,8 +184,8 @@ function deriveDarkComponentMap(
|
||||
`0 0 0 3px ${inputOutlineColor}, 0 14px 28px -22px ${withAlpha(BLACK, 0.72)}`,
|
||||
shadowStrength,
|
||||
),
|
||||
inputActiveShadow: '0 0 0 3px var(--cp-control-outline)',
|
||||
inputErrorActiveShadow: `0 0 0 3px ${error.border}`,
|
||||
inputActiveShadow: `0 0 0 3px ${inputOutlineColor}`,
|
||||
inputErrorActiveShadow: `0 0 0 3px ${withAlpha(error.color, 0.28)}`,
|
||||
layoutSiderShadow: scaleShadowAlpha(`2px 0 18px -14px ${withAlpha(BLACK, 0.72)}`, shadowStrength),
|
||||
scrollbarThumbBg: mix(surfaces.colorBorderSecondary, surfaces.colorTextSecondary, 0.16),
|
||||
scrollbarThumbHoverBg: mix(surfaces.colorBorderSecondary, surfaces.colorTextSecondary, 0.3),
|
||||
@@ -237,8 +237,8 @@ function deriveLightComponentMap(
|
||||
`0 0 0 3px ${inputOutlineColor}, 0 12px 24px -16px ${withAlpha(LIGHT_SHADOW_BASE, 0.12)}`,
|
||||
shadowStrength,
|
||||
),
|
||||
inputActiveShadow: '0 0 0 3px var(--cp-control-outline)',
|
||||
inputErrorActiveShadow: `0 0 0 3px ${error.border}`,
|
||||
inputActiveShadow: `0 0 0 3px ${inputOutlineColor}`,
|
||||
inputErrorActiveShadow: `0 0 0 3px ${withAlpha(error.color, 0.18)}`,
|
||||
layoutSiderShadow: scaleShadowAlpha(`2px 0 12px -12px ${withAlpha(LIGHT_SHADOW_BASE, 0.027)}`, shadowStrength),
|
||||
scrollbarThumbBg: mix(surfaces.colorBgLayout, surfaces.colorTextSecondary, 0.2),
|
||||
scrollbarThumbHoverBg: mix(surfaces.colorBgLayout, surfaces.colorTextSecondary, 0.34),
|
||||
|
||||
@@ -24,7 +24,8 @@ export const THEME_COLOR_ROLE_RECIPES = {
|
||||
hover: 5,
|
||||
active: 7,
|
||||
textHover: 5,
|
||||
text: 6,
|
||||
text: 7,
|
||||
textOnBackground: 6,
|
||||
textActive: 7,
|
||||
backgroundMix: 0.08,
|
||||
backgroundHoverMix: 0.12,
|
||||
@@ -62,7 +63,8 @@ export const THEME_COLOR_ROLE_RECIPES = {
|
||||
hover: 8,
|
||||
active: 6,
|
||||
textHover: 8,
|
||||
text: 9,
|
||||
text: 7,
|
||||
textOnBackground: 9,
|
||||
textActive: 10,
|
||||
backgroundMix: 0.18,
|
||||
backgroundHoverMix: 0.24,
|
||||
|
||||
@@ -90,6 +90,7 @@ export interface ThemeColorRoleRecipe {
|
||||
active: ThemePaletteSource
|
||||
textHover: ThemePaletteSource
|
||||
text: ThemePaletteSource
|
||||
textOnBackground?: ThemePaletteSource
|
||||
textActive: ThemePaletteSource
|
||||
backgroundMix: number
|
||||
backgroundHoverMix: number
|
||||
@@ -211,7 +212,10 @@ export interface FunctionalColorMap {
|
||||
border: string
|
||||
borderHover: string
|
||||
textHover: string
|
||||
/** 语义色在中性表面上的强调文字。 */
|
||||
text: string
|
||||
/** 语义色在自身背景上的高对比文字。 */
|
||||
textOnBackground: string
|
||||
textActive: string
|
||||
}
|
||||
|
||||
@@ -308,6 +312,7 @@ export type FunctionalTokenSuffix
|
||||
| '-border-hover'
|
||||
| '-text-hover'
|
||||
| '-text'
|
||||
| '-text-on-bg'
|
||||
| '-text-active'
|
||||
|
||||
type SemanticColorName = Extract<keyof ThemeSemanticMap, string>
|
||||
|
||||
@@ -121,7 +121,7 @@ const { allSelected, indeterminate, selectedRowKeys, toggleSelection, toggleAll
|
||||
<span
|
||||
class="inline-flex h-6 items-center rounded-lg px-2 text-cp-xs font-bold"
|
||||
:class="row.enabled
|
||||
? 'bg-cp-success-bg text-cp-success-text'
|
||||
? 'bg-cp-success-bg text-cp-success-text-on-bg'
|
||||
: 'bg-cp-fill-tertiary text-cp-text-quaternary'"
|
||||
>
|
||||
{{ row.enabled ? '已启用' : '已禁用' }}
|
||||
|
||||
@@ -50,7 +50,7 @@ function overviewIconClass(tone: string) {
|
||||
return 'bg-cp-orange-bg text-cp-orange-text-on-bg'
|
||||
}
|
||||
if (tone === 'danger') {
|
||||
return 'bg-cp-error-bg text-cp-error-text'
|
||||
return 'bg-cp-error-bg text-cp-error-text-on-bg'
|
||||
}
|
||||
return 'bg-cp-blue-bg text-cp-blue-text-on-bg'
|
||||
}
|
||||
|
||||
@@ -140,9 +140,9 @@ async function handleConfirmConsume() {
|
||||
|
||||
<div v-else class="grid gap-4">
|
||||
<section v-if="ambiguous" class="flex items-start gap-3 rounded-cp bg-cp-warning-bg px-4 py-3.5" role="status">
|
||||
<AlertTriangle class="mt-0.5 size-4 shrink-0 text-cp-warning-text" />
|
||||
<AlertTriangle class="mt-0.5 size-4 shrink-0 text-cp-warning-text-on-bg" />
|
||||
<div class="min-w-0">
|
||||
<p class="m-0 text-cp-sm font-heavy text-cp-warning-text">
|
||||
<p class="m-0 text-cp-sm font-heavy text-cp-warning-text-on-bg">
|
||||
上次操作结果待确认
|
||||
</p>
|
||||
<p class="mt-1 mb-0 text-cp-xs leading-normal font-emphasis text-cp-text-secondary">
|
||||
@@ -193,7 +193,7 @@ async function handleConfirmConsume() {
|
||||
|
||||
<p
|
||||
v-if="loadError"
|
||||
class="m-0 rounded-cp bg-cp-error-bg px-4 py-3 text-cp-xs leading-normal font-emphasis text-cp-error-text"
|
||||
class="m-0 rounded-cp bg-cp-error-bg px-4 py-3 text-cp-xs leading-normal font-emphasis text-cp-error-text-on-bg"
|
||||
role="status"
|
||||
>
|
||||
{{ loadError }},请刷新重试。
|
||||
|
||||
@@ -53,26 +53,26 @@ const statusStyles: Record<AccountStatusTone, AccountStatusStyle> = {
|
||||
success: {
|
||||
text: 'text-cp-success-text',
|
||||
dot: 'bg-cp-success',
|
||||
badge: 'bg-cp-success-bg text-cp-success-text',
|
||||
icon: 'bg-cp-success-bg text-cp-success-text',
|
||||
badge: 'bg-cp-success-bg text-cp-success-text-on-bg',
|
||||
icon: 'bg-cp-success-bg text-cp-success-text-on-bg',
|
||||
},
|
||||
danger: {
|
||||
text: 'text-cp-error-text',
|
||||
dot: 'bg-cp-error',
|
||||
badge: 'bg-cp-error-bg text-cp-error-text',
|
||||
icon: 'bg-cp-error-bg text-cp-error-text',
|
||||
badge: 'bg-cp-error-bg text-cp-error-text-on-bg',
|
||||
icon: 'bg-cp-error-bg text-cp-error-text-on-bg',
|
||||
},
|
||||
warning: {
|
||||
text: 'text-cp-warning-text',
|
||||
dot: 'bg-cp-warning',
|
||||
badge: 'bg-cp-warning-bg text-cp-warning-text',
|
||||
icon: 'bg-cp-warning-bg text-cp-warning-text',
|
||||
badge: 'bg-cp-warning-bg text-cp-warning-text-on-bg',
|
||||
icon: 'bg-cp-warning-bg text-cp-warning-text-on-bg',
|
||||
},
|
||||
info: {
|
||||
text: 'text-cp-info-text',
|
||||
dot: 'bg-cp-info',
|
||||
badge: 'bg-cp-info-bg text-cp-info-text',
|
||||
icon: 'bg-cp-info-bg text-cp-info-text',
|
||||
badge: 'bg-cp-info-bg text-cp-info-text-on-bg',
|
||||
icon: 'bg-cp-info-bg text-cp-info-text-on-bg',
|
||||
},
|
||||
normal: {
|
||||
text: 'text-cp-text-secondary',
|
||||
|
||||
@@ -191,7 +191,7 @@ export function useAccountConnectionTest(options: { reload: () => Promise<unknow
|
||||
label: '正在测试',
|
||||
description: '正在向所选模型发送请求并接收流式响应',
|
||||
icon: Clock3,
|
||||
badge: 'bg-cp-info-bg text-cp-info-text',
|
||||
badge: 'bg-cp-info-bg text-cp-info-text-on-bg',
|
||||
iconClass: 'text-cp-info',
|
||||
}
|
||||
}
|
||||
@@ -200,7 +200,7 @@ export function useAccountConnectionTest(options: { reload: () => Promise<unknow
|
||||
label: '连接正常',
|
||||
description: '请求已完成,可在下方查看模型、耗时和事件轨迹',
|
||||
icon: CheckCircle2,
|
||||
badge: 'bg-cp-success-bg text-cp-success-text',
|
||||
badge: 'bg-cp-success-bg text-cp-success-text-on-bg',
|
||||
iconClass: 'text-cp-success',
|
||||
}
|
||||
}
|
||||
@@ -209,7 +209,7 @@ export function useAccountConnectionTest(options: { reload: () => Promise<unknow
|
||||
label: '测试失败',
|
||||
description: '请求未完成,请在下方查看失败来源与原始诊断',
|
||||
icon: XCircle,
|
||||
badge: 'bg-cp-error-bg text-cp-error-text',
|
||||
badge: 'bg-cp-error-bg text-cp-error-text-on-bg',
|
||||
iconClass: 'text-cp-error',
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ const title = computed(() => props.editing ? '编辑 API Key' : '创建 API Key'
|
||||
>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="rounded-cp border border-cp-warning-border bg-cp-warning-bg px-4 py-3">
|
||||
<p class="m-0 text-cp font-semibold text-cp-warning-text">
|
||||
<p class="m-0 text-cp font-semibold text-cp-warning-text-on-bg">
|
||||
该密钥具有网关访问权限,请仅发送给可信调用方
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@ defineProps<{
|
||||
<template>
|
||||
<div class="grid w-full justify-items-center gap-1.5">
|
||||
<div v-if="apiKey.routingScope === 'all'" class="flex items-center justify-center gap-2">
|
||||
<span class="inline-flex h-6 items-center rounded-lg bg-cp-warning-bg px-2 text-cp-xs font-bold text-cp-warning-text">
|
||||
<span class="inline-flex h-6 items-center rounded-lg bg-cp-warning-bg px-2 text-cp-xs font-bold text-cp-warning-text-on-bg">
|
||||
全部账号权限
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,7 @@ defineProps<{
|
||||
<span
|
||||
class="inline-flex h-6 min-w-14 items-center justify-center rounded-full px-2 text-cp-sm leading-none font-bold"
|
||||
:class="{
|
||||
'bg-cp-success-bg text-cp-success-text': apiKey.enabled,
|
||||
'bg-cp-success-bg text-cp-success-text-on-bg': apiKey.enabled,
|
||||
'bg-cp-fill-quaternary text-cp-text-secondary': !apiKey.enabled,
|
||||
}"
|
||||
>
|
||||
|
||||
@@ -75,7 +75,7 @@ const releaseStatus = computed(() => {
|
||||
return {
|
||||
label: '当前生效',
|
||||
title: '当前 Provider 请求正在使用此运行时画像',
|
||||
tone: 'bg-cp-info-bg text-cp-info-text',
|
||||
tone: 'bg-cp-info-bg text-cp-info-text-on-bg',
|
||||
icon: ShieldCheck,
|
||||
}
|
||||
}
|
||||
@@ -85,7 +85,7 @@ const releaseStatus = computed(() => {
|
||||
return {
|
||||
label: '制品一致',
|
||||
title: '当前生效版本与官方最新发布一致',
|
||||
tone: 'bg-cp-success-bg text-cp-success-text',
|
||||
tone: 'bg-cp-success-bg text-cp-success-text-on-bg',
|
||||
icon: CheckCircle2,
|
||||
}
|
||||
}
|
||||
@@ -93,7 +93,7 @@ const releaseStatus = computed(() => {
|
||||
return {
|
||||
label: '发现新版',
|
||||
title: `官方最新版本 ${releaseLabel.value}`,
|
||||
tone: 'bg-cp-warning-bg text-cp-warning-text',
|
||||
tone: 'bg-cp-warning-bg text-cp-warning-text-on-bg',
|
||||
icon: TriangleAlert,
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ const releaseStatus = computed(() => {
|
||||
return {
|
||||
label: '检查失败',
|
||||
title: current.release.error || '官方版本检查失败',
|
||||
tone: 'bg-cp-error-bg text-cp-error-text',
|
||||
tone: 'bg-cp-error-bg text-cp-error-text-on-bg',
|
||||
icon: TriangleAlert,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ export const metricToneIconClasses: Record<MetricTone, string> = {
|
||||
info: 'bg-cp-blue-bg text-cp-blue-text-on-bg',
|
||||
success: 'bg-cp-green-bg text-cp-green-text-on-bg',
|
||||
warning: 'bg-cp-orange-bg text-cp-orange-text-on-bg',
|
||||
danger: 'bg-cp-error-bg text-cp-error-text',
|
||||
danger: 'bg-cp-error-bg text-cp-error-text-on-bg',
|
||||
}
|
||||
|
||||
export const metricToneValueClasses: Record<MetricTone, string> = {
|
||||
@@ -71,12 +71,12 @@ export const healthStatusMeta: Record<HealthStatus, HealthStatusMeta> = {
|
||||
unavailable: {
|
||||
label: '不可达',
|
||||
cellClass: 'bg-cp-error',
|
||||
badgeClass: 'bg-cp-error-bg text-cp-error-text',
|
||||
badgeClass: 'bg-cp-error-bg text-cp-error-text-on-bg',
|
||||
},
|
||||
unstable: {
|
||||
label: '不稳定',
|
||||
cellClass: 'bg-cp-warning',
|
||||
badgeClass: 'bg-cp-warning-bg text-cp-warning-text',
|
||||
badgeClass: 'bg-cp-warning-bg text-cp-warning-text-on-bg',
|
||||
},
|
||||
low_sample: {
|
||||
label: '低样本',
|
||||
@@ -86,7 +86,7 @@ export const healthStatusMeta: Record<HealthStatus, HealthStatusMeta> = {
|
||||
stable: {
|
||||
label: '稳定',
|
||||
cellClass: 'bg-cp-success',
|
||||
badgeClass: 'bg-cp-success-bg text-cp-success-text',
|
||||
badgeClass: 'bg-cp-success-bg text-cp-success-text-on-bg',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -92,14 +92,14 @@ function formatFileSize(value: number | null): string {
|
||||
|
||||
<p
|
||||
v-if="downloads?.warning"
|
||||
class="m-0 rounded-cp bg-cp-warning-bg px-3 py-2.5 text-cp-sm leading-[1.45] font-bold text-cp-warning-text"
|
||||
class="m-0 rounded-cp bg-cp-warning-bg px-3 py-2.5 text-cp-sm leading-[1.45] font-bold text-cp-warning-text-on-bg"
|
||||
>
|
||||
{{ downloads.warning }}
|
||||
</p>
|
||||
|
||||
<p
|
||||
v-if="error && downloads"
|
||||
class="m-0 rounded-cp bg-cp-error-bg px-3 py-2.5 text-cp-sm leading-[1.45] font-bold text-cp-error-text"
|
||||
class="m-0 rounded-cp bg-cp-error-bg px-3 py-2.5 text-cp-sm leading-[1.45] font-bold text-cp-error-text-on-bg"
|
||||
role="alert"
|
||||
>
|
||||
{{ error }},当前仍显示上次成功结果。
|
||||
|
||||
@@ -112,11 +112,11 @@ const pagination: BaseTablePaginationState = {
|
||||
|
||||
function statusClass(status: PreviewTableRow['status']) {
|
||||
if (status === '正常')
|
||||
return 'bg-cp-success-bg text-cp-success-text'
|
||||
return 'bg-cp-success-bg text-cp-success-text-on-bg'
|
||||
if (status === '限流')
|
||||
return 'bg-cp-warning-bg text-cp-warning-text'
|
||||
return 'bg-cp-warning-bg text-cp-warning-text-on-bg'
|
||||
if (status === '异常')
|
||||
return 'bg-cp-error-bg text-cp-error-text'
|
||||
return 'bg-cp-error-bg text-cp-error-text-on-bg'
|
||||
return 'bg-cp-fill-tertiary text-cp-text-secondary'
|
||||
}
|
||||
</script>
|
||||
@@ -300,16 +300,16 @@ function statusClass(status: PreviewTableRow['status']) {
|
||||
<BaseCard padding="compact" class="col-span-4 h-full min-w-0 bg-cp-fill-quaternary! shadow-none!" title="反馈语义" description="Success · Warning · Error · Info">
|
||||
<template #body>
|
||||
<div class="grid gap-2.5">
|
||||
<div class="flex items-center gap-3 rounded-cp bg-cp-success-bg px-3.5 py-3 text-cp-success-text">
|
||||
<div class="flex items-center gap-3 rounded-cp bg-cp-success-bg px-3.5 py-3 text-cp-success-text-on-bg">
|
||||
<Check class="size-4 shrink-0" /><strong class="text-cp-sm">主题设置已保存</strong>
|
||||
</div>
|
||||
<div class="flex items-center gap-3 rounded-cp bg-cp-warning-bg px-3.5 py-3 text-cp-warning-text">
|
||||
<div class="flex items-center gap-3 rounded-cp bg-cp-warning-bg px-3.5 py-3 text-cp-warning-text-on-bg">
|
||||
<TriangleAlert class="size-4 shrink-0" /><strong class="text-cp-sm">3 个账号额度接近上限</strong>
|
||||
</div>
|
||||
<div class="flex items-center gap-3 rounded-cp bg-cp-error-bg px-3.5 py-3 text-cp-error-text">
|
||||
<div class="flex items-center gap-3 rounded-cp bg-cp-error-bg px-3.5 py-3 text-cp-error-text-on-bg">
|
||||
<CircleAlert class="size-4 shrink-0" /><strong class="text-cp-sm">连接测试未通过</strong>
|
||||
</div>
|
||||
<div class="flex items-center gap-3 rounded-cp bg-cp-info-bg px-3.5 py-3 text-cp-info-text">
|
||||
<div class="flex items-center gap-3 rounded-cp bg-cp-info-bg px-3.5 py-3 text-cp-info-text-on-bg">
|
||||
<Info class="size-4 shrink-0" /><strong class="text-cp-sm">调度规则将在下次请求生效</strong>
|
||||
</div>
|
||||
</div>
|
||||
@@ -320,10 +320,10 @@ function statusClass(status: PreviewTableRow['status']) {
|
||||
<template #body>
|
||||
<div class="grid gap-4">
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<span class="rounded-full bg-cp-success-bg px-3 py-1.5 text-cp-xs font-heavy text-cp-success-text">运行正常</span>
|
||||
<span class="rounded-full bg-cp-warning-bg px-3 py-1.5 text-cp-xs font-heavy text-cp-warning-text">额度受限</span>
|
||||
<span class="rounded-full bg-cp-error-bg px-3 py-1.5 text-cp-xs font-heavy text-cp-error-text">需要处理</span>
|
||||
<span class="rounded-full bg-cp-info-bg px-3 py-1.5 text-cp-xs font-heavy text-cp-info-text">同步中</span>
|
||||
<span class="rounded-full bg-cp-success-bg px-3 py-1.5 text-cp-xs font-heavy text-cp-success-text-on-bg">运行正常</span>
|
||||
<span class="rounded-full bg-cp-warning-bg px-3 py-1.5 text-cp-xs font-heavy text-cp-warning-text-on-bg">额度受限</span>
|
||||
<span class="rounded-full bg-cp-error-bg px-3 py-1.5 text-cp-xs font-heavy text-cp-error-text-on-bg">需要处理</span>
|
||||
<span class="rounded-full bg-cp-info-bg px-3 py-1.5 text-cp-xs font-heavy text-cp-info-text-on-bg">同步中</span>
|
||||
</div>
|
||||
<div v-for="item in progressItems" :key="item.label" class="grid gap-2">
|
||||
<div class="flex justify-between text-cp-sm font-heavy text-cp-text-secondary">
|
||||
|
||||
@@ -130,7 +130,7 @@ function upstreamSendStateText(value: string | null | undefined) {
|
||||
</code>
|
||||
<span
|
||||
v-if="row.metadata.recoveredAt"
|
||||
class="inline-flex h-5 shrink-0 items-center rounded-full bg-cp-success-bg px-2 text-cp-xs leading-none font-heavy text-cp-success-text"
|
||||
class="inline-flex h-5 shrink-0 items-center rounded-full bg-cp-success-bg px-2 text-cp-xs leading-none font-heavy text-cp-success-text-on-bg"
|
||||
>
|
||||
已自动恢复
|
||||
</span>
|
||||
|
||||
@@ -45,7 +45,7 @@ const latencyDetails = computed(() => usageLatencyDetails(props.record))
|
||||
|
||||
<div class="flex justify-between border-t border-cp-split pt-2">
|
||||
<span class="whitespace-nowrap text-cp-text-secondary">总耗时</span>
|
||||
<span class="whitespace-nowrap font-mono font-heavy text-cp-blue-text">
|
||||
<span class="whitespace-nowrap font-mono font-heavy text-cp-info-text">
|
||||
{{ latencyDetails.totalDisplay }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -9,14 +9,14 @@ function statusClass(statusCode?: number | null) {
|
||||
}
|
||||
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
return 'bg-cp-success-bg text-cp-success-text'
|
||||
return 'bg-cp-success-bg text-cp-success-text-on-bg'
|
||||
}
|
||||
|
||||
if (statusCode >= 300 && statusCode < 400) {
|
||||
return 'bg-cp-warning-bg text-cp-warning-text'
|
||||
return 'bg-cp-warning-bg text-cp-warning-text-on-bg'
|
||||
}
|
||||
|
||||
return 'bg-cp-error-bg text-cp-error-text'
|
||||
return 'bg-cp-error-bg text-cp-error-text-on-bg'
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user