import type { MediaKind, NamingKind } from "@umt/contracts"; import { FileSignature, Save, Trash2 } from "lucide-react"; import { useEffect, useState } from "react"; import { toast } from "sonner"; import { useNamingTemplates, useSaveEntityNaming } from "~/api/naming.ts"; import { ErrorState, LoadingState } from "~/components/console/empty-state.tsx"; import { StatusBadge } from "~/components/console/status-badge.tsx"; import { Button } from "~/components/ui/button.tsx"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "~/components/ui/dialog.tsx"; import { errorMessage } from "~/lib/api.ts"; import { overrideBody, SOURCE_LABEL, splitNamingErrors } from "./model.ts"; import { NAMING_NOTE, NamingTemplateEditor } from "./template-editor.tsx"; // 作品详情 → 命名覆盖:只编辑该作品类型对应的模板;留空沿用库根 / 全局。 export function namingKindOf(kind: MediaKind): NamingKind { if (kind === "series") return "tv"; if (kind === "variety") return "variety"; return "movie"; } /** 作品头部按钮 + 对话框(自带开关状态,挂载处只放一行) */ export function EntityNamingButton({ entityId, kind }: { entityId: string; kind: MediaKind }) { const [open, setOpen] = useState(false); return ( <> {open ? ( setOpen(false)} /> ) : null} ); } function EntityNamingDialog({ entityId, kind, onClose }: { entityId: string; kind: NamingKind; onClose: () => void }) { const q = useNamingTemplates({ entityId }); const save = useSaveEntityNaming(); const [draft, setDraft] = useState> | null>(null); const [errors, setErrors] = useState> | undefined>(); useEffect(() => { if (q.data && !draft) setDraft({ ...(q.data.entity ?? {}) }); }, [q.data, draft]); const saved = q.data?.entity ?? {}; const inheritedTemplate = q.data ? (q.data.root?.[kind] ?? q.data.global[kind]) : ""; const inheritedSource = q.data?.root?.[kind] ? SOURCE_LABEL.root : SOURCE_LABEL.global; const dirty = !!draft && (draft[kind] ?? "") !== (saved[kind] ?? ""); const put = async (clear: boolean) => { if (!draft) return; setErrors(undefined); // 只改本类型,其它类型的已有覆盖原样保留 const next = clear ? { ...saved, [kind]: "" } : { ...saved, [kind]: draft[kind] ?? "" }; const body = overrideBody(next); try { await save.mutateAsync({ id: entityId, namingOverride: body }); setDraft({ ...(body ?? {}) }); toast.success(clear ? "已清除作品命名覆盖" : "作品命名覆盖已保存"); } catch (err) { const split = splitNamingErrors(errorMessage(err)); if (split) setErrors(split); toast.error(split ? "模板有错误,未保存" : errorMessage(err, "保存失败")); } }; return ( !o && onClose()}> 命名覆盖 {NAMING_NOTE} {q.isError ? ( q.refetch()} /> ) : q.isPending || !draft ? ( ) : (
当前:{saved[kind] ? "作品覆盖" : `沿用${inheritedSource}`}
{ setDraft((d) => ({ ...d, [k]: v })); setErrors(undefined); }} defaults={q.data.defaults} inherited={{ [kind]: { template: inheritedTemplate, source: inheritedSource } }} entityId={entityId} saveErrors={errors} />
)}
); }