前端: 浅色模式 + 系统自动主题

- 引入语义化 CSS 变量令牌(bg/surface/edge/ink/muted/accent 等), data-theme 三态切换
- theme store(localStorage + 系统偏好跟随), 首屏内联脚本防主题闪烁
- ThemeToggle 组件(浅色/深色/跟随系统) 置于导航与控制台顶栏
- 全量替换硬编码 zinc/emerald/red 类为令牌, 图表基线/状态色随主题适配
- 浅色对比度校准(accent/err/warn 深浅各一套)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Sakurasan
2026-08-15 16:20:43 +08:00
co-authored by Claude
parent 4846db9293
commit a422034b2b
24 changed files with 380 additions and 249 deletions
+14 -14
View File
@@ -131,7 +131,7 @@ onMounted(load)
<div class="mb-6 flex items-center justify-between">
<div>
<h1 class="text-lg font-semibold">渠道</h1>
<p class="text-sm text-zinc-500">接入上游服务,API Key 加密存储</p>
<p class="text-sm text-muted">接入上游服务,API Key 加密存储</p>
</div>
<Button @click="openCreate">添加渠道</Button>
</div>
@@ -140,7 +140,7 @@ onMounted(load)
<div class="overflow-x-auto">
<table class="w-full text-sm">
<thead>
<tr class="border-b border-zinc-800 text-left text-xs text-zinc-500">
<tr class="border-b border-edge text-left text-xs text-muted">
<th scope="col" class="px-4 py-2.5 font-medium">名称</th>
<th scope="col" class="px-4 py-2.5 font-medium">类型</th>
<th scope="col" class="px-4 py-2.5 font-medium">Base URL</th>
@@ -152,29 +152,29 @@ onMounted(load)
</thead>
<tbody>
<tr v-for="ch in channels" :key="ch.id" class="table-row">
<td class="px-4 py-2.5 text-zinc-200">{{ ch.name }}</td>
<td class="px-4 py-2.5 font-mono text-xs text-zinc-400">{{ providerMap[ch.provider] }}</td>
<td class="px-4 py-2.5 font-mono text-xs text-zinc-500">{{ ch.base_url }}</td>
<td class="px-4 py-2.5 font-mono text-xs text-zinc-600">{{ ch.api_key_masked || '****' }}</td>
<td class="px-4 py-2.5 text-ink">{{ ch.name }}</td>
<td class="px-4 py-2.5 font-mono text-xs text-muted">{{ providerMap[ch.provider] }}</td>
<td class="px-4 py-2.5 font-mono text-xs text-muted">{{ ch.base_url }}</td>
<td class="px-4 py-2.5 font-mono text-xs text-muted">{{ ch.api_key_masked || '****' }}</td>
<td class="px-4 py-2.5">
<Badge :variant="ch.health_status === 'healthy' ? 'ok' : ch.health_status === 'cooldown' ? 'err' : 'warn'">
{{ ch.health_status }}
</Badge>
</td>
<td class="px-4 py-2.5 text-xs text-zinc-400">{{ ch.enabled ? '是' : '否' }}</td>
<td class="px-4 py-2.5 text-xs text-muted">{{ ch.enabled ? '是' : '否' }}</td>
<td class="px-4 py-2.5 text-right">
<div class="flex justify-end gap-2">
<button class="text-xs text-zinc-500 hover:text-accent" :disabled="busyId === ch.id" @click="testChannel(ch)">
<button class="text-xs text-muted hover:text-accent" :disabled="busyId === ch.id" @click="testChannel(ch)">
{{ busyId === ch.id ? '测试中…' : '测试' }}
</button>
<button class="text-xs text-zinc-500 hover:text-accent" @click="importModels(ch)">导入模型</button>
<button class="text-xs text-zinc-500 hover:text-zinc-200" @click="openEdit(ch)">编辑</button>
<button class="text-xs text-zinc-500 hover:text-red-400" @click="remove(ch)">删除</button>
<button class="text-xs text-muted hover:text-accent" @click="importModels(ch)">导入模型</button>
<button class="text-xs text-muted hover:text-ink" @click="openEdit(ch)">编辑</button>
<button class="text-xs text-muted hover:text-err" @click="remove(ch)">删除</button>
</div>
</td>
</tr>
<tr v-if="channels.length === 0">
<td colspan="7" class="px-4 py-10 text-center text-sm text-zinc-600">还没有渠道,点击「添加渠道」</td>
<td colspan="7" class="px-4 py-10 text-center text-sm text-muted">还没有渠道,点击「添加渠道」</td>
</tr>
</tbody>
</table>
@@ -186,8 +186,8 @@ onMounted(load)
<div class="grid grid-cols-2 gap-4">
<Input v-model="form.name" label="名称" placeholder="openai" />
<label class="block">
<span class="mb-1.5 block text-xs font-medium text-zinc-400">API 类型</span>
<select v-model="form.provider" class="h-10 w-full rounded-md border border-zinc-700 bg-zinc-900 px-3 text-sm text-zinc-100 outline-none focus:border-accent">
<span class="mb-1.5 block text-xs font-medium text-muted">API 类型</span>
<select v-model="form.provider" class="h-10 w-full rounded-md border border-edge2 bg-surface px-3 text-sm text-ink outline-none focus:border-accent">
<option value="openai">OpenAI</option>
<option value="anthropic">Anthropic</option>
<option value="compatible">兼容</option>