"use client"; import { useCallback, useEffect, useMemo, useState } from "react"; import { api } from "@/lib/api/client"; import type { ForeshadowView } from "@/lib/api/types"; import { classifyChapterForeshadow, type ChapterForeshadowGroups, } from "./chapterForeshadow"; // 写作台「本章伏笔」提醒的数据层:拉本项目全量伏笔(GET /foreshadow,只读), // 再按当前章号本地分类。项目内一次拉取,切章仅重新分类(不重复请求)。 export type ChapterForeshadowStatus = "loading" | "ready" | "error"; export interface UseChapterForeshadow { groups: ChapterForeshadowGroups; status: ChapterForeshadowStatus; reload: () => void; } const FORESHADOW_PATH = "/projects/{project_id}/foreshadow" as const; const EMPTY_ITEMS: ForeshadowView[] = []; export function useChapterForeshadow( projectId: string, chapterNo: number, ): UseChapterForeshadow { const [items, setItems] = useState(EMPTY_ITEMS); const [status, setStatus] = useState("loading"); // reload 触发器:自增即重新拉取。 const [nonce, setNonce] = useState(0); useEffect(() => { let cancelled = false; setStatus("loading"); void (async () => { try { const { data, error } = await api.GET(FORESHADOW_PATH, { params: { path: { project_id: projectId } }, }); if (cancelled) return; if (error || !data) { setItems(EMPTY_ITEMS); setStatus("error"); return; } setItems(data.foreshadow ?? EMPTY_ITEMS); setStatus("ready"); } catch { // 网络层失败(后端不可达/CORS):openapi-fetch 直接抛而非返回 error 信封。 if (cancelled) return; setItems(EMPTY_ITEMS); setStatus("error"); } })(); return () => { cancelled = true; }; }, [projectId, nonce]); // 切章不重拉,仅重新分类(伏笔窗口相对章号变化)。 const groups = useMemo( () => classifyChapterForeshadow(items, chapterNo), [items, chapterNo], ); const reload = useCallback(() => setNonce((n) => n + 1), []); return { groups, status, reload }; }