"use client"; import { useCallback, useState } from "react"; import { api } from "@/lib/api/client"; import { useToast } from "@/components/Toast"; import type { AcceptResponse } from "@/lib/api/types"; import { buildAcceptRequest, type DecisionDraft } from "./decisions"; export type AcceptStatus = "idle" | "accepting" | "accepted" | "error"; export interface AcceptOutcome { result: AcceptResponse | null; // 409 CONFLICT_UNRESOLVED 缺判下标(高亮报告卡)。 missingIndices: number[]; } export interface UseAccept { status: AcceptStatus; result: AcceptResponse | null; accept: ( projectId: string, chapterNo: number, finalText: string, drafts: readonly DecisionDraft[], ) => Promise; } interface ApiErrorEnvelope { error?: { code?: string; message?: string; details?: { missing_conflict_indices?: number[] } | null; }; } // 验收:乐观置 accepting → 成功置 accepted(呈现「本次将更新」清单); // 失败回滚状态 + toast;409 CONFLICT_UNRESOLVED 解析缺判下标供高亮。 export function useAccept(): UseAccept { const [status, setStatus] = useState("idle"); const [result, setResult] = useState(null); const toast = useToast(); const accept = useCallback( async (projectId, chapterNo, finalText, drafts) => { setStatus("accepting"); const body = buildAcceptRequest(finalText, drafts); const { data, error } = await api.POST( "/projects/{project_id}/chapters/{chapter_no}/accept", { params: { path: { project_id: projectId, chapter_no: chapterNo } }, body, }, ); if (error || !data) { setStatus("error"); const env = error as ApiErrorEnvelope | undefined; const code = env?.error?.code; const missing = env?.error?.details?.missing_conflict_indices ?? []; if (code === "CONFLICT_UNRESOLVED") { toast("尚有冲突未裁决,请先处理高亮项", "error"); return { result: null, missingIndices: missing }; } toast("验收失败,请重试(正文未丢失)", "error"); return { result: null, missingIndices: [] }; } setResult(data); setStatus("accepted"); toast("本章已验收", "success"); return { result: data, missingIndices: [] }; }, [toast], ); return { status, result, accept }; }