大模型区能配了:四元绑定就地改 + 连通自检,不再是只读橱窗

后端的 upsert 与 probe 一直在(`POST /api/gov/llm` · `/api/gov/llm/:id/probe`),
只是**界面从来没用过**:进去只看得见「密钥已绑定」,却没有一处能绑 —— 那不叫配置面。

现在:
  · **实例卡**能配:名 / Provider / Base URL / Model / API-Key / 启用 / 系统用途,
    列表卡上一枚笔就地开表单,详情页也有同一张表(同一个组件,不写两份);
  · **API-Key 只写不读**(OS 7.3 凭证隔离):服务端永不回显,所以留空 = 保持原值,
    不是清空 —— 实测改型号后 `apiKeyBound` 仍为 true,密钥没被空表单洗掉;
  · **Base URL 留空取该 Provider 的默认端点**;`openai-compatible` 没有默认,
    前端先拦一道(服务端也拦)—— 不填就是连不上,别等自检才知道;
  · **连通自检**:真发一次最小调用,通了报延迟,不通把**厂商原话**摆在卡里,
    不改写成一句「连不上」—— 「密钥无效」和「端点不通」是两件要分头修的事。
    实测种子里的 key 是占位串,自检当场说清:`Your api key: ****lder is invalid`。
  · 幽灵卡新建实例(LLM 没有删除路由,所以本轮只验证了改,没造多余实例)。

卡片沿用刚定稿的管理系统风(着色图标 + 状态胶囊 + 计量块);端点那格占两格宽,
主机名不截断。五闸绿。

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 00:43:49 +08:00
co-authored by Claude Opus 5
parent 9b286ae4ba
commit 21aea48c6c
3 changed files with 306 additions and 47 deletions
+12
View File
@@ -297,6 +297,9 @@
.g-fcard .plate b { font: 700 14px/1 var(--mono); letter-spacing: -.03em; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.g-fcard .plate i { font-style: normal; font-size: 10px; color: var(--ink-4); white-space: nowrap; }
.g-fcard .plate > span.bad { background: #fdf3f3; }
/* 宽格:装得下主机名这类长值 —— 占两格宽、字降一档,不省略号 */
.g-fcard .plate > span.wide { grid-column: span 2; }
.g-fcard .plate > span.wide b { font-size: 11.5px; letter-spacing: 0; }
.g-fcard .plate > span.bad b { color: var(--danger); }
/* ⋯ 菜单:从头行那枚钮下弹出 */
@@ -307,6 +310,15 @@
.g-fcard .menu button.bad:hover { background: #fdf2f2; }
.g-fcard .menu .q { padding: 3px 8px 5px; font-size: 11px; line-height: 1.5; color: var(--ink-3); }
/* 自检读数:卡底一条 —— 通了报延迟,不通把**厂商原话**摆出来(两行内,长了截断) */
.g-fcard .probe { position: relative; z-index: 1; display: flex; align-items: flex-start; gap: 6px; padding: 8px 10px; border-radius: 9px; background: #f2f7f4; font: 500 11px/1.5 var(--sans); color: #0c8154; }
.g-fcard .probe.bad { background: #fdf3f3; color: #a83a3a; }
.g-fcard .probe svg { flex: none; margin-top: 2px; }
/* 开关行:两枚复选框并排 —— 表单里唯一的横排 */
.g-swrow { display: flex; align-items: center; gap: 18px; }
.g-swrow label { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--ink-2, var(--ink)); cursor: pointer; }
.g-swrow input { width: 14px; height: 14px; accent-color: var(--brand); cursor: pointer; }
/* 审批依据:一行两格 + 删 */
.g-basis { display: flex; flex-direction: column; gap: 6px; }
.g-basis-r { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto; gap: 6px; }