| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859 |
- "use client";
- import { useCallback, useEffect, useMemo, useState } from "react";
- import { AppShell } from "@/components/AppShell";
- import { ErrorState, LoadingState } from "@/components/StateBlocks";
- import { getVideoWalk } from "@/lib/api/client";
- import type { FlowLedgerVideoWalkResponse, RawRecord } from "@/lib/api/types";
- import { asRecord, text } from "@/lib/flow-ledger/format";
- import { WalkTree } from "@/features/walk/WalkTree";
- export function VideoWalkPage({ runId, contentId }: { runId: string; contentId: string }) {
- const [data, setData] = useState<FlowLedgerVideoWalkResponse | null>(null);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState<string | null>(null);
- const load = useCallback(async () => {
- setLoading(true);
- setError(null);
- try {
- const debug = new URLSearchParams(window.location.search).get("debug") === "1";
- setData(await getVideoWalk(runId, contentId, debug));
- } catch (err) {
- setError(err instanceof Error ? err.message : String(err));
- } finally {
- setLoading(false);
- }
- }, [contentId, runId]);
- useEffect(() => {
- void load();
- }, [load]);
- const root = asRecord(data?.root_video);
- const rootTitle = cleanTitle(text(root.title, "这条视频"));
- const actions = useMemo(
- () => (data?.actions || []).filter((a): a is RawRecord => typeof a === "object" && a !== null),
- [data?.actions]
- );
- return (
- <AppShell
- title="这条视频的扩展过程"
- subtitle={`从《${rootTitle}》开始向外游走`}
- runId={runId}
- showBack
- onRefresh={load}
- >
- {loading ? <LoadingState /> : null}
- {error ? <ErrorState message={error} /> : null}
- {data && !loading && !error ? (
- <WalkTree actions={actions} runId={runId} emptyLabel="这条视频没有继续向外游走" />
- ) : null}
- </AppShell>
- );
- }
- function cleanTitle(value: string): string {
- return value.replace(/#[^\s#]+/g, " ").replace(/\s+/g, " ").trim() || value;
- }
|