100 lines
2.8 KiB
TypeScript
100 lines
2.8 KiB
TypeScript
import { NextResponse } from "next/server";
|
|||
|
|
import { createSupabaseRouteClient } from "@/lib/supabase/server";
|
||
|
|
import { ensureDefaultWorkspace, resolveActiveWorkspaceId } from "@/lib/workspaces";
|
||
|
|
|
||
|
|
type CreateChildPayload = {
|
||
|
|
parentId: string | null;
|
||
|
|
title?: string;
|
||
|
|
blocks?: unknown;
|
||
|
|
};
|
||
|
|
|
||
|
|
export const dynamic = "force-dynamic";
|
||
|
|
|
||
|
|
export async function POST(request: Request) {
|
||
|
|
const supabase = await createSupabaseRouteClient();
|
||
|
|
const {
|
||
|
|
data: { session },
|
||
|
|
} = await supabase.auth.getSession();
|
||
|
|
|
||
|
|
if (!session) {
|
||
|
|
return NextResponse.json({ error: "未登录无法创建页面" }, { status: 401 });
|
||
|
|
}
|
||
|
|
|
||
|
|
const { parentId, title, blocks }: CreateChildPayload = await request.json();
|
||
|
|
|
||
|
|
if (typeof parentId === "undefined") {
|
||
|
|
return NextResponse.json({ error: "缺少 parentId" }, { status: 400 });
|
||
|
|
}
|
||
|
|
|
||
|
|
let workspaceId: string;
|
||
|
|
let accessScope: "private" | "shared" | "public" = "private";
|
||
|
|
|
||
|
|
if (parentId) {
|
||
|
|
const { data: parentDoc, error: parentError } = await supabase
|
||
|
|
.from("documents")
|
||
|
|
.select("workspace_id,access_scope")
|
||
|
|
.eq("id", parentId)
|
||
|
|
.single();
|
||
|
|
|
||
|
|
if (parentError || !parentDoc) {
|
||
|
|
return NextResponse.json({ error: "父页面不存在" }, { status: 404 });
|
||
|
|
}
|
||
|
|
workspaceId = parentDoc.workspace_id;
|
||
|
|
accessScope = (parentDoc.access_scope ?? "private") as typeof accessScope;
|
||
|
|
} else {
|
||
|
|
await ensureDefaultWorkspace(supabase, session.user.id, session.user.email ?? "我的空间");
|
||
|
|
workspaceId = await resolveActiveWorkspaceId(supabase, session.user.id);
|
||
|
|
if (!workspaceId) {
|
||
|
|
return NextResponse.json({ error: "缺少目标工作空间" }, { status: 400 });
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const siblingQuery = supabase
|
||
|
|
.from("documents")
|
||
|
|
.select("id", { head: true, count: "exact" })
|
||
|
|
.eq("workspace_id", workspaceId);
|
||
|
|
|
||
|
|
if (parentId) {
|
||
|
|
siblingQuery.eq("parent_id", parentId);
|
||
|
|
} else {
|
||
|
|
siblingQuery.is("parent_id", null);
|
||
|
|
}
|
||
|
|
|
||
|
|
const { count: siblingCount = 0, error: countError } = await siblingQuery;
|
||
|
|
|
||
|
|
if (countError) {
|
||
|
|
return NextResponse.json({ error: countError.message }, { status: 500 });
|
||
|
|
}
|
||
|
|
|
||
|
|
const resolvedTitle =
|
||
|
|
title && title.trim().length > 0 ? title.trim() : "未命名页面";
|
||
|
|
|
||
|
|
const contentPayload = Array.isArray(blocks) ? blocks : [];
|
||
|
|
|
||
|
|
const { data, error } = await supabase
|
||
|
|
.from("documents")
|
||
|
|
.insert({
|
||
|
|
user_id: session.user.id,
|
||
|
|
parent_id: parentId,
|
||
|
|
workspace_id: workspaceId,
|
||
|
|
access_scope: accessScope,
|
||
|
|
title: resolvedTitle,
|
||
|
|
content: contentPayload,
|
||
|
|
sort_order: siblingCount,
|
||
|
|
})
|
||
|
|
.select("id,title")
|
||
|
|
.single();
|
||
|
|
|
||
|
|
if (error || !data) {
|
||
|
|
return NextResponse.json(
|
||
|
|
{ error: error?.message ?? "创建子页面失败" },
|
||
|
|
{ status: 500 },
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
return NextResponse.json({
|
||
|
|
pageId: data.id,
|
||
|
|
title: data.title ?? resolvedTitle,
|
||
|
|
});
|
||
|
|
}
|