接入模型改成右侧抽屉:先挑供应商、再填连接、当场测连通(且只测不存)

上一版是把字段倒在地上:整页宽的内联卡、输入框拉到 1100px、动作钮掉出屏幕。
照模型接入面的通行做法重排 —— 520px 右侧抽屉,头固定 / 身滚动 / 底动作栏常驻:

  ① **供应商**:一排可点的牌子,挑中即预填它的默认端点(没有默认的标「端点自填」);
  ② **连接**:API 端点 + API Key(密码框带显示切换),下面就是「测试连接」;
  ③ **型号与用途**:模型(厂商侧型号名)+ 用途名(活动里声明的那个)+ 两枚开关。
  遮罩点击与 Esc 都关得掉 —— 抽屉盖住整屏,不给键盘出路是把人关在里面。

**默认端点从服务端取**(新 `GET /api/gov/llm/providers`):前端不自带一份 URL 表 ——
那种表迟早与 provider 档案漂移,而漂移那天没人会发现(端点错了只表现为「连不上」)。

**「测试连接」只测不存**(新 `POST /api/gov/llm/probe` + `llm.probeDraft`):
拿表单上正填的四元真发一次最小调用,一个字节不落库;密钥留空则取该实例已存的密文,
改端点、换型号不必重打钥匙。上一版是「先存再试」—— 人只想知道钥匙对不对,
结果端点被改了、实例被建了,点取消也收不回来。实测:改错端点后测试,
库里 instances 逐字节未变(测过 before/after 全等)。

顺带补 `eye-off` 图标。五闸绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
2026-07-30 01:10:49 +08:00
co-authored by Claude Opus 5
parent 21aea48c6c
commit f9318b1ae9
12 changed files with 422 additions and 76 deletions
+53
View File
@@ -236,6 +236,31 @@ export declare const llmInstanceViewSchema: z.ZodObject<{
enabled: z.ZodDefault<z.ZodBoolean>;
}, z.core.$strip>;
export type LlmInstanceView = z.infer<typeof llmInstanceViewSchema>;
/**
* Provider 一览 —— 建实例那张表要**预填默认端点**,而唯一真相在服务端的 provider 档案里。
* 前端不自带一份 URL 表:那种表迟早与服务端漂移,漂移的那天没人会发现(端点错了只表现为「连不上」)。
*/
export declare const listLlmProvidersRoute: {
readonly method: "GET";
readonly path: "/api/gov/llm/providers";
readonly output: z.ZodObject<{
providers: z.ZodArray<z.ZodObject<{
provider: z.ZodEnum<{
"openai-compatible": "openai-compatible";
openai: "openai";
deepseek: "deepseek";
anthropic: "anthropic";
qwen: "qwen";
}>;
label: z.ZodString;
defaultBaseUrl: z.ZodString;
structuredOutput: z.ZodEnum<{
"json-object": "json-object";
"prompt-only": "prompt-only";
}>;
}, z.core.$strip>>;
}, z.core.$strip>;
};
export declare const listLlmInstancesRoute: {
readonly method: "GET";
readonly path: "/api/gov/llm";
@@ -294,6 +319,34 @@ export declare const upsertLlmInstanceRoute: {
enabled: z.ZodDefault<z.ZodBoolean>;
}, z.core.$strip>;
};
/**
* 测试连接(草稿)—— **只测不存**:拿表单上正填的四元真发一次最小调用,一个字节不落库。
* 「测试」把表单写进库是个会咬人的副作用:人只想知道钥匙对不对,取消却收不回已改的端点。
* 留空 `apiKey` 时取该实例已存的密钥(改端点、换型号不必重打钥匙)。
*/
export declare const probeLlmDraftRoute: {
readonly method: "POST";
readonly path: "/api/gov/llm/probe";
readonly body: z.ZodObject<{
id: z.ZodOptional<z.ZodString>;
name: z.ZodOptional<z.ZodString>;
provider: z.ZodEnum<{
"openai-compatible": "openai-compatible";
openai: "openai";
deepseek: "deepseek";
anthropic: "anthropic";
qwen: "qwen";
}>;
baseUrl: z.ZodDefault<z.ZodString>;
model: z.ZodString;
apiKey: z.ZodOptional<z.ZodString>;
}, z.core.$strip>;
readonly output: z.ZodObject<{
ok: z.ZodBoolean;
latencyMs: z.ZodOptional<z.ZodNumber>;
error: z.ZodOptional<z.ZodString>;
}, z.core.$strip>;
};
export declare const probeLlmInstanceRoute: {
readonly method: "POST";
readonly path: "/api/gov/llm/:id/probe";