import type { IdentityPoolItem, PoolCandidate } from "@umt/contracts"; import { ArrowRight, ExternalLink, LoaderCircle, RotateCw } from "lucide-react"; import { Link } from "react-router"; import { toast } from "sonner"; import { useRetryPool } from "~/api/identity.ts"; import { DetailSection, DetailSheet } from "~/components/console/detail-sheet.tsx"; import { JsonView } from "~/components/console/json-view.tsx"; import { KvList } from "~/components/console/kv-list.tsx"; import { consolePath } from "~/components/console/nav.ts"; import { Button } from "~/components/ui/button.tsx"; import { errorMessage } from "~/lib/api.ts"; import { formatDateTime } from "~/lib/utils.ts"; import { EVIDENCE_LEVEL, POOL_REASON, POOL_STATUS } from "./labels.ts"; import { Chip, Tone } from "./parts.tsx"; // 待识别资源详情(只读):候选证据 + 重新识别。选候选、忽略在待处理里做(判定只在待处理与作品详情)。 /** 多个候选 / 待确认的资源开"待确认身份"事项;没有候选的(无结果、复查耗尽)开"待识别"事项 */ export function inInbox(item: Pick): boolean { return item.status === "pending" && (item.decisionId !== null || hasCandidates(item)); } function hasCandidates(item: Pick): boolean { return (item.reason === "ambiguous" || item.reason === "proposed") && item.candidates.length > 0; } export const INBOX_IDENTITY = `${consolePath("inbox")}?kind=identity_ambiguous`; export const INBOX_UNRESOLVED = `${consolePath("inbox")}?kind=identity_unresolved`; /** 条目对应的待处理筛选链接 */ export function inboxLink(item: Pick): string { return hasCandidates(item) ? INBOX_IDENTITY : INBOX_UNRESOLVED; } /** query 摘要:标题 / 年份 / 季集 */ export function querySummary(q: Record): string { const parts: string[] = []; if (q.title) parts.push(String(q.title)); if (q.year) parts.push(String(q.year)); if (q.season !== undefined && q.season !== null) parts.push(`S${String(q.season).padStart(2, "0")}`); if (q.episode !== undefined && q.episode !== null) parts.push(`E${String(q.episode).padStart(2, "0")}`); if (q.segment) parts.push(String(q.segment)); if (q.cut) parts.push(String(q.cut)); return parts.join(" · ") || "—"; } function CandidateRow({ c, index }: { c: PoolCandidate; index: number }) { return (
  • {index + 1}. {c.title} {c.year ? ` (${c.year})` : ""}

    {c.provider}:{c.entityType}:{c.externalId}

    {EVIDENCE_LEVEL[c.level] ?? c.level} {c.localEntityId ? ( 本地作品 ) : ( 本地未建档 )}
    {c.evidence.length ? (
      {c.evidence.map((e) => (
    • {e}
    • ))}
    ) : null}
  • ); } export function PoolSheet({ item, onClose }: { item: IdentityPoolItem | null; onClose: () => void }) { const retry = useRetryPool(); if (!item) return null; const queued = inInbox(item); return ( !o && onClose()} title={item.release.title} description={item.release.subtitle ?? undefined} footer={ <> {queued ? ( ) : null} } > {queued ? (

    已进待处理,在那里选择候选或忽略。

    ) : null} }, { label: "原因", value: }, { label: "解析结果", value: querySummary(item.query), wide: true }, { label: "站点分类", value: item.release.categoryRaw }, { label: "首次发现", value: formatDateTime(item.release.firstSeenAt) }, { label: "尝试次数", value: String(item.attempts) }, { label: "上次尝试", value: formatDateTime(item.lastAttemptAt) }, { label: "下次复查", value: item.nextReviewAt ? formatDateTime(item.nextReviewAt) : "不再自动复查" }, { label: "证据版本", value: item.evidenceVersion, mono: true }, ]} /> {item.candidates.length ? (
      {item.candidates.map((c, i) => ( ))}
    ) : (

    没有候选。有新证据时自动重试。

    )}
    ); }