refactor(web): 下载盘、RSS、订阅、设置与待处理的剩余去噪项(DEAI-2)

- 下载面板:下载盘只显示「已用 x / 总量」与进度条,暂停线 / 在途 / 预留 / 可清理 / 做种保留收进详情;
  阈值文案统一「暂停线 / 恢复线 / 下载盘满暂停」
- RSS 页去掉与站点页重复的站点表,节标题「RSS 地址」;用途只在非通用时显示
- 订阅:一条都没有时不铺筛选;表单里「空 = 24;0 = 关」等等式改成 placeholder + 一句说明
- 设置:浏览器服务、元数据识别、MCP 说明去掉组件名与实现细节;会话目录与 fake 脚本只在开发构建显示;
  API Key scope 前加中文名;命名模板变量去掉「MP 无」
- 待处理顶部计数卡改成一行筛选按钮
- 智能体悬浮按钮只在没有侧栏的窄屏出现,抽屉打开时不再显示「收起」胶囊

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-29 21:02:30 +08:00
1 parent 57ce40168d
commit 2c8c33c31c
15 files changed
+185 -237

No files matched your search

@@ -8,6 +8,7 @@ import { ConfirmDialog } from "~/components/console/confirm-dialog.tsx";
import { ErrorState, LoadingState } from "~/components/console/empty-state.tsx";
import { consolePath, settingsPath } from "~/components/console/nav.ts";
import { StatusBadge } from "~/components/console/status-badge.tsx";
import { TechInfo } from "~/components/console/tech-info.tsx";
import { Button } from "~/components/ui/button.tsx";
import { errorMessage } from "~/lib/api.ts";
import { cn, formatBytes } from "~/lib/utils.ts";
@@ -37,10 +38,11 @@ function VolumeBar({ v }: { v: Volume }) {
<span className="truncate">{volumeLabel(v)}</span>
</span>
<span className="text-meta text-muted-foreground tabular-nums">
{pct === null ? "使用率未知" : `${pct.toFixed(1)}%`}
{v.usedBytes !== null && v.totalBytes !== null
? ` · ${formatBytes(v.usedBytes, 1)} / ${formatBytes(v.totalBytes, 1)}`
: ""}
? `已用 ${formatBytes(v.usedBytes, 0)} / ${formatBytes(v.totalBytes, 1)}`
: pct === null
? "用量未知"
: `已用 ${Math.round(pct)}%`}
</span>
</div>
<div className="relative mt-1.5 h-1.5 rounded-full bg-foreground/[0.08]">
@@ -57,28 +59,32 @@ function VolumeBar({ v }: { v: Volume }) {
aria-hidden
className="absolute -top-1 h-3.5 w-px bg-destructive"
style={{ left: `${v.hardThresholdPercent}%` }}
title={`硬阈值 ${v.hardThresholdPercent}%`}
title={`暂停线 ${v.hardThresholdPercent}%`}
/>
<span
aria-hidden
className="absolute -top-1 h-3.5 w-px bg-muted-foreground"
style={{ left: `${v.resumePercent}%` }}
title={`恢复水位 ${v.resumePercent}%`}
title={`恢复线 ${v.resumePercent}%`}
/>
</div>
<div className="mt-1.5 flex flex-wrap gap-x-3 gap-y-1 text-meta text-muted-foreground">
<span>
硬阈值 {v.hardThresholdPercent}% / 恢复 {v.resumePercent}%
</span>
<span>在途 {formatBytes(v.pendingBytes, 1)}</span>
<span>预留 {formatBytes(v.reservedBytes, 1)}</span>
<span>可清理 {formatBytes(v.cleanableBytes, 1)}</span>
<span>保留锁定 {formatBytes(v.retentionLockedBytes, 1)}</span>
</div>
<TechInfo
title="详情"
className="mt-1"
items={[
{ label: "暂停线 / 恢复线", value: `${v.hardThresholdPercent}% / ${v.resumePercent}%`, mono: false },
{ label: "下载中还要占用", value: formatBytes(v.pendingBytes, 1), mono: false },
{ label: "已预留", value: formatBytes(v.reservedBytes, 1), mono: false },
{ label: "可清理", value: formatBytes(v.cleanableBytes, 1), mono: false },
{ label: "做种保留中", value: formatBytes(v.retentionLockedBytes, 1), mono: false },
]}
/>
<div className="mt-1.5 flex flex-wrap gap-1.5">
{pct === null ? <StatusBadge tone="warning">读不到磁盘状态,已暂停新提交</StatusBadge> : null}
{tripped ? <StatusBadge tone="destructive">已达硬阈值,停止新提交</StatusBadge> : null}
{v.pausedByThreshold ? <StatusBadge tone="warning">阈值暂停 {v.pausedByThreshold} 个任务</StatusBadge> : null}
{tripped ? <StatusBadge tone="destructive">超过暂停线,停止新下载</StatusBadge> : null}
{v.pausedByThreshold ? (
<StatusBadge tone="warning">因下载盘暂停 {v.pausedByThreshold} 个任务</StatusBadge>
) : null}
</div>
{v.notes.map((n) => (
<p key={n} className="mt-1 text-meta text-muted-foreground">
@@ -97,7 +103,7 @@ export function CacheVolumes() {
return (
<section className="pg-slab mb-6 rounded-xl p-4">
<div className="mb-3 flex flex-wrap items-center justify-between gap-2">
<h2 className="text-label font-semibold tracking-[0.18em] text-muted-foreground uppercase">缓存水位</h2>
<h2 className="text-label font-semibold tracking-[0.18em] text-muted-foreground uppercase">下载盘</h2>
<div className="flex flex-wrap gap-2">
<Button asChild variant="ghost" size="sm">
<Link to={settingsPath("automation", "cache")}>
@@ -50,7 +50,7 @@ export function DownloadStatusBadges({ t }: { t: DownloadTask }) {
<span className="flex flex-wrap gap-1">
<StatusBadge tone={DOWNLOAD_STATUS_TONE[t.status]}>{DOWNLOAD_STATUS_LABEL[t.status]}</StatusBadge>
{t.pauseReason === "threshold" ? (
<StatusBadge tone="warning">阈值暂停</StatusBadge>
<StatusBadge tone="warning">下载盘满,已暂停</StatusBadge>
) : t.pauseReason ? (
<StatusBadge>{PAUSE_REASON_LABEL[t.pauseReason]}</StatusBadge>
) : null}
@@ -71,14 +71,14 @@ export function PauseResume({ t, size = "sm" }: { t: DownloadTask; size?: "sm" |
variant="outline"
size={size}
disabled={act.isPending}
title={threshold ? "阈值暂停,缓存回落到恢复水位后自动恢复" : undefined}
title={threshold ? "下载盘超过暂停线,降到恢复线后自动恢复" : undefined}
onKeyDown={(e) => e.stopPropagation()}
onClick={(e) => {
e.stopPropagation();
act.mutate(
{ id: t.id, action: canResume ? "resume" : "pause" },
{
onSuccess: () => toast.success(canResume ? "已恢复" : "已暂停。阈值回落时不会自动恢复"),
onSuccess: () => toast.success(canResume ? "已恢复" : "已暂停。下载盘回落时不会自动恢复"),
onError: (err) => toast.error(errorMessage(err)),
},
);