fix(web): 控制台界面细节与 uhd_web 控件规范对齐

- 顶栏搜索移进右侧玻璃胶囊;输入框改淡玻璃(边线 0.46 → 0.16,悬停加深,聚焦 / 出错保留光晕)
- 新增 SegmentedControl(滑动 seg-thumb),替换站点、下载、订阅、文件、智能体列表及对话框里的实心选中块;Tabs 改为同一枚滑块
- 开关型按钮统一 outline + aria-pressed 选中外观;页头 / 工具栏次操作描边、图标钮描边圆;文件排序改 Select;下载总速度加标签
- 分页一页放得下时只留总数、空列表不渲染、按容器宽度收起按钮
- 运行状态存储区重排;智能体列表页与会话页共用外壳路由,标题与左栏不再重挂载
- 站点卡片「⋯」不再单独换行;设置导航、状态计数、多选条件改玻璃选中态

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-10-08 12:02:48 +08:00
1 parent 8ff1817845
commit c9b4ceb301
32 files changed
+753 -639

No files matched your search

+138 -142
View File
@@ -324,150 +324,146 @@ export function StorageSection({ health }: { health: SystemHealth }) {
<BudgetBar label="会话与证据" u={s.sessionsEvidence} />
</ul>
<div className="grid gap-6 xl:grid-cols-2">
<TechInfo title={`数据库里最大的 ${TOP_TABLES} 张表`} columns={1}>
<Panel title={`体积最大的表(前 ${TOP_TABLES})`} note="含索引与 TOAST">
<DataTable<TableRow>
rows={s.db.tables.slice(0, TOP_TABLES)}
rowKey={(t) => `${t.schema}.${t.name}`}
empty={{ title: "取不到表体积" }}
columns={[
{
key: "name",
header: "表",
cell: (t) => (
<span className="font-mono text-caption break-all">
{t.schema === "public" ? t.name : `${t.schema}.${t.name}`}
</span>
),
},
{
key: "total",
header: "合计",
align: "right",
cell: (t) => (
<span className="whitespace-nowrap tabular-nums">{formatBytes(t.totalBytes, 1)}</span>
),
},
{
key: "idx",
header: "索引",
align: "right",
hideBelow: "md",
cell: (t) => (
<span className="whitespace-nowrap tabular-nums text-muted-foreground">
{formatBytes(t.indexBytes, 1)}
</span>
),
},
{
key: "rows",
header: "估算行数",
align: "right",
hideBelow: "sm",
cell: (t) => (
<span className="tabular-nums text-muted-foreground">
{t.rowsEstimate === null ? "—" : t.rowsEstimate.toLocaleString("zh-CN")}
</span>
),
},
{
key: "dead",
header: "死元组",
align: "right",
hideBelow: "md",
cell: (t) => (
<span className="tabular-nums text-muted-foreground">
{t.deadRows === null ? "—" : t.deadRows.toLocaleString("zh-CN")}
</span>
),
},
]}
/>
</Panel>
</TechInfo>
<div className="space-y-6">
<Panel title="缓存" note="条数含还没清理的过期条目">
<DataTable<KvRow>
rows={s.kvCache}
rowKey={(r) => r.region}
empty={{ title: "缓存为空" }}
columns={[
{
key: "region",
header: "类别",
cell: (r) => (
<span title={r.region}>
{REGION_LABEL[r.region] ?? <span className="font-mono text-caption">{r.region}</span>}
</span>
),
},
{
key: "entries",
header: "条数",
align: "right",
cell: (r) => <span className="tabular-nums">{r.entries.toLocaleString("zh-CN")}</span>,
},
{
key: "expired",
header: "已过期",
align: "right",
hideBelow: "sm",
cell: (r) => (
<span className="tabular-nums text-muted-foreground">{r.expired.toLocaleString("zh-CN")}</span>
),
},
{
key: "bytes",
header: "体积",
align: "right",
cell: (r) => <span className="whitespace-nowrap tabular-nums">{formatBytes(r.bytes, 1)}</span>,
},
]}
/>
</Panel>
<Panel title="数据目录" note="DATA_DIR 各子目录">
<DataTable<DirRow>
rows={s.dataDir}
rowKey={(d) => d.path}
empty={{ title: "还没有统计", description: "目录用量每 5 分钟统计一次。" }}
columns={[
{
key: "name",
header: "目录",
cell: (d) => (
<div className="min-w-0">
<p className="font-medium">{d.name}</p>
<p className="truncate font-mono text-meta text-muted-foreground" title={d.path}>
{d.path}
</p>
{d.error ? <p className="text-meta text-destructive">{d.error}</p> : null}
</div>
),
},
{
key: "files",
header: "文件",
align: "right",
hideBelow: "sm",
cell: (d) => (
<span className="tabular-nums text-muted-foreground">{d.files.toLocaleString("zh-CN")}</span>
),
},
{
key: "used",
header: "占用",
align: "right",
cell: (d) => (
<span className="whitespace-nowrap tabular-nums">{formatBytes(d.usedBytes, 1)}</span>
),
},
]}
/>
</Panel>
</div>
{/* 缓存与数据目录在宽屏并排;两个折叠区(最大的表、语句统计)整行放在下面,收起时不留空栏 */}
<div className="grid items-start gap-6 lg:grid-cols-2">
<Panel title="缓存" note="条数含还没清理的过期条目">
<DataTable<KvRow>
rows={s.kvCache}
rowKey={(r) => r.region}
empty={{ title: "缓存为空" }}
columns={[
{
key: "region",
header: "类别",
cell: (r) => (
<span title={r.region}>
{REGION_LABEL[r.region] ?? <span className="font-mono text-caption">{r.region}</span>}
</span>
),
},
{
key: "entries",
header: "条数",
align: "right",
cell: (r) => <span className="tabular-nums">{r.entries.toLocaleString("zh-CN")}</span>,
},
{
key: "expired",
header: "已过期",
align: "right",
hideBelow: "sm",
cell: (r) => (
<span className="tabular-nums text-muted-foreground">{r.expired.toLocaleString("zh-CN")}</span>
),
},
{
key: "bytes",
header: "体积",
align: "right",
cell: (r) => <span className="whitespace-nowrap tabular-nums">{formatBytes(r.bytes, 1)}</span>,
},
]}
/>
</Panel>
<Panel title="数据目录" note="DATA_DIR 各子目录">
<DataTable<DirRow>
rows={s.dataDir}
rowKey={(d) => d.path}
empty={{ title: "还没有统计", description: "目录用量每 5 分钟统计一次。" }}
columns={[
{
key: "name",
header: "目录",
cell: (d) => (
<div className="min-w-0">
<p className="font-medium">{d.name}</p>
<p className="truncate font-mono text-meta text-muted-foreground" title={d.path}>
{d.path}
</p>
{d.error ? <p className="text-meta text-destructive">{d.error}</p> : null}
</div>
),
},
{
key: "files",
header: "文件",
align: "right",
hideBelow: "sm",
cell: (d) => (
<span className="tabular-nums text-muted-foreground">{d.files.toLocaleString("zh-CN")}</span>
),
},
{
key: "used",
header: "占用",
align: "right",
cell: (d) => <span className="whitespace-nowrap tabular-nums">{formatBytes(d.usedBytes, 1)}</span>,
},
]}
/>
</Panel>
</div>
<TechInfo title={`数据库里最大的 ${TOP_TABLES} 张表`} columns={1}>
<Panel title={`体积最大的表(前 ${TOP_TABLES})`} note="含索引与 TOAST">
<DataTable<TableRow>
rows={s.db.tables.slice(0, TOP_TABLES)}
rowKey={(t) => `${t.schema}.${t.name}`}
empty={{ title: "取不到表体积" }}
columns={[
{
key: "name",
header: "表",
cell: (t) => (
<span className="font-mono text-caption break-all">
{t.schema === "public" ? t.name : `${t.schema}.${t.name}`}
</span>
),
},
{
key: "total",
header: "合计",
align: "right",
cell: (t) => <span className="whitespace-nowrap tabular-nums">{formatBytes(t.totalBytes, 1)}</span>,
},
{
key: "idx",
header: "索引",
align: "right",
hideBelow: "md",
cell: (t) => (
<span className="whitespace-nowrap tabular-nums text-muted-foreground">
{formatBytes(t.indexBytes, 1)}
</span>
),
},
{
key: "rows",
header: "估算行数",
align: "right",
hideBelow: "sm",
cell: (t) => (
<span className="tabular-nums text-muted-foreground">
{t.rowsEstimate === null ? "—" : t.rowsEstimate.toLocaleString("zh-CN")}
</span>
),
},
{
key: "dead",
header: "死元组",
align: "right",
hideBelow: "md",
cell: (t) => (
<span className="tabular-nums text-muted-foreground">
{t.deadRows === null ? "—" : t.deadRows.toLocaleString("zh-CN")}
</span>
),
},
]}
/>
</Panel>
</TechInfo>
<StatementsInfo st={s.db.statements} />
<Panel title="清理任务" note="立即清理会把维护任务加入队列,结果在运行记录里看">