v0.6.2: 仪表盘布局重构 + 每日趋势折线图 + OpenCode Go/Zen 预设

仪表盘:
- 新增每日用量趋势折线图(Token/缓存命中率/请求数三线)
- 用量趋势 Tab 组(每日/模型/供应商模型)与模型表格同行等高
- 热力图独立整行,格子放大 16px
- 折线图坐标轴文字改 HTML 覆盖层(修复 SVG 拉伸变形)
- 表格 border-collapse + 行线与边框同色
- 模型表格估算标签行内显示(行高统一)
- 最近请求容器 max-h 限制
- 页脚归属放内容流末尾

模型唯一性:
- 获取模型列表时自动勾选已存在模型 + 已添加徽章
- 批量添加跳过同供应商已存在 model id
- onBulkAdd 同供应商 model id 去重

新增预设:
- OpenCode Go(套餐 subscription,带推荐链接)
- OpenCode Zen(按量 pay_as_you_go)

折线图优化:
- 缓存命中率 0-1 映射修复
- 请求数默认显示
- 直线连接 + 渐变填充
This commit is contained in:
KimiSwitch Dev committed 2026-07-30 11:50:05 +08:00
1 parent 2614f80d0f
commit bee981aefa
13 files changed
+739 -95

No files matched your search

+122 -6
View File
@@ -17,6 +17,9 @@ export type UsageKind =
| "plan:zhipu"
| "plan:minimax";
/** Billing model for a preset. Drives the tab filter in PresetPickerModal. */
export type BillingMode = "subscription" | "pay_as_you_go";
/** Runtime set used to catch TS/Rust enum drift (see dev-assert below). */
export const SUPPORTED_USAGE_KINDS: ReadonlySet<string> = new Set<UsageKind>([
"balance:deepseek",
@@ -71,6 +74,12 @@ export interface ProviderPreset {
/** Defaults to ["thinking"]. */
capabilities?: string[];
}>;
/**
* Billing model — drives the 套餐/按量 tab in PresetPickerModal.
* - "subscription": coding-plan / token-plan style subscription (quota-based)
* - "pay_as_you_go": per-token API billing
*/
billingMode: BillingMode;
/**
* Billing/usage query kinds; omitted means "do not query".
* Persisted to SQLite settings by the Rust side on save, never to
@@ -95,6 +104,7 @@ export const providerPresets: ProviderPreset[] = [
{ model: "claude-sonnet-4-5" },
{ model: "claude-haiku-4-5" },
],
billingMode: "pay_as_you_go",
},
{
id: "kimi-coding",
@@ -111,6 +121,7 @@ export const providerPresets: ProviderPreset[] = [
{ model: "kimi-for-coding", displayName: "Kimi For Coding" },
{ model: "kimi-k2.7-code" },
],
billingMode: "subscription",
usageKinds: ["plan:kimi_coding"],
},
{
@@ -127,6 +138,7 @@ export const providerPresets: ProviderPreset[] = [
{ model: "kimi-k2-thinking-turbo" },
{ model: "kimi-k2.6" },
],
billingMode: "pay_as_you_go",
},
{
id: "deepseek",
@@ -138,12 +150,13 @@ export const providerPresets: ProviderPreset[] = [
baseUrl: "https://api.deepseek.com/v1",
icon: "deepseek",
models: [{ model: "deepseek-chat" }, { model: "deepseek-reasoner" }],
billingMode: "pay_as_you_go",
usageKinds: ["balance:deepseek"],
},
{
id: "zhipu",
name: "Zhipu GLM",
nameKey: "presetNameZhipu",
id: "zhipu-api",
name: "Zhipu GLM (API)",
nameKey: "presetNameZhipuApi",
websiteUrl: "https://open.bigmodel.cn",
category: "cn_official",
providerType: "openai",
@@ -154,18 +167,51 @@ export const providerPresets: ProviderPreset[] = [
{ model: "glm-4.6" },
{ model: "glm-4.5-air" },
],
billingMode: "pay_as_you_go",
},
{
id: "zhipu-coding",
name: "Zhipu GLM Coding Plan",
nameKey: "presetNameZhipuCoding",
websiteUrl: "https://open.bigmodel.cn",
category: "cn_official",
providerType: "openai",
// Coding Plan endpoint is separate from the pay-as-you-go PaaS API.
baseUrl: "https://open.bigmodel.cn/api/coding/paas/v4",
icon: "zhipu",
models: [
{ model: "glm-4.7" },
{ model: "glm-4.6" },
{ model: "glm-4.5-air" },
],
billingMode: "subscription",
usageKinds: ["plan:zhipu"],
},
{
id: "zai",
name: "z.ai",
nameKey: "presetNameZai",
id: "zai-api",
name: "z.ai (API)",
nameKey: "presetNameZaiApi",
websiteUrl: "https://z.ai",
category: "third_party",
providerType: "openai",
baseUrl: "https://api.z.ai/api/paas/v4",
icon: "zhipu",
models: [{ model: "glm-4.7" }, { model: "glm-4.6" }],
billingMode: "pay_as_you_go",
},
{
id: "zai-coding",
name: "z.ai Coding Plan",
nameKey: "presetNameZaiCoding",
websiteUrl: "https://z.ai",
category: "third_party",
providerType: "openai",
// Coding Plan endpoint (mirror of Zhipu GLM Coding Plan). If the path
// differs on z.ai, fall back to a known mirror.
baseUrl: "https://api.z.ai/api/coding/paas/v4",
icon: "zhipu",
models: [{ model: "glm-4.7" }, { model: "glm-4.6" }],
billingMode: "subscription",
usageKinds: ["plan:zhipu"],
},
{
@@ -182,6 +228,7 @@ export const providerPresets: ProviderPreset[] = [
{ model: "qwen3-coder-plus" },
{ model: "qwen3.5-plus" },
],
billingMode: "pay_as_you_go",
},
{
id: "minimax",
@@ -193,6 +240,25 @@ export const providerPresets: ProviderPreset[] = [
baseUrl: "https://api.minimaxi.com/v1",
icon: "minimax",
models: [{ model: "MiniMax-M3" }, { model: "MiniMax-M2.7" }],
billingMode: "pay_as_you_go",
usageKinds: ["plan:minimax"],
},
{
id: "minimax-token-plan",
name: "MiniMax Token Plan",
nameKey: "presetNameMinimaxTokenPlan",
websiteUrl: "https://platform.minimaxi.com",
category: "cn_official",
providerType: "openai",
// Token Plan is sold against the same platform endpoint as the
// pay-as-you-go API — only the API key differs. The Rust detect
// routes api.minimaxi.com to plan:minimax, so this preset picks up
// the same query path; the `subscription` tag helps the user pick
// the right entry based on which key they hold.
baseUrl: "https://api.minimaxi.com/v1",
icon: "minimax",
models: [{ model: "MiniMax-M3" }, { model: "MiniMax-M2.7" }],
billingMode: "subscription",
usageKinds: ["plan:minimax"],
},
{
@@ -205,6 +271,7 @@ export const providerPresets: ProviderPreset[] = [
baseUrl: "https://api.stepfun.com/v1",
icon: "stepfun",
models: [{ model: "step-3.7-flash" }, { model: "step-3.5-flash" }],
billingMode: "pay_as_you_go",
usageKinds: ["balance:stepfun"],
},
{
@@ -229,6 +296,7 @@ export const providerPresets: ProviderPreset[] = [
},
],
usageKinds: ["balance:siliconflow"],
billingMode: "pay_as_you_go",
},
{
id: "novita",
@@ -251,6 +319,7 @@ export const providerPresets: ProviderPreset[] = [
{ model: "zai-org/glm-4.6" },
],
usageKinds: ["balance:novita"],
billingMode: "pay_as_you_go",
},
{
id: "openrouter",
@@ -273,6 +342,7 @@ export const providerPresets: ProviderPreset[] = [
{ model: "google/gemini-3-pro-preview" },
],
usageKinds: ["balance:openrouter"],
billingMode: "pay_as_you_go",
},
{
id: "openai",
@@ -288,6 +358,7 @@ export const providerPresets: ProviderPreset[] = [
{ model: "gpt-5.1-codex-max" },
{ model: "gpt-5-mini" },
],
billingMode: "pay_as_you_go",
},
{
id: "google-genai",
@@ -303,6 +374,7 @@ export const providerPresets: ProviderPreset[] = [
{ model: "gemini-3-flash-preview" },
{ model: "gemini-2.5-flash" },
],
billingMode: "pay_as_you_go",
},
{
id: "volcengine",
@@ -321,6 +393,50 @@ export const providerPresets: ProviderPreset[] = [
},
{ model: "kimi-k2-250905", displayName: "Kimi K2" },
],
billingMode: "pay_as_you_go",
},
{
id: "opencode-go",
name: "OpenCode Go",
nameKey: "presetNameOpencodeGo",
// Referral link — supports the OpenCode project
websiteUrl: "https://opencode.ai/go?ref=DFCNADQCEM",
apiKeyUrl: "https://opencode.ai/zen/",
category: "third_party",
providerType: "openai",
baseUrl: "https://opencode.ai/zen/go/v1",
icon: "opencode",
models: [
{ model: "grok-4.5", displayName: "Grok 4.5" },
{ model: "glm-5.2", displayName: "GLM-5.2" },
{ model: "glm-5.1", displayName: "GLM-5.1" },
{ model: "kimi-k3", displayName: "Kimi K3" },
{ model: "kimi-k2.7-code", displayName: "Kimi K2.7 Code" },
{ model: "kimi-k2.6", displayName: "Kimi K2.6" },
{ model: "deepseek-v4-pro", displayName: "DeepSeek V4 Pro" },
{ model: "deepseek-v4-flash", displayName: "DeepSeek V4 Flash" },
],
billingMode: "subscription",
},
{
id: "opencode-zen",
name: "OpenCode Zen",
nameKey: "presetNameOpencodeZen",
websiteUrl: "https://opencode.ai/zen/",
apiKeyUrl: "https://opencode.ai/zen/",
category: "third_party",
providerType: "openai",
baseUrl: "https://opencode.ai/zen/v1",
icon: "opencode",
models: [
{ model: "claude-opus-5", displayName: "Claude Opus 5" },
{ model: "claude-sonnet-5", displayName: "Claude Sonnet 5" },
{ model: "gpt-5.5", displayName: "GPT 5.5" },
{ model: "gemini-3.6-flash", displayName: "Gemini 3.6 Flash" },
{ model: "grok-4.5", displayName: "Grok 4.5" },
{ model: "deepseek-v4-pro", displayName: "DeepSeek V4 Pro" },
],
billingMode: "pay_as_you_go",
},
];