"use client"; import { useState } from "react"; import { useRouter } from "next/navigation"; import { Button } from "@/components/ui/Button"; import { Card, CardHeader } from "@/components/ui/Card"; import { extractionApi } from "@/lib/api"; import { describeError } from "@/lib/utils/error"; import { formatDateTime } from "@/lib/utils/format"; import type { MemoryCandidate, WorldEntity } from "@/types/api"; /** * 候选审核面板(跨来源统一入口)。 * 记忆候选(cycle 大周天 / import 资料导入)与世界实体候选逐条 approve/reject。 * 审核后 router.refresh()。与 ImportWizard 的批量审核互补——此处为跨来源统一待审队列。 */ export function CandidateReviewPanel({ memoryCandidates, worldProposals, }: { memoryCandidates: MemoryCandidate[]; worldProposals: WorldEntity[]; }) { const router = useRouter(); const [busyId, setBusyId] = useState(null); const [error, setError] = useState(null); async function reviewMemory(id: string, approve: boolean) { setBusyId(id); setError(null); try { if (approve) await extractionApi.approveMemoryCandidate(id); else await extractionApi.rejectMemoryCandidate(id); router.refresh(); } catch (e) { setError(describeError(e)); } finally { setBusyId(null); } } async function reviewWorld(id: string, approve: boolean) { setBusyId(id); setError(null); try { if (approve) await extractionApi.approveWorldEntity(id); else await extractionApi.rejectWorldEntity(id); router.refresh(); } catch (e) { setError(describeError(e)); } finally { setBusyId(null); } } return (
{memoryCandidates.length === 0 ? (

暂无待审记忆候选。

) : (
    {memoryCandidates.map((c) => (
  • {c.type} {c.title} {c.import_job_id ? "资料导入" : c.cycle_id ? "大周天" : ""} {` · ${formatDateTime(c.created_at)}`} {(c.confidence ?? 0).toFixed(2)}

    {c.content}

  • ))}
)}
{worldProposals.length === 0 ? (

暂无待审世界实体候选。

) : (
    {worldProposals.map((e) => (
  • {e.type} {e.name} {e.confidence.toFixed(2)}
  • ))}
)}
{error &&

{error}

}
); }