diff --git a/apps/web/app/components/library/identity-pool-sheet.tsx b/apps/web/app/components/library/identity-pool-sheet.tsx index aba218ff..dcccdda0 100644 --- a/apps/web/app/components/library/identity-pool-sheet.tsx +++ b/apps/web/app/components/library/identity-pool-sheet.tsx @@ -1,32 +1,30 @@ import type { IdentityPoolItem, PoolCandidate } from "@umt/contracts"; -import { ExternalLink, LoaderCircle, RotateCw } from "lucide-react"; -import { type FormEvent, useState } from "react"; +import { ArrowRight, ExternalLink, LoaderCircle, RotateCw } from "lucide-react"; import { Link } from "react-router"; import { toast } from "sonner"; -import { z } from "zod"; -import { useAssignPool, useDismissPool, useRetryPool } from "~/api/identity.ts"; -import { ConfirmDialog } from "~/components/console/confirm-dialog.tsx"; +import { useRetryPool } from "~/api/identity.ts"; import { DetailSection, DetailSheet } from "~/components/console/detail-sheet.tsx"; -import { FormField, zodFieldErrors } from "~/components/console/form-field.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 { Input } from "~/components/ui/input.tsx"; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "~/components/ui/select.tsx"; -import { Textarea } from "~/components/ui/textarea.tsx"; import { errorMessage } from "~/lib/api.ts"; import { formatDateTime } from "~/lib/utils.ts"; -import { EntityPicker, type PickedEntity } from "./identity-entity-picker.tsx"; import { EVIDENCE_LEVEL, POOL_REASON, POOL_STATUS } from "./labels.ts"; import { Chip, Tone } from "./parts.tsx"; -// 待识别条目详情:候选证据 + 三种人工指定方式(候选 / 手动 TMDB id / 本地作品)+ 忽略 / 重试。指定后默认加人工锁。 +// 待识别资源详情(只读):候选证据 + 重新识别。选候选、忽略在待处理里做(判定只在待处理与作品详情)。 -const TmdbForm = z.object({ - entityType: z.enum(["movie", "tv"]), - externalId: z.string().trim().regex(/^\d+$/, "TMDB ID 只能是数字"), -}); +/** 多个候选 / 待确认的资源会生成"待确认身份"待处理事项 */ +export function inInbox(item: Pick): boolean { + return ( + item.status === "pending" && + (item.reason === "ambiguous" || item.reason === "proposed") && + item.candidates.length > 0 + ); +} + +export const INBOX_IDENTITY = `${consolePath("inbox")}?kind=identity_ambiguous`; /** query 摘要:标题 / 年份 / 季集 */ export function querySummary(q: Record): string { @@ -40,17 +38,7 @@ export function querySummary(q: Record): string { return parts.join(" · ") || "—"; } -function CandidateRow({ - c, - index, - onPick, - disabled, -}: { - c: PoolCandidate; - index: number; - onPick: () => void; - disabled: boolean; -}) { +function CandidateRow({ c, index }: { c: PoolCandidate; index: number }) { return (
  • @@ -63,9 +51,6 @@ function CandidateRow({ {c.provider}:{c.entityType}:{c.externalId}

    -
    {EVIDENCE_LEVEL[c.level] ?? c.level} @@ -78,7 +63,7 @@ function CandidateRow({ ) : ( - 本地未建档,指定后按 TMDB 信息建档 + 本地未建档 )}
    {c.evidence.length ? ( @@ -95,41 +80,9 @@ function CandidateRow({ } export function PoolSheet({ item, onClose }: { item: IdentityPoolItem | null; onClose: () => void }) { - const assign = useAssignPool(); - const dismiss = useDismissPool(); const retry = useRetryPool(); - const [tmdb, setTmdb] = useState({ entityType: "movie" as "movie" | "tv", externalId: "" }); - const [tmdbErr, setTmdbErr] = useState>({}); - const [entity, setEntity] = useState(null); - const [note, setNote] = useState(""); - if (!item) return null; - const pending = item.status === "pending"; - const busy = assign.isPending || dismiss.isPending || retry.isPending; - - const doAssign = async (body: Parameters[0], ok: string) => { - try { - await assign.mutateAsync(body); - toast.success(ok); - onClose(); - } catch (err) { - toast.error(errorMessage(err)); - } - }; - - const submitTmdb = (e: FormEvent) => { - e.preventDefault(); - const r = TmdbForm.safeParse(tmdb); - if (!r.success) { - setTmdbErr(zodFieldErrors(r.error.issues)); - return; - } - setTmdbErr({}); - void doAssign( - { id: item.id, external: { provider: "tmdb", ...r.data }, lock: true }, - `已指定 TMDB ${r.data.entityType}:${r.data.externalId} 并加人工锁`, - ); - }; + const queued = inInbox(item); return ( - - 忽略 - - } - title="忽略这条待识别资源?" - description="忽略后不再自动复查,仍可按原始标题搜到。" - confirmLabel="忽略" - onConfirm={async () => { - try { - await dismiss.mutateAsync({ id: item.id, note: note.trim() || undefined }); - toast.success("已忽略"); - onClose(); - } catch (err) { - toast.error(errorMessage(err)); - throw err; - } - }} - > -