fix(web): 后端不可用统一用 BackendDownNotice 替代 404/手搓提示
This commit is contained in:
@@ -2,6 +2,7 @@ import Link from "next/link";
|
|||||||
import { BookOpen, Plus } from "lucide-react";
|
import { BookOpen, Plus } from "lucide-react";
|
||||||
|
|
||||||
import { AppShell } from "@/components/AppShell";
|
import { AppShell } from "@/components/AppShell";
|
||||||
|
import { BackendDownNotice } from "@/components/BackendDownNotice";
|
||||||
import { ProjectLibrary } from "@/components/projects/ProjectLibrary";
|
import { ProjectLibrary } from "@/components/projects/ProjectLibrary";
|
||||||
import { EmptyState } from "@/components/ui/EmptyState";
|
import { EmptyState } from "@/components/ui/EmptyState";
|
||||||
import { PageHeader } from "@/components/ui/PageHeader";
|
import { PageHeader } from "@/components/ui/PageHeader";
|
||||||
@@ -38,9 +39,7 @@ export default async function DashboardPage() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{loadError ? (
|
{loadError ? (
|
||||||
<p className="rounded border border-conflict bg-panel p-6 text-conflict">
|
<BackendDownNotice />
|
||||||
无法连接后端服务,请确认 API 已启动后刷新。
|
|
||||||
</p>
|
|
||||||
) : projects.length === 0 ? (
|
) : projects.length === 0 ? (
|
||||||
<EmptyState
|
<EmptyState
|
||||||
icon={BookOpen}
|
icon={BookOpen}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { notFound } from "next/navigation";
|
import { BackendDownNotice } from "@/components/BackendDownNotice";
|
||||||
|
|
||||||
import { CodexPage } from "@/components/codex/CodexPage";
|
import { CodexPage } from "@/components/codex/CodexPage";
|
||||||
import {
|
import {
|
||||||
fetchCharacters,
|
fetchCharacters,
|
||||||
@@ -37,6 +36,6 @@ export default async function CodexRoutePage({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} catch {
|
} catch {
|
||||||
notFound();
|
return <BackendDownNotice className="m-6" />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
|
|
||||||
|
import { BackendDownNotice } from "@/components/BackendDownNotice";
|
||||||
import { ForeshadowBoard } from "@/components/foreshadow/ForeshadowBoard";
|
import { ForeshadowBoard } from "@/components/foreshadow/ForeshadowBoard";
|
||||||
import { fetchForeshadow, fetchProject } from "@/lib/api/server";
|
import { fetchForeshadow, fetchProject } from "@/lib/api/server";
|
||||||
|
import type { ForeshadowView, ProjectResponse } from "@/lib/api/types";
|
||||||
|
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
params: Promise<{ id: string }>;
|
params: Promise<{ id: string }>;
|
||||||
@@ -11,13 +13,30 @@ interface PageProps {
|
|||||||
// ForeshadowBoard(Client)按 status 分四泳道并承载登记/状态变更交互。
|
// ForeshadowBoard(Client)按 status 分四泳道并承载登记/状态变更交互。
|
||||||
export default async function ForeshadowPage({ params }: PageProps) {
|
export default async function ForeshadowPage({ params }: PageProps) {
|
||||||
const { id } = await params;
|
const { id } = await params;
|
||||||
|
|
||||||
|
// 仅当项目确实不存在(404)才判 notFound;后端不可用等其它失败降级为「后端不可达」提示,
|
||||||
|
// 不把整页变成「找不到页面」。
|
||||||
|
let project: ProjectResponse;
|
||||||
try {
|
try {
|
||||||
const project = await fetchProject(id);
|
project = await fetchProject(id);
|
||||||
const board = await fetchForeshadow(id);
|
} catch (err) {
|
||||||
return (
|
if (isNotFoundError(err)) notFound();
|
||||||
<ForeshadowBoard project={project} initialItems={board.foreshadow ?? []} />
|
return <BackendDownNotice className="m-6" />;
|
||||||
);
|
|
||||||
} catch {
|
|
||||||
notFound();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 伏笔看板(GET .../foreshadow)。瞬时错误降级为空看板,不阻塞进页。
|
||||||
|
let initialItems: ForeshadowView[] = [];
|
||||||
|
try {
|
||||||
|
const board = await fetchForeshadow(id);
|
||||||
|
initialItems = board.foreshadow ?? [];
|
||||||
|
} catch {
|
||||||
|
initialItems = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return <ForeshadowBoard project={project} initialItems={initialItems} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchProject 抛错信息形如「请求失败 404: ...」;据此区分「项目不存在」与「后端不可用」。
|
||||||
|
function isNotFoundError(err: unknown): boolean {
|
||||||
|
return err instanceof Error && err.message.includes("请求失败 404");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
|
|
||||||
|
import { BackendDownNotice } from "@/components/BackendDownNotice";
|
||||||
import { OutlineEditor } from "@/components/outline/OutlineEditor";
|
import { OutlineEditor } from "@/components/outline/OutlineEditor";
|
||||||
import { fetchOutline, fetchProject } from "@/lib/api/server";
|
import { fetchOutline, fetchProject } from "@/lib/api/server";
|
||||||
|
import type { ProjectResponse } from "@/lib/api/types";
|
||||||
|
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
params: Promise<{ id: string }>;
|
params: Promise<{ id: string }>;
|
||||||
@@ -12,13 +14,22 @@ interface PageProps {
|
|||||||
// 仍按需触发 POST .../outline 生成/覆盖所显章节。
|
// 仍按需触发 POST .../outline 生成/覆盖所显章节。
|
||||||
export default async function OutlinePage({ params }: PageProps) {
|
export default async function OutlinePage({ params }: PageProps) {
|
||||||
const { id } = await params;
|
const { id } = await params;
|
||||||
|
|
||||||
|
// 仅当项目确实不存在(404)才判 notFound;后端不可用等其它失败降级为「后端不可达」提示,
|
||||||
|
// 不把整页变成「找不到页面」。次级拉取(大纲)的瞬时错误已在 fetchOutline 内降级为空。
|
||||||
|
let project: ProjectResponse;
|
||||||
try {
|
try {
|
||||||
const project = await fetchProject(id);
|
project = await fetchProject(id);
|
||||||
const initialChapters = await fetchOutline(id);
|
} catch (err) {
|
||||||
return (
|
if (isNotFoundError(err)) notFound();
|
||||||
<OutlineEditor project={project} initialChapters={initialChapters} />
|
return <BackendDownNotice className="m-6" />;
|
||||||
);
|
|
||||||
} catch {
|
|
||||||
notFound();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const initialChapters = await fetchOutline(id);
|
||||||
|
return <OutlineEditor project={project} initialChapters={initialChapters} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchProject 抛错信息形如「请求失败 404: ...」;据此区分「项目不存在」与「后端不可用」。
|
||||||
|
function isNotFoundError(err: unknown): boolean {
|
||||||
|
return err instanceof Error && err.message.includes("请求失败 404");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { notFound } from "next/navigation";
|
import { BackendDownNotice } from "@/components/BackendDownNotice";
|
||||||
|
|
||||||
import { ToolboxPage } from "@/components/toolbox/ToolboxPage";
|
import { ToolboxPage } from "@/components/toolbox/ToolboxPage";
|
||||||
import { fetchProject, fetchToolbox } from "@/lib/api/server";
|
import { fetchProject, fetchToolbox } from "@/lib/api/server";
|
||||||
|
|
||||||
@@ -29,6 +28,6 @@ export default async function ToolboxRoutePage({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} catch {
|
} catch {
|
||||||
notFound();
|
return <BackendDownNotice className="m-6" />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { AppShell } from "@/components/AppShell";
|
import { AppShell } from "@/components/AppShell";
|
||||||
|
import { BackendDownNotice } from "@/components/BackendDownNotice";
|
||||||
import { ProvidersSettings } from "@/components/settings/ProvidersSettings";
|
import { ProvidersSettings } from "@/components/settings/ProvidersSettings";
|
||||||
import { PageHeader } from "@/components/ui/PageHeader";
|
import { PageHeader } from "@/components/ui/PageHeader";
|
||||||
import { fetchKimiOauthStatus, fetchProviders } from "@/lib/api/server";
|
import { fetchKimiOauthStatus, fetchProviders } from "@/lib/api/server";
|
||||||
@@ -34,9 +35,7 @@ export default async function ProvidersSettingsPage() {
|
|||||||
description="配置写手、分析、轻量三类能力档位的路由,并管理 API Key 与 Kimi Code OAuth。"
|
description="配置写手、分析、轻量三类能力档位的路由,并管理 API Key 与 Kimi Code OAuth。"
|
||||||
/>
|
/>
|
||||||
{loadError ? (
|
{loadError ? (
|
||||||
<p className="rounded border border-conflict bg-panel p-6 text-conflict">
|
<BackendDownNotice />
|
||||||
无法连接后端服务,请确认 API 已启动后刷新。
|
|
||||||
</p>
|
|
||||||
) : (
|
) : (
|
||||||
<ProvidersSettings initial={initial} kimiOauth={kimiOauth} />
|
<ProvidersSettings initial={initial} kimiOauth={kimiOauth} />
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user