客户端按 ?chapter=N 切章时 React 复用 Workbench 实例,useState(initialText)/ autosave 基线沿用上一章导致显示旧内容。以章号为 key 强制重挂载即用新章草稿刷新。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
57 lines
2.1 KiB
TypeScript
57 lines
2.1 KiB
TypeScript
import { notFound } from "next/navigation";
|
||
|
||
import { Workbench } from "@/components/workbench/Workbench";
|
||
import { fetchDraft, fetchOutline, fetchProject } from "@/lib/api/server";
|
||
import type { ProjectResponse } from "@/lib/api/types";
|
||
import { parseChapterParam, type ChapterEntry } from "@/lib/workbench/chapter";
|
||
|
||
interface PageProps {
|
||
params: Promise<{ id: string }>;
|
||
searchParams: Promise<{ chapter?: string | string[] }>;
|
||
}
|
||
|
||
// 写作工作台页(UX §6.3)。Server Component 取项目 + 该章已存草稿(GET .../draft,
|
||
// 404→null=空编辑器),把正文作为编辑器初值种入,重访时重载已写章节;Workbench
|
||
// 负责编辑/流式/保存(流式照常覆盖初值)。章号由 `?chapter=N` 指定(缺省=第 1 章),
|
||
// 支持写下一章。
|
||
export default async function WritePage({ params, searchParams }: PageProps) {
|
||
const { id } = await params;
|
||
const { chapter } = await searchParams;
|
||
const chapterNo = parseChapterParam(chapter);
|
||
|
||
// 仅当项目确实取不到时才判 404;草稿/瞬时错误不应把整页变成「找不到页面」。
|
||
let project: ProjectResponse;
|
||
try {
|
||
project = await fetchProject(id);
|
||
} catch {
|
||
notFound();
|
||
}
|
||
|
||
// 草稿读取失败(后端瞬时错误 / 新章尚无草稿)→ 空编辑器初值,绝不 404。
|
||
let initialText = "";
|
||
try {
|
||
const draft = await fetchDraft(id, chapterNo);
|
||
initialText = draft?.content ?? "";
|
||
} catch {
|
||
initialText = "";
|
||
}
|
||
|
||
// 大纲章节作目录(fetchOutline 已对空/错误降级为 []);首个节拍当短标题。
|
||
const chapters: ChapterEntry[] = (await fetchOutline(id)).map((c) => ({
|
||
no: c.no,
|
||
title: c.beats?.[0],
|
||
}));
|
||
|
||
return (
|
||
// key=章号:客户端切章(?chapter=N 变化)时强制重挂载,用新章草稿刷新编辑器状态,
|
||
// 避免 Workbench 内 useState(initialText)/autosave 基线沿用上一章而显示旧内容。
|
||
<Workbench
|
||
key={chapterNo}
|
||
project={project}
|
||
chapterNo={chapterNo}
|
||
initialText={initialText}
|
||
chapters={chapters}
|
||
/>
|
||
);
|
||
}
|