import { useEffect, useState } from "react"; import "./admin-generations.css"; interface AdminSession { acknowledged_private_content_notice_version: string | null; current_private_content_notice_version: string | null; csrf_token: string; notice_acknowledged: boolean; } interface GenerationRecord { generation_id: string; owner_ref: string; project_id: string; model_id: string; ratio: string; status: "queued" | "running" | "succeeded" | "failed" | "rejected"; created_at: string; completed_at: string | null; duration_ms: number | null; confirmed_credit_cost: number; reserved_credits: number; final_credit_state: "committed" | "released" | null; error_category: string | null; } interface GenerationResponse { generated_at: string; items: GenerationRecord[] } interface OpenedPrompt { generation_id: string; prompt: string } function idempotencyKey() { return `${crypto.randomUUID().replaceAll("-", "")}${crypto.randomUUID().replaceAll("-", "")}`; } function compactId(value: string) { return `${value.slice(0, 8)}...${value.slice(-4)}`; } function formatTime(value: string | null) { return value ? new Intl.DateTimeFormat("zh-CN", { dateStyle: "short", timeStyle: "medium" }).format(new Date(value)) : "未完成"; } function statusLabel(value: GenerationRecord["status"]) { return { queued: "排队", running: "运行中", succeeded: "成功", failed: "失败", rejected: "已拒绝" }[value]; } export function AdminGenerationsPage() { const [session, setSession] = useState(); const [records, setRecords] = useState([]); const [loading, setLoading] = useState(true); const [failed, setFailed] = useState(false); const [acknowledging, setAcknowledging] = useState(false); const [notice, setNotice] = useState(""); const [openedPrompt, setOpenedPrompt] = useState(); const [openedImage, setOpenedImage] = useState<{ generationId: string; url: string }>(); async function load() { setLoading(true); setFailed(false); try { const sessionResponse = await fetch("/api/v1/admin-auth/session", { credentials: "same-origin" }); if (sessionResponse.status === 401) throw new Error("session_invalid"); if (!sessionResponse.ok) throw new Error("session_unavailable"); const current = await sessionResponse.json() as AdminSession; setSession(current); setNotice(""); if (!current.notice_acknowledged) { setRecords([]); return; } const listResponse = await fetch("/api/v1/admin/generations", { credentials: "same-origin" }); if (!listResponse.ok) throw new Error("generation_list_unavailable"); setRecords((await listResponse.json() as GenerationResponse).items); } catch { setFailed(true); } finally { setLoading(false); } } useEffect(() => { void load(); }, []); useEffect(() => () => { if (openedImage) URL.revokeObjectURL(openedImage.url); }, [openedImage]); async function acknowledge() { if (!session?.current_private_content_notice_version || acknowledging) return; setAcknowledging(true); setNotice(""); try { const response = await fetch("/api/v1/admin/private-content-notice/ack", { body: JSON.stringify({ expected_notice_version: session.current_private_content_notice_version }), credentials: "same-origin", headers: { "Content-Type": "application/json", "Idempotency-Key": idempotencyKey(), "X-CSRF-Token": session.csrf_token }, method: "POST", }); if (!response.ok) throw new Error("notice_ack_failed"); await load(); } catch { setNotice("告知版本已变化或确认未完成,请重新读取。 "); } finally { setAcknowledging(false); } } async function openPrompt(generationId: string) { setNotice(""); try { const response = await fetch(`/api/v1/admin/private-content/generations/${generationId}/prompt`, { credentials: "same-origin" }); if (!response.ok) throw new Error("prompt_unavailable"); setOpenedPrompt(await response.json() as OpenedPrompt); } catch { setNotice("内容读取未完成,访问审计未成功时不会返回内容。 "); } } async function openImage(generationId: string) { setNotice(""); try { const response = await fetch(`/api/v1/admin/private-content/generations/${generationId}/image`, { credentials: "same-origin" }); if (!response.ok) throw new Error("image_unavailable"); const url = URL.createObjectURL(await response.blob()); setOpenedImage((previous) => { if (previous) URL.revokeObjectURL(previous.url); return { generationId, url }; }); } catch { setNotice("内容读取未完成,访问审计未成功时不会返回内容。 "); } } return (

OPERATIONS / GENERATION RECORDS

生成记录

{loading ?

正在读取生成记录

: null} {failed ?
后台生成记录暂时无法读取。
: null} {notice ?

{notice}

: null} {session && !session.notice_acknowledged ? (

PRIVATE CONTENT ACCESS

查看私有内容前,请确认当前规则告知

生成记录默认只显示安全元数据。打开图片或完整提示词时,系统会自动记录本次管理员、目标和内容类型访问审计。

) : null} {session?.notice_acknowledged ? (
{records.map((record) => )}
任务用户标识模型 / 比例状态创建 / 完成点数私有内容
{compactId(record.generation_id)} {compactId(record.owner_ref)} {record.model_id}
{record.ratio}
{statusLabel(record.status)}{record.error_category ? {record.error_category} : null}
{formatTime(record.completed_at)}
{record.confirmed_credit_cost} / {record.final_credit_state ?? "冻结"}
{!records.length && !loading ?

当前无生成记录

: null}
) : null} {openedPrompt ?

已记录审计的完整提示词

{compactId(openedPrompt.generation_id)}

{openedPrompt.prompt}
: null} {openedImage ?

已记录审计的生成图片

已记录审计的生成图片
: null}
); }