feat(web): 技术信息折叠、原因码人话化、待处理「指定作品」(DEAI-2)
- 新增 TechInfo 折叠组件(默认收起,标题「技术信息」);设置新增「界面」分区, 「默认展开技术信息」开关存本机浏览器 - 原因码表 @umt/contracts reasons.ts(identity_unknown、blocked:target_exists、below_min_size… → 一句人话 + 下一步),服务端整理记录 message 与冲突事项标题/摘要改用它 - 整理记录列表/详情、下载详情与时间线:原码、ID、hash、用时、变更序号进技术信息; 下载完成但入库失败时单独提示;时间线只列有记录的阶段,标题改「经过」 - 待处理:没识别出作品类事项主按钮「指定作品」(搜媒体库 + TMDB,走已有 resolve; 整理类事项打开重新整理),忽略为次要;去掉正常态徽章与「实时」指示;原始证据改「详细信息」进技术信息 - 整理成功后同时关闭该下载的「没识别出作品」事项 Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
4480fc346d
commit
f0d4935fa7
21 files changed
+688
-78
No files matched your search
@@ -1,6 +1,7 @@
|
||||
import type { DownloadTask } from "@umt/contracts";
|
||||
import { Bot, FolderInput, Pause, Play, ShieldAlert } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { Link } from "react-router";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
DOWNLOAD_STATUS_LABEL,
|
||||
@@ -17,11 +18,13 @@ import { DetailSection } from "~/components/console/detail-sheet.tsx";
|
||||
import { JsonView } from "~/components/console/json-view.tsx";
|
||||
import { KvList } from "~/components/console/kv-list.tsx";
|
||||
import { StatusBadge } from "~/components/console/status-badge.tsx";
|
||||
import { TechInfo } from "~/components/console/tech-info.tsx";
|
||||
import { OrganizeWizard } from "~/components/organize-wizard/organize-wizard.tsx";
|
||||
import { Button } from "~/components/ui/button.tsx";
|
||||
import { relTime } from "~/components/workbench/release-fields.ts";
|
||||
import { errorMessage } from "~/lib/api.ts";
|
||||
import { planReasonText } from "~/lib/labels.ts";
|
||||
import { humanizeReason, reasonLine } from "~/lib/reasons.ts";
|
||||
import { formatBytes, formatDateTime } from "~/lib/utils.ts";
|
||||
import { BusinessTimeline } from "./business-timeline.tsx";
|
||||
|
||||
@@ -52,7 +55,6 @@ export function DownloadStatusBadges({ t }: { t: DownloadTask }) {
|
||||
<StatusBadge>{PAUSE_REASON_LABEL[t.pauseReason]}</StatusBadge>
|
||||
) : null}
|
||||
{!t.managed ? <StatusBadge>外部任务</StatusBadge> : null}
|
||||
{t.origin === "adopted" ? <StatusBadge>接管</StatusBadge> : null}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -95,6 +97,11 @@ export function DownloadDetail({ task }: { task: DownloadTask }) {
|
||||
const trace = useDownloadTrace(task, plan.data);
|
||||
const [organizing, setOrganizing] = useState(false);
|
||||
const canOrganize = ["completed", "importing", "imported"].includes(task.status);
|
||||
// 下载完成但最近一次整理失败:状态行只写"下载完成"会误导,单独说明入库失败
|
||||
const lastRecord = [...(trace.records.data?.items ?? [])].sort((a, b) =>
|
||||
(b.startedAt ?? b.createdAt).localeCompare(a.startedAt ?? a.createdAt),
|
||||
)[0];
|
||||
const importFailed = task.status === "completed" && lastRecord?.status === "failed" ? lastRecord : null;
|
||||
|
||||
return (
|
||||
<div className="space-y-5">
|
||||
@@ -132,7 +139,15 @@ export function DownloadDetail({ task }: { task: DownloadTask }) {
|
||||
{task.pauseReason === "threshold" ? (
|
||||
<p className="flex items-start gap-2 rounded-lg border border-warning/40 bg-warning/10 px-3 py-2 text-caption text-warning">
|
||||
<ShieldAlert className="mt-0.5 h-3.5 w-3.5 shrink-0" />
|
||||
缓存卷达到硬阈值,任务已暂停,水位回落到恢复线后自动恢复。手动恢复和智能体都不能绕过阈值。
|
||||
下载盘超过暂停线,任务已暂停;降到恢复线以下后自动恢复。
|
||||
</p>
|
||||
) : null}
|
||||
{importFailed ? (
|
||||
<p className="rounded-lg border border-destructive/40 bg-destructive/10 px-3 py-2 text-caption text-destructive">
|
||||
入库失败:{reasonLine(importFailed.reason)}。
|
||||
<Link to="/console/inbox" className="ml-1 underline underline-offset-4">
|
||||
去待处理
|
||||
</Link>
|
||||
</p>
|
||||
) : null}
|
||||
{task.noProgressSince ? (
|
||||
@@ -151,17 +166,26 @@ export function DownloadDetail({ task }: { task: DownloadTask }) {
|
||||
{ label: "剩余", value: task.remainingBytes === null ? "未知" : formatBytes(task.remainingBytes, 2) },
|
||||
{ label: "分享率", value: task.ratio === null ? "—" : task.ratio.toFixed(2) },
|
||||
{ label: "最近进展", value: relTime(task.lastProgressAt) },
|
||||
{ label: "最近同步", value: relTime(task.lastSyncedAt) },
|
||||
{ label: "标签", value: task.tags.join(", ") },
|
||||
{ label: "分类", value: task.category },
|
||||
{ label: "保存路径", value: task.savePath, mono: true, wide: true },
|
||||
{ label: "内容路径", value: task.contentPath, mono: true, wide: true },
|
||||
{ label: "torrent hash", value: task.torrentHash, mono: true, wide: true },
|
||||
]}
|
||||
/>
|
||||
<TechInfo
|
||||
className="mt-3"
|
||||
items={[
|
||||
{ label: "最近同步", value: relTime(task.lastSyncedAt), mono: false },
|
||||
{ label: "标签", value: task.tags.join(", ") },
|
||||
{ label: "分类", value: task.category },
|
||||
{ label: "下载器状态", value: task.rawState },
|
||||
{ label: "内容路径", value: task.contentPath, wide: true },
|
||||
{ label: "torrent hash", value: task.torrentHash, wide: true },
|
||||
{ label: "任务 ID", value: task.id, wide: true },
|
||||
]}
|
||||
>
|
||||
{task.lastError ? <JsonView label="下载器错误原文" value={task.lastError} tone="destructive" /> : null}
|
||||
</TechInfo>
|
||||
</DetailSection>
|
||||
|
||||
<DetailSection title="业务时间线">
|
||||
<DetailSection title="经过">
|
||||
<BusinessTimeline events={trace.events} loading={trace.loading} />
|
||||
</DetailSection>
|
||||
|
||||
@@ -175,7 +199,9 @@ export function DownloadDetail({ task }: { task: DownloadTask }) {
|
||||
{ label: "说明", value: planReasonText(plan.data.statusReason), wide: true },
|
||||
]}
|
||||
/>
|
||||
<JsonView className="mt-2" label="评估依据" value={plan.data.evaluation} />
|
||||
<TechInfo className="mt-2">
|
||||
<JsonView label="评估依据" value={plan.data.evaluation} />
|
||||
</TechInfo>
|
||||
</DetailSection>
|
||||
) : null}
|
||||
|
||||
@@ -195,7 +221,12 @@ export function DownloadDetail({ task }: { task: DownloadTask }) {
|
||||
</DetailSection>
|
||||
) : null}
|
||||
|
||||
{task.lastError ? <JsonView label="下载器错误" value={task.lastError} tone="destructive" defaultOpen /> : null}
|
||||
{task.lastError ? (
|
||||
<p className="rounded-lg border border-destructive/40 bg-destructive/10 px-3 py-2 text-caption text-destructive">
|
||||
下载器报错:
|
||||
{humanizeReason(String((task.lastError as { message?: unknown }).message ?? "")) || "原文见技术信息"}
|
||||
</p>
|
||||
) : null}
|
||||
|
||||
{organizing ? (
|
||||
<OrganizeWizard
|
||||
|
||||
Reference in new issue
Block a user