Files
writer-work-flow/apps/web/lib/errors/messages.ts
Yaojia Wang 9a623688e8 fix(qa): 前端错误文案——按 API 信封 surface 真实错因,去掉通用 toast
新增 friendlyFromApiError(apiError):兼容业务信封 {error:{code,message}}(ARCH §7.1)
与 FastAPI 422 {detail:[...]},422 映射为友好 VALIDATION 文案(不泄露技术细节)。
接入三处此前吞掉错因、永显通用文案的调用点:
- useOutline(QA #2):原 env.error.code 漏读 422 detail,永显「大纲生成失败」。
- ChainPage / ChainAdjudication(QA #11):原 friendlyError(undefined) 永显通用 toast,
  现 surface 真实 code(如 LLM_UNAVAILABLE→去设置 provider / CONFLICT→提示裁决)。
+ messages.test.ts 加 3 例(业务码带动作 / 422→VALIDATION / 未知形兜底)。
门禁绿:vitest / tsc / eslint 干净。
2026-06-24 18:01:15 +02:00

66 lines
2.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 错误码 → 友好中文文案(+ 可选跳转动作)。
// 对齐后端 ErrorCodeARCH §7.1+ 前端流式/网络码useDraftStream
// 目的UI 不直接暴露 error code给作者可读的下一步。
export interface FriendlyError {
text: string;
// 可选的「下一步」链接(如未连模型 → 去设置)。
actionHref?: string;
actionLabel?: string;
}
const PROVIDER_ACTION = {
actionHref: "/settings/providers",
actionLabel: "去设置提供商",
} as const;
const MESSAGES: Record<string, FriendlyError> = {
// 后端 ErrorCode
LLM_UNAVAILABLE: {
text: "未连接可用模型,去设置里连一个 provider。",
...PROVIDER_ACTION,
},
RATE_LIMITED: { text: "请求过于频繁,稍后再试。" },
CONFLICT_UNRESOLVED: { text: "仍有未裁决的冲突,请先逐条裁决再验收。" },
NOT_FOUND: { text: "资源不存在或已被删除。" },
VALIDATION: { text: "提交内容有误,请检查后重试。" },
INTERNAL: { text: "服务出了点问题,请稍后重试。" },
// 前端流式/网络码
NETWORK: { text: "网络中断,请检查连接后重试。" },
STREAM_FAILED: { text: "写章中断,请重试。" },
};
const DEFAULT_TEXT = "出错了,请稍后重试。";
// 把 (code, 原始 message) 映射为友好文案。
// 已知码 → 预设文案 + 动作;未知码 → 回退到原始 message非空或通用兜底。
export function friendlyError(
code: string | undefined,
fallbackMessage?: string,
): FriendlyError {
if (code && MESSAGES[code]) {
return MESSAGES[code];
}
const fallback = fallbackMessage?.trim();
return { text: fallback && fallback.length > 0 ? fallback : DEFAULT_TEXT };
}
// 从原始 API 错误对象openapi-fetch 的 `error`)提取友好文案。
// 兼容两种信封:业务错误 `{error:{code,message}}`ARCH §7.1)与 FastAPI 校验错误 `{detail:[...]}`。
// 422 一律映射为友好的 VALIDATION 文案(不泄露技术性 detail。未知形 → 通用兜底。
export function friendlyFromApiError(apiError: unknown): FriendlyError {
if (apiError && typeof apiError === "object") {
const env = apiError as {
error?: { code?: string; message?: string };
detail?: unknown;
};
if (env.error?.code) {
return friendlyError(env.error.code, env.error.message);
}
if (env.detail !== undefined) {
return friendlyError("VALIDATION");
}
}
return friendlyError(undefined);
}