"use client"; import { useCallback, useState } from "react"; import { api } from "@/lib/api/client"; import { useToast } from "@/components/Toast"; import type { OutlineChapterView } from "@/lib/api/types"; export type OutlineStatus = "idle" | "generating" | "ready" | "error"; export interface OutlineError { code: string; message: string; } export interface UseOutline { chapters: OutlineChapterView[]; status: OutlineStatus; error: OutlineError | null; generate: (projectId: string, volume: number) => Promise; } // 生成大纲:POST .../outline(body {volume})。无凭据/网关失败 → 503 LLM_UNAVAILABLE // (流前 JSON 信封),经 error 检出、引导去设置(同 draft/review 范式)。 export function useOutline(initial: OutlineChapterView[]): UseOutline { const [chapters, setChapters] = useState(initial); const [status, setStatus] = useState( initial.length > 0 ? "ready" : "idle", ); const [error, setError] = useState(null); const toast = useToast(); const generate = useCallback( async (projectId, volume) => { setStatus("generating"); setError(null); const { data, error: apiError } = await api.POST( "/projects/{project_id}/outline", { params: { path: { project_id: projectId } }, body: { volume }, }, ); if (apiError || !data) { const env = apiError as | { error?: { code?: string; message?: string } } | undefined; const code = env?.error?.code ?? "OUTLINE_FAILED"; const message = env?.error?.message ?? "大纲生成失败,请重试。"; setError({ code, message }); setStatus("error"); toast(message, "error"); return; } setChapters(data.chapters ?? []); setStatus("ready"); toast("大纲已生成", "success"); }, [toast], ); return { chapters, status, error, generate }; }