Files
writer-work-flow/apps/web/app/projects/[id]/review/page.tsx

79 lines
2.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { notFound } from "next/navigation";
import { ReviewReport } from "@/components/review/ReviewReport";
import {
fetchDraft,
fetchOutline,
fetchProject,
fetchReviews,
} from "@/lib/api/server";
import type { ProjectResponse } from "@/lib/api/types";
import { latestReview } from "@/lib/review/history";
import type { ChapterEntry } from "@/lib/workbench/chapter";
interface PageProps {
params: Promise<{ id: string }>;
searchParams: Promise<{ chapter?: string }>;
}
const DEFAULT_CHAPTER_NO = 1;
// 审稿报告页UX §6.4。Server Component 取项目 + 审稿留痕历史(新→旧);
// ReviewReportClient承载 SSE 重审 / 裁决 / 验收交互。
export default async function ReviewPage({ params, searchParams }: PageProps) {
const { id } = await params;
const { chapter } = await searchParams;
const chapterNo = parsePositiveInt(chapter) ?? DEFAULT_CHAPTER_NO;
// 仅当项目确实取不到时才判 404审稿/草稿/大纲等次级拉取的瞬时错误不应把整页变成「找不到」。
let project: ProjectResponse;
try {
project = await fetchProject(id);
} catch {
notFound();
}
// 审稿留痕GET .../reviews失败→空历史
let initialReview;
try {
const history = await fetchReviews(id, chapterNo);
initialReview = latestReview(history.reviews);
} catch {
initialReview = undefined;
}
// 终稿初值取已存草稿GET .../draft404→null→"");否则 final_text 为空 → accept 422。
let initialDraft = "";
try {
const draft = await fetchDraft(id, chapterNo);
initialDraft = draft?.content ?? "";
} catch {
initialDraft = "";
}
// 大纲章节作章节导航目录fetchOutline 已对空/错误降级为 []);首个节拍当短标题。
const chapters: ChapterEntry[] = (await fetchOutline(id)).map((c) => ({
no: c.no,
title: c.beats?.[0],
}));
return (
// key=章号:客户端切章(?chapter=N 变化)时强制重挂载,用新章审稿/草稿刷新状态,
// 避免 ReviewReport 内 useState 基线沿用上一章。
<ReviewReport
key={chapterNo}
project={project}
chapterNo={chapterNo}
initialReview={initialReview}
initialDraft={initialDraft}
chapters={chapters}
/>
);
}
function parsePositiveInt(raw: string | undefined): number | null {
if (!raw) return null;
const n = Number.parseInt(raw, 10);
return Number.isInteger(n) && n > 0 ? n : null;
}