copy(web): api 标签与整理状态统一

整理记录状态改为排队中 / 整理中 / 已整理 / 部分整理 / 整理失败(列表摘要、组汇总、队列面板同口径);
下载计划「等你批准」「准备提交」;资源评估「可下载」「信息不全」「已跳过」;任务状态带「中」;
识别等待提示改匹配「TMDB 结果在后台查询」。

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-07 02:10:19 +08:00
1 parent 148b12f279
commit 592f40ccf8
23 files changed
+58 -59

No files matched your search

@@ -42,7 +42,7 @@ export const TASK_STATUS: Record<
> = {
pending: { label: "排队中", tone: "neutral" },
running: { label: "运行中", tone: "neutral" },
waiting: { label: "等待", tone: "warning" },
waiting: { label: "等待中", tone: "warning" },
succeeded: { label: "成功", tone: "success" },
failed: { label: "失败", tone: "destructive" },
cancelled: { label: "已取消", tone: "neutral" },
@@ -63,7 +63,7 @@ export const SUBJECT_LABEL: Record<string, string> = {
feed_source: "RSS",
site: "站点",
library_root: "媒体库目录",
cache_volume: "缓存卷",
cache_volume: "下载盘",
};
/** 业务任务的对象 → 它的"家"页面 */
@@ -155,7 +155,7 @@ export function IdentifyPanel({
})}
</ul>
) : it.skipped ? null : (
<p className="text-caption text-muted-foreground">没有可信候选。整理时可以手动搜索作品。</p>
<p className="text-caption text-muted-foreground">没有可信的候选作品。整理时可以手动搜索作品。</p>
)}
</div>
)}
+1 -1
View File
@@ -339,7 +339,7 @@ describe("识别远端回填(S-7)", () => {
candidates: [],
suggestion: { mediaEntityId: null, contentUnitId: null, contentUnit: null },
existing: { assetId: null },
warnings: ["远端候选在后台查询,查完自动补上"],
warnings: ["TMDB 结果在后台查询,查完自动补上"],
...over,
});
const base = { items: [item("a.mkv"), item("b.mkv")], truncated: false, remoteTaskId: "run-1", remotePending: 1 };
+1 -1
View File
@@ -548,7 +548,7 @@ export function nameTaken(name: string, self: string, siblings: string[]): boole
const identifyKey = (it: Pick<FileIdentifyItem, "root" | "path">) => `${it.root}\u0000${it.path}`;
/** 服务端给"远端在后台查"项加的提示;结果回来后去掉 */
const REMOTE_PENDING_WARNING = /^远端候选在后台查询/;
const REMOTE_PENDING_WARNING = /^TMDB 结果在后台查询/;
/**
* SSE identify.completed 回填:taskId 与响应的 remoteTaskId 一致时,按 root + path 用完整结果替换条目;
+3 -3
View File
@@ -123,10 +123,10 @@ export const ORG_STATUS: Record<OrganizationStatus, ToneLabel> = {
};
export const CANDIDATE_DECISION: Record<string, ToneLabel> = {
accept: { label: "接受", tone: "success" },
accept: { label: "可下载", tone: "success" },
upgrade: { label: "可升级", tone: "success" },
reject: { label: "拒绝", tone: "destructive" },
unknown_field: { label: "字段未知", tone: "warning" },
unknown_field: { label: "信息不全", tone: "warning" },
skipped: { label: "已跳过", tone: "neutral" },
deferred: { label: "延后:已有下载在进行", tone: "warning" },
};
@@ -294,7 +294,7 @@ export const ENRICH_SOURCE_KIND: Record<string, string> = {
platform: "平台页",
douban: "豆瓣摘要",
snippet: "搜索摘要",
other: "其它网站",
other: "其他网站",
};
/** 补全来源链接被跳过的原因 */
@@ -99,7 +99,7 @@ export function ScrapeRecordView({ record: s, showPath = false }: { record: Scra
<div className="grid gap-2">
<div className="flex flex-wrap items-center gap-2">
<StatusBadge tone={SCRAPE_STATUS[s.status].tone}>{SCRAPE_STATUS[s.status].label}</StatusBadge>
{showPath ? <span className="min-w-0 text-sm break-all text-foreground">{s.path || "目录根"}</span> : null}
{showPath ? <span className="min-w-0 text-sm break-all text-foreground">{s.path || "(登记目录本身)"}</span> : null}
{done && (files.length || s.status === "succeeded") ? (
<span className="text-sm text-muted-foreground">{scrapeCounts(s) || "没有要写的文件"}</span>
) : null}
@@ -26,7 +26,7 @@ function ScrapeQueueItem({ run }: { run: EngineRun }) {
const scrapeId = input.scrapeRecordId ?? input.recordId;
const scrape = useScrapeRecords(scrapeId ? [scrapeId] : []);
const record = scrape.data?.records[0];
const status = run.status === "pending" ? "排队" : run.status === "sleeping" ? "等待" : "执行中";
const status = run.status === "pending" ? "排队中" : run.status === "sleeping" ? "等待中" : "整理中";
return (
<li className="pg-slab space-y-2 rounded-xl p-4">
<div className="flex flex-wrap items-center gap-2">
@@ -85,7 +85,7 @@ function QueueItem({ run }: { run: EngineRun }) {
const progress = record ? recordFileProgress(record) : null;
const title = record ? recordTitle(record) : (download.data?.name ?? run.business?.title ?? "整理任务");
const source = record?.source.path ?? download.data?.contentPath ?? download.data?.savePath;
const status = run.status === "pending" ? "排队" : run.status === "sleeping" ? "等待" : "执行中";
const status = run.status === "pending" ? "排队中" : run.status === "sleeping" ? "等待中" : "整理中";
return (
<li className="pg-slab space-y-2 rounded-xl p-4">
<div className="flex flex-wrap items-center gap-2">
@@ -114,9 +114,9 @@ describe("整理记录列表:整理方式、分类、分组", () => {
const st = (...xs: PublicOrganizationRecord["status"][]) => xs.map((status) => ({ status }));
expect(groupIssues(st("succeeded", "succeeded"))).toEqual([]);
expect(groupIssues(st("succeeded", "failed", "partial", "running", "queued"))).toEqual([
{ label: "失败", n: 1, tone: "destructive" },
{ label: "部分成功", n: 1, tone: "warning" },
{ label: "进行中", n: 2, tone: "neutral" },
{ label: "整理失败", n: 1, tone: "destructive" },
{ label: "部分整理", n: 1, tone: "warning" },
{ label: "整理中", n: 2, tone: "neutral" },
]);
});
@@ -80,9 +80,9 @@ export function groupIssues(
): { label: string; n: number; tone: "destructive" | "warning" | "neutral" }[] {
const n = (f: (s: PublicOrganizationRecord["status"]) => boolean) => rows.filter((r) => f(r.status)).length;
return [
{ label: "失败", n: n((s) => s === "failed"), tone: "destructive" as const },
{ label: "部分成功", n: n((s) => s === "partial"), tone: "warning" as const },
{ label: "进行中", n: n((s) => s === "queued" || s === "running"), tone: "neutral" as const },
{ label: "整理失败", n: n((s) => s === "failed"), tone: "destructive" as const },
{ label: "部分整理", n: n((s) => s === "partial"), tone: "warning" as const },
{ label: "整理中", n: n((s) => s === "queued" || s === "running"), tone: "neutral" as const },
{ label: "已取消", n: n((s) => s === "cancelled"), tone: "neutral" as const },
].filter((x) => x.n > 0);
}
+1 -1
View File
@@ -282,7 +282,7 @@ export const TTL_CARD: CardSpec = {
ttlField("tmdbMissDays", "TMDB 空结果", "搜索无结果或没识别出的结果也缓存,期内不重复查"),
ttlField("imageDays", "TMDB 人物与图片"),
ttlField("metaSearchDays", "豆瓣 / Bangumi 搜索"),
ttlField("metaDetailDays", "豆瓣 / Bangumi 条目"),
ttlField("metaDetailDays", "豆瓣 / Bangumi 作品"),
ttlField("siteDetailDays", "站点详情页内容"),
ttlField("webSearchDays", "网页搜索结果"),
],
@@ -208,7 +208,7 @@ describe("缓存区名", () => {
it("已知区显示中文名,未知区原样显示", () => {
const base = { entries: 1, expired: 0, bytes: 10, lastWriteAt: null };
expect(cacheRow({ region: "tmdb.request", ...base }).label).toBe("TMDB 请求");
expect(cacheRow({ region: "douban.subject", ...base }).label).toBe("豆瓣条目");
expect(cacheRow({ region: "douban.subject", ...base }).label).toBe("豆瓣作品");
expect(cacheRow({ region: "bangumi.calendar", ...base }).label).toBe("Bangumi(calendar)");
expect(cacheRow({ region: "site.detail", ...base }).label).toBe("站点详情页");
expect(cacheRow({ region: "images", ...base }).label).toBe("图片");
+1 -1
View File
@@ -19,7 +19,7 @@ describe("任务行状态", () => {
});
it("引擎自身失败 / 进行中照旧;没有业务对象照旧", () => {
expect(engineRunStatus({ status: "failed", business: agent("budget_exceeded") }).label).toBe("失败");
expect(engineRunStatus({ status: "running", business: agent("running") }).label).toBe("进行中");
expect(engineRunStatus({ status: "running", business: agent("running") }).label).toBe("运行中");
expect(engineRunStatus({ status: "completed", business: null }).label).toBe("完成");
});
});
+3 -3
View File
@@ -54,9 +54,9 @@ export const workflowLabel = (name: string) => WORKFLOW_LABEL[name] ?? name;
/** 引擎状态 → 任务状态 */
const RUN_STATUS: Record<string, { label: string; tone: StatusTone }> = {
pending: { label: "排队", tone: "neutral" },
running: { label: "进行中", tone: "neutral" },
sleeping: { label: "等待", tone: "neutral" },
pending: { label: "排队中", tone: "neutral" },
running: { label: "运行中", tone: "neutral" },
sleeping: { label: "等待中", tone: "neutral" },
completed: { label: "完成", tone: "success" },
succeeded: { label: "完成", tone: "success" },
failed: { label: "失败", tone: "destructive" },