feat(episode-mapping): 映射规则接口与模拟预览、待处理确认 / 忽略、作品页集数映射分区与订阅摘要
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
1 parent
fe597187dd
commit
45a114263b
26 files changed
+2770
-9
No files matched your search
@@ -0,0 +1,73 @@
|
||||
import type { EpisodeMappingPreviewItem } from "@umt/contracts";
|
||||
import { ArrowRight } from "lucide-react";
|
||||
import { StatusBadge } from "~/components/console/status-badge.tsx";
|
||||
import { cn, formatDateTime } from "~/lib/utils.ts";
|
||||
import { canonicalText, methodText, sourceText, VALIDATION } from "./model.ts";
|
||||
|
||||
// 模拟预览表格:原始季集 → 当前结果 → 套用草稿后的结果、方式、校验;与当前不同的行高亮并标「有变化」。
|
||||
|
||||
export function PreviewTable({
|
||||
items,
|
||||
hasDraft,
|
||||
empty = "这部作品还没有绑定的资源。",
|
||||
}: {
|
||||
items: EpisodeMappingPreviewItem[];
|
||||
/** 有草稿时列名写「套用后」,否则写「重算」 */
|
||||
hasDraft: boolean;
|
||||
empty?: string;
|
||||
}) {
|
||||
if (!items.length) return <p className="px-4 py-6 text-caption text-muted-foreground sm:px-5">{empty}</p>;
|
||||
return (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full min-w-[44rem] text-caption">
|
||||
<thead>
|
||||
<tr className="border-b border-border/60 text-left text-meta text-muted-foreground">
|
||||
<th className="px-4 py-2 font-medium">资源</th>
|
||||
<th className="px-3 py-2 font-medium">原始</th>
|
||||
<th className="px-3 py-2 font-medium">当前</th>
|
||||
<th className="px-3 py-2 font-medium">{hasDraft ? "套用后" : "重算"}</th>
|
||||
<th className="px-3 py-2 font-medium">方式</th>
|
||||
<th className="px-4 py-2 font-medium">校验</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{items.map((it) => {
|
||||
const v = VALIDATION[it.validation];
|
||||
return (
|
||||
<tr
|
||||
key={it.sourceReleaseId}
|
||||
data-changed={it.changed || undefined}
|
||||
className={cn("border-b border-border/60 last:border-b-0", it.changed && "bg-foreground/[0.04]")}
|
||||
>
|
||||
<td className="max-w-[22rem] px-4 py-2 align-top">
|
||||
<div className="font-mono text-meta break-all text-foreground">{it.title}</div>
|
||||
<div className="mt-0.5 text-meta text-muted-foreground">
|
||||
{[it.releaseGroup, formatDateTime(it.publishedAt)].filter(Boolean).join(" · ")}
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-3 py-2 align-top font-mono tabular-nums">{sourceText(it.preview)}</td>
|
||||
<td className="px-3 py-2 align-top">
|
||||
<div className="font-mono tabular-nums">{canonicalText(it.current)}</div>
|
||||
<div className="text-meta text-muted-foreground">{methodText(it.current)}</div>
|
||||
</td>
|
||||
<td className="px-3 py-2 align-top">
|
||||
<div className="inline-flex items-center gap-1 font-mono tabular-nums">
|
||||
{it.changed ? <ArrowRight aria-hidden className="h-3 w-3 text-muted-foreground" /> : null}
|
||||
<span className={cn(it.changed && "font-semibold text-foreground")}>
|
||||
{canonicalText(it.preview)}
|
||||
</span>
|
||||
</div>
|
||||
{it.changed ? <div className="text-meta text-muted-foreground">有变化</div> : null}
|
||||
</td>
|
||||
<td className="px-3 py-2 align-top">{methodText(it.preview)}</td>
|
||||
<td className="px-4 py-2 align-top">
|
||||
<StatusBadge tone={v.tone}>{v.label}</StatusBadge>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user