diff --git a/apps/web/lib/review/useAccept.ts b/apps/web/lib/review/useAccept.ts index 32d2ea3..6aa9f12 100644 --- a/apps/web/lib/review/useAccept.ts +++ b/apps/web/lib/review/useAccept.ts @@ -4,6 +4,7 @@ import { useCallback, useState } from "react"; import { api } from "@/lib/api/client"; import { useToast } from "@/components/Toast"; +import type { components } from "@/lib/api/schema"; import type { AcceptResponse } from "@/lib/api/types"; import { buildAcceptRequest, type DecisionDraft } from "./decisions"; @@ -29,12 +30,13 @@ export interface UseAccept { ) => Promise; } -interface ApiErrorEnvelope { - error?: { - code?: string; - message?: string; - details?: { missing_conflict_indices?: number[] } | null; - }; +// 错误信封形状从后端 OpenAPI 生成的 schema 派生,避免与契约漂移(不再手抄字段)。 +type ApiErrorEnvelope = components["schemas"]["ErrorEnvelope"]; + +// accept 端点 409 CONFLICT_UNRESOLVED 在 details 里携带缺判下标; +// 生成 schema 的 details 为松散 `{[k]: unknown}`,此处就地收窄该端点专属字段。 +interface ConflictErrorDetails { + missing_conflict_indices?: number[]; } // 验收:乐观置 accepting → 成功置 accepted(呈现「本次将更新」清单); @@ -59,7 +61,8 @@ export function useAccept(): UseAccept { setStatus("error"); const env = error as ApiErrorEnvelope | undefined; const code = env?.error?.code; - const missing = env?.error?.details?.missing_conflict_indices ?? []; + const details = env?.error?.details as ConflictErrorDetails | undefined; + const missing = details?.missing_conflict_indices ?? []; if (code === "CONFLICT_UNRESOLVED") { return { result: null, missingIndices: missing, conflictUnresolved: true }; }