diff --git a/app/[locale]/docs/[...slug]/page.tsx b/app/[locale]/docs/[...slug]/page.tsx index 49fbc004..f8c79764 100644 --- a/app/[locale]/docs/[...slug]/page.tsx +++ b/app/[locale]/docs/[...slug]/page.tsx @@ -63,7 +63,9 @@ async function resolveDocPath( } return null; } - // 非 3xx:记录真实状态,便于从 Vercel 日志定位(CF 403 / 后端异常等) + // 404 = 后端无历史映射,是正常的"真 404"结论,不算故障 + if (res.status === 404) return null; + // 其余非 3xx:记录真实状态,便于从 Vercel 日志定位(CF 403 / 后端异常等) console.error("[docs/resolve] non-redirect status", { path: strippedPath, status: res.status, diff --git a/app/api/suggestions/route.ts b/app/api/suggestions/route.ts index a07f1c2f..2fa23003 100644 --- a/app/api/suggestions/route.ts +++ b/app/api/suggestions/route.ts @@ -159,6 +159,11 @@ export async function POST(req: Request) { // 修复大模型可能生成的中文引号 cleanedText = cleanedText.replace(/“/g, '"').replace(/”/g, '"'); + // 修复 key 后的全角冒号 / 冒号被包进引号,如 "action:"xx" 或 "action:"xx" + cleanedText = cleanedText.replace( + /"(title|label|action)"?\s*[::]\s*"/g, + '"$1":"', + ); // 尝试仅提取数组部分,防止 AI 返回了前缀描述文本 const arrayMatch = cleanedText.match(/\[[\s\S]*\]/); @@ -166,7 +171,22 @@ export async function POST(req: Request) { cleanedText = arrayMatch[0]; } - questions = JSON.parse(cleanedText); + try { + questions = JSON.parse(cleanedText); + } catch (parseError) { + // 编号列表 / 多个数组拼接等非法外壳:逐个提取对象 + const objects = (cleanedText.match(/\{[^{}]*\}/g) ?? []).flatMap( + (chunk) => { + try { + return [JSON.parse(chunk)]; + } catch { + return []; + } + }, + ); + if (objects.length === 0) throw parseError; + questions = objects; + } } catch (e) { console.error("解析建议 JSON 失败:", e, "原始文本:", text); diff --git a/mdx-components.tsx b/mdx-components.tsx index e5655539..4f6f781a 100644 --- a/mdx-components.tsx +++ b/mdx-components.tsx @@ -30,7 +30,15 @@ export function getMDXComponents(components?: MDXComponents): MDXComponents { return { ...defaultMdxComponents, // 覆盖默认的 img 映射,使用原生 标签而不是 Next.js Image 组件 - img: (props) => {props.alt, + // 本地相对路径图片会被 remark-image 编译成静态 import,src 是 + // StaticImageData 对象而不是字符串,直接透传会渲染成 "[object Object]" + img: ({ src, ...props }) => { + const resolved = + src && typeof src === "object" && "src" in src + ? (src as { src: string }).src + : src; + return {props.alt; + }, ...components, }; }