feat(downloads): fold download plans into download panel (DL-3)

- Waiting plans (approval / disk space / automation off / queued) are
  active-segment rows on /download-tasks/board, merged by created_at,
  counted, with approve / cancel actions; ?plan= deep links and legacy
  /downloads/plans routes redirect to the panel
- Download detail shows "why this download" (source, purpose, replaced
  version, reasons); raw evaluation in tech info
- Failed / cancelled / expired plans appear in the entity download
  history; rejected / revoked / expired approvals close draft plans
- New GET /acquisition-plans/{id}/why, POST /acquisition-plans/{id}/cancel
- User-facing copy no longer says 下载计划; glossary updated

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-30 01:15:25 +08:00
1 parent c0522f2531
commit a9147e647d
50 files changed
+1535 -348

No files matched your search

@@ -19,7 +19,7 @@ import { errorMessage } from "~/lib/api.ts";
import { formatBytes } from "~/lib/utils.ts";
const STEPS = [
"生成下载计划,预留收录版本和预算;每个收录版本同时只有一个在途计划",
"预留收录版本和预算;每个收录版本同时只有一个在途的下载",
"已有相同资源或相同 hash 的任务时直接接管,不重复提交",
"缓存卷超过硬阈值或读不到磁盘状态时无法提交",
"提交前复核免费、做种等易变字段",
@@ -56,10 +56,10 @@ export function DownloadDialog({
if (r.submitted && r.plan) {
setRejected(null);
setDone(r.plan.id);
toast.success(`已提交${slotName(r.slotId) ? `(${slotName(r.slotId)})` : ""},进度见「下载队列」`);
toast.success(`已提交${slotName(r.slotId) ? `(${slotName(r.slotId)})` : ""},进度见「下载面板」`);
} else {
setRejected(r.rejected);
toast.warning("没有生成下载计划");
toast.warning("没有下载");
}
},
onError: (e) => toast.error(errorMessage(e)),
@@ -109,7 +109,7 @@ export function DownloadDialog({
)}
{rejected ? (
<div className="rounded-xl border border-warning/40 bg-warning/10 px-3 py-2.5 text-caption text-warning">
<p className="mb-1">没有生成下载计划:</p>
<p className="mb-1">没有下载:</p>
<ul className="list-disc space-y-0.5 pl-5">
{rejected.map((r, i) => (
<li key={`${r.slotId}-${r.code}-${i}`} className="break-words">
@@ -122,8 +122,8 @@ export function DownloadDialog({
) : null}
{done ? (
<p className="text-caption text-success">
计划已生成。
<Link to="/console/downloads/plans" className="underline underline-offset-4">
已加入下载。
<Link to={`/console/downloads?plan=${done}`} className="underline underline-offset-4">
查看
</Link>
</p>