"use client"; import Link from "next/link"; import { PanelRightOpen } from "lucide-react"; import { useCallback, useEffect, useMemo, useState } from "react"; import { AppShell } from "@/components/AppShell"; import { EmptyState, ErrorState, LoadingState } from "@/components/StateBlocks"; import { TechnicalRetryDetails } from "@/components/TechnicalRetryDetails"; import { getFlowLedgerVideos } from "@/lib/api/client"; import type { FlowLedgerVideosResponse } from "@/lib/api/types"; import { videoFromApi } from "@/lib/flow-ledger/build"; import { actionLabel, mediaStatusLabel, metricLabel, methodLabel, platformLabel, scoreItemsText } from "@/lib/flow-ledger/business"; import { asRecord, text } from "@/lib/flow-ledger/format"; import type { VideoRef } from "@/lib/flow-ledger/types"; export function QueryVideosPage({ runId, queryId }: { runId: string; queryId: string }) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const load = useCallback(async () => { setLoading(true); setError(null); try { const debug = new URLSearchParams(window.location.search).get("debug") === "1"; setData(await getFlowLedgerVideos(runId, queryId, debug)); } catch (err) { setError(err instanceof Error ? err.message : String(err)); } finally { setLoading(false); } }, [queryId, runId]); useEffect(() => { void load(); }, [load]); const query = asRecord(data?.query); const videos = useMemo(() => (data?.videos || []).map(videoFromApi), [data]); return ( {loading ? : null} {error ? : null} {!loading && !error && !videos.length ? : null} {data ? ( <>
搜索词 {text(query.text, "搜索词待确认")} 来源:{methodLabel(text(query.method, ""))} 首轮视频 {Number(data.summary.total || videos.length)}
{videos.map((video, index) => ( ))}
# 视频 作者 / 平台 互动 判断 评分详情 视频保存 操作
) : null}
); } function Summary({ label, value }: { label: string; value: string }) { return (
{label}
{value}
); } function VideoRow({ index, runId, video }: { index: number; runId: string; video: VideoRef }) { return ( {index + 1} {video.title} {video.author}
{platformLabel(video.platform)}
{metricLabel(video)} {actionLabel(video.decisionAction)} {video.decisionAction === "TECHNICAL_RETRY_REQUIRED" ? (
{technicalRetryShortText(video)}
) : null} {video.decisionAction === "TECHNICAL_RETRY_REQUIRED" ? : null}
{scoreItemsText(video.scoreItems)}
{video.mediaStatusLabel} {video.mediaFailureReason ?
{video.mediaFailureReason}
: null} 看详情 ); } function technicalRetryShortText(video: VideoRef): string { const detail = video.technicalRetryDetail; if (!detail) return "系统需要重试后再判断"; const stage = detail.stageLabel || "技术问题"; const reason = detail.briefReason || detail.failureLabel || detail.failureType || "系统需要重试后再判断"; return `${stage}:${reason}`; }