From 6ea650baf5196ccd6a21f5733a4975e6c84f0e8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=81=B5=E5=BA=94?= Date: Wed, 8 Jul 2026 00:16:34 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=A1=AE=E8=AE=A4?= =?UTF-8?q?=E7=94=9F=E6=88=90=E6=8A=A5=E9=94=99=E5=AF=BC=E8=87=B4React?= =?UTF-8?q?=E5=B4=A9=E6=BA=83=20-=20=E9=80=92=E5=BD=92=E6=8F=90=E5=8F=96?= =?UTF-8?q?=E5=B5=8C=E5=A5=97=E9=94=99=E8=AF=AF=E5=AF=B9=E8=B1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - client.ts: safeExtractString 升级为递归版本,处理 {code, message: {code, message}} 嵌套 - GeneratePage.tsx: catch块 extractString 升级为递归版本 - GeneratePage.tsx: 轮询错误路径 safeExtract 递归处理嵌套对象 - GeneratePage.tsx: 渲染处加 typeof 防御,确保不传对象给 React - 修复 TS2304 变量名错误 (errorMsg → backendMsg) --- apps/web/src/api/client.ts | 15 +++-- apps/web/src/pages/generate/GeneratePage.tsx | 66 ++++++++++++++------ 2 files changed, 57 insertions(+), 24 deletions(-) diff --git a/apps/web/src/api/client.ts b/apps/web/src/api/client.ts index 625eab366..a4f7caada 100644 --- a/apps/web/src/api/client.ts +++ b/apps/web/src/api/client.ts @@ -125,14 +125,19 @@ apiClient.interceptors.response.use( // 注意:后端返回的字段可能是对象 {code, message} 而非字符串,需要安全提取 const data = error.response?.data; const rawServerMsg = data?.detail || data?.message || data?.msg; - // 安全提取字符串:如果是对象则递归提取 message/msg/detail 字段 + // 安全提取字符串:递归处理嵌套对象(后端可能返回 {code, message: {code, message}} 等) const safeExtractString = (val: unknown): string => { if (typeof val === "string") return val; if (typeof val === "object" && val !== null) { - if ("message" in val) - return String((val as { message: unknown }).message); - if ("msg" in val) return String((val as { msg: unknown }).msg); - if ("detail" in val) return String((val as { detail: unknown }).detail); + const obj = val as Record; + if (typeof obj.message === "string") return obj.message; + if (typeof obj.msg === "string") return obj.msg; + if (typeof obj.detail === "string") return obj.detail; + // 嵌套对象:递归提取 + if (typeof obj.message === "object" && obj.message !== null) + return safeExtractString(obj.message); + if (typeof obj.msg === "object" && obj.msg !== null) + return safeExtractString(obj.msg); return JSON.stringify(val); } return ""; diff --git a/apps/web/src/pages/generate/GeneratePage.tsx b/apps/web/src/pages/generate/GeneratePage.tsx index f4c286e41..7e582007b 100644 --- a/apps/web/src/pages/generate/GeneratePage.tsx +++ b/apps/web/src/pages/generate/GeneratePage.tsx @@ -542,15 +542,21 @@ const GeneratePage: React.FC = () => { (c: { status: string }) => c.status === "failed", )?.error_message || "视频生成失败,请联系管理员或重试"; - // 安全提取字符串:如果是对象且有 message 属性,提取 message - const errorMsg = - typeof rawMsg === "string" - ? rawMsg - : typeof rawMsg === "object" && - rawMsg !== null && - "message" in rawMsg - ? String((rawMsg as { message: unknown }).message) - : JSON.stringify(rawMsg); + // 安全提取字符串:递归处理嵌套对象(后端可能返回 {code, message: {code, message}} 等嵌套结构) + const safeExtract = (val: unknown): string => { + if (typeof val === "string") return val; + if (typeof val === "object" && val !== null) { + const obj = val as Record; + if (typeof obj.message === "string") return obj.message; + if (typeof obj.msg === "string") return obj.msg; + if (typeof obj.detail === "string") return obj.detail; + if (obj.message && typeof obj.message === "object") + return safeExtract(obj.message); + return JSON.stringify(val); + } + return String(val ?? ""); + }; + const errorMsg = safeExtract(rawMsg); console.error("[生成失败] planId:", plan.id, "响应:", data); setGenerateError(errorMsg); message.error(errorMsg); @@ -596,15 +602,19 @@ const GeneratePage: React.FC = () => { }; message?: string; }; - // 安全提取错误消息:后端可能返回对象 {code, message} 而非字符串 + // 安全提取错误消息:递归处理嵌套对象(后端可能返回 {code, message: {code, message}} 等) const extractString = (val: unknown): string => { if (typeof val === "string") return val; if (typeof val === "object" && val !== null) { - if ("message" in val) - return String((val as { message: unknown }).message); - if ("msg" in val) return String((val as { msg: unknown }).msg); - if ("detail" in val) - return String((val as { detail: unknown }).detail); + const obj = val as Record; + if (typeof obj.message === "string") return obj.message; + if (typeof obj.msg === "string") return obj.msg; + if (typeof obj.detail === "string") return obj.detail; + // 嵌套对象:递归提取 + if (typeof obj.message === "object" && obj.message !== null) + return extractString(obj.message); + if (typeof obj.msg === "object" && obj.msg !== null) + return extractString(obj.msg); return JSON.stringify(val); } return ""; @@ -622,9 +632,25 @@ const GeneratePage: React.FC = () => { "完整错误:", axiosErr, ); - const errorMsg = backendMsg || "生成失败,请检查网络后重试或联系管理员"; - setGenerateError(errorMsg); - message.error(errorMsg); + // 确保 errorMsg 一定是字符串(后端可能返回 {code, message} 嵌套对象) + const safeExtractErr = (val: unknown): string => { + if (typeof val === "string") return val; + if (typeof val === "object" && val !== null) { + const obj = val as Record; + if (typeof obj.message === "string") return obj.message; + if (typeof obj.msg === "string") return obj.msg; + if (typeof obj.detail === "string") return obj.detail; + // 嵌套对象:递归提取 + if (typeof obj.message === "object") + return safeExtractErr(obj.message); + return JSON.stringify(val); + } + return String(val ?? ""); + }; + const finalMsg = + safeExtractErr(backendMsg) || "生成失败,请检查网络后重试或联系管理员"; + setGenerateError(finalMsg); + message.error(finalMsg); } }, [ title, @@ -1525,7 +1551,9 @@ const GeneratePage: React.FC = () => { 生成失败 - {generateError} + {typeof generateError === "string" + ? generateError + : JSON.stringify(generateError)}