From 47eb42f274e958ab307d26bc354eb19aab6f8b97 Mon Sep 17 00:00:00 2001 From: Yaojia Wang Date: Mon, 29 Jun 2026 16:52:43 +0200 Subject: [PATCH] =?UTF-8?q?fix(web):=20=E5=90=8E=E7=AB=AF=E4=B8=8D?= =?UTF-8?q?=E5=8F=AF=E7=94=A8=E7=BB=9F=E4=B8=80=E7=94=A8=20BackendDownNoti?= =?UTF-8?q?ce=20=E6=9B=BF=E4=BB=A3=20404/=E6=89=8B=E6=90=93=E6=8F=90?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/app/page.tsx | 5 ++- apps/web/app/projects/[id]/codex/page.tsx | 5 ++- .../web/app/projects/[id]/foreshadow/page.tsx | 33 +++++++++++++++---- apps/web/app/projects/[id]/outline/page.tsx | 25 ++++++++++---- apps/web/app/projects/[id]/toolbox/page.tsx | 5 ++- apps/web/app/settings/providers/page.tsx | 5 ++- 6 files changed, 52 insertions(+), 26 deletions(-) diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx index ea774bb..48d8def 100644 --- a/apps/web/app/page.tsx +++ b/apps/web/app/page.tsx @@ -2,6 +2,7 @@ import Link from "next/link"; import { BookOpen, Plus } from "lucide-react"; import { AppShell } from "@/components/AppShell"; +import { BackendDownNotice } from "@/components/BackendDownNotice"; import { ProjectLibrary } from "@/components/projects/ProjectLibrary"; import { EmptyState } from "@/components/ui/EmptyState"; import { PageHeader } from "@/components/ui/PageHeader"; @@ -38,9 +39,7 @@ export default async function DashboardPage() { /> {loadError ? ( -

- 无法连接后端服务,请确认 API 已启动后刷新。 -

+ ) : projects.length === 0 ? ( ); } catch { - notFound(); + return ; } } diff --git a/apps/web/app/projects/[id]/foreshadow/page.tsx b/apps/web/app/projects/[id]/foreshadow/page.tsx index 832097c..8d80e12 100644 --- a/apps/web/app/projects/[id]/foreshadow/page.tsx +++ b/apps/web/app/projects/[id]/foreshadow/page.tsx @@ -1,7 +1,9 @@ import { notFound } from "next/navigation"; +import { BackendDownNotice } from "@/components/BackendDownNotice"; import { ForeshadowBoard } from "@/components/foreshadow/ForeshadowBoard"; import { fetchForeshadow, fetchProject } from "@/lib/api/server"; +import type { ForeshadowView, ProjectResponse } from "@/lib/api/types"; interface PageProps { params: Promise<{ id: string }>; @@ -11,13 +13,30 @@ interface PageProps { // ForeshadowBoard(Client)按 status 分四泳道并承载登记/状态变更交互。 export default async function ForeshadowPage({ params }: PageProps) { const { id } = await params; + + // 仅当项目确实不存在(404)才判 notFound;后端不可用等其它失败降级为「后端不可达」提示, + // 不把整页变成「找不到页面」。 + let project: ProjectResponse; try { - const project = await fetchProject(id); - const board = await fetchForeshadow(id); - return ( - - ); - } catch { - notFound(); + project = await fetchProject(id); + } catch (err) { + if (isNotFoundError(err)) notFound(); + return ; } + + // 伏笔看板(GET .../foreshadow)。瞬时错误降级为空看板,不阻塞进页。 + let initialItems: ForeshadowView[] = []; + try { + const board = await fetchForeshadow(id); + initialItems = board.foreshadow ?? []; + } catch { + initialItems = []; + } + + return ; +} + +// fetchProject 抛错信息形如「请求失败 404: ...」;据此区分「项目不存在」与「后端不可用」。 +function isNotFoundError(err: unknown): boolean { + return err instanceof Error && err.message.includes("请求失败 404"); } diff --git a/apps/web/app/projects/[id]/outline/page.tsx b/apps/web/app/projects/[id]/outline/page.tsx index 3a12da2..0de0bd5 100644 --- a/apps/web/app/projects/[id]/outline/page.tsx +++ b/apps/web/app/projects/[id]/outline/page.tsx @@ -1,7 +1,9 @@ import { notFound } from "next/navigation"; +import { BackendDownNotice } from "@/components/BackendDownNotice"; import { OutlineEditor } from "@/components/outline/OutlineEditor"; import { fetchOutline, fetchProject } from "@/lib/api/server"; +import type { ProjectResponse } from "@/lib/api/types"; interface PageProps { params: Promise<{ id: string }>; @@ -12,13 +14,22 @@ interface PageProps { // 仍按需触发 POST .../outline 生成/覆盖所显章节。 export default async function OutlinePage({ params }: PageProps) { const { id } = await params; + + // 仅当项目确实不存在(404)才判 notFound;后端不可用等其它失败降级为「后端不可达」提示, + // 不把整页变成「找不到页面」。次级拉取(大纲)的瞬时错误已在 fetchOutline 内降级为空。 + let project: ProjectResponse; try { - const project = await fetchProject(id); - const initialChapters = await fetchOutline(id); - return ( - - ); - } catch { - notFound(); + project = await fetchProject(id); + } catch (err) { + if (isNotFoundError(err)) notFound(); + return ; } + + const initialChapters = await fetchOutline(id); + return ; +} + +// fetchProject 抛错信息形如「请求失败 404: ...」;据此区分「项目不存在」与「后端不可用」。 +function isNotFoundError(err: unknown): boolean { + return err instanceof Error && err.message.includes("请求失败 404"); } diff --git a/apps/web/app/projects/[id]/toolbox/page.tsx b/apps/web/app/projects/[id]/toolbox/page.tsx index becf65d..9867bb5 100644 --- a/apps/web/app/projects/[id]/toolbox/page.tsx +++ b/apps/web/app/projects/[id]/toolbox/page.tsx @@ -1,5 +1,4 @@ -import { notFound } from "next/navigation"; - +import { BackendDownNotice } from "@/components/BackendDownNotice"; import { ToolboxPage } from "@/components/toolbox/ToolboxPage"; import { fetchProject, fetchToolbox } from "@/lib/api/server"; @@ -29,6 +28,6 @@ export default async function ToolboxRoutePage({ /> ); } catch { - notFound(); + return ; } } diff --git a/apps/web/app/settings/providers/page.tsx b/apps/web/app/settings/providers/page.tsx index 0c855fc..b7ebdee 100644 --- a/apps/web/app/settings/providers/page.tsx +++ b/apps/web/app/settings/providers/page.tsx @@ -1,4 +1,5 @@ import { AppShell } from "@/components/AppShell"; +import { BackendDownNotice } from "@/components/BackendDownNotice"; import { ProvidersSettings } from "@/components/settings/ProvidersSettings"; import { PageHeader } from "@/components/ui/PageHeader"; import { fetchKimiOauthStatus, fetchProviders } from "@/lib/api/server"; @@ -34,9 +35,7 @@ export default async function ProvidersSettingsPage() { description="配置写手、分析、轻量三类能力档位的路由,并管理 API Key 与 Kimi Code OAuth。" /> {loadError ? ( -

- 无法连接后端服务,请确认 API 已启动后刷新。 -

+ ) : ( )}