From d80d41a08debe6c84cecdf0072a8fe200ed793b3 Mon Sep 17 00:00:00 2001 From: Yaojia Wang Date: Wed, 8 Jul 2026 13:27:32 +0200 Subject: [PATCH] =?UTF-8?q?refactor(web):=20ApiErrorEnvelope=20=E6=94=B9?= =?UTF-8?q?=E7=94=B1=E7=94=9F=E6=88=90=20schema=20=E6=B4=BE=E7=94=9F?= =?UTF-8?q?=EF=BC=8C=E9=98=B2=E5=A5=91=E7=BA=A6=E6=BC=82=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 手写 ApiErrorEnvelope 改由 components["schemas"]["ErrorEnvelope"] 派生;accept 端点专属 details.missing_conflict_indices 就地收窄。运行时行为不变(既有 useAccept 测试全绿)。 --- apps/web/lib/review/useAccept.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) 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 }; }