WuYongJie 70f954382a 减轻风格化入口加载并防止新建项目超时重复创建
风格化入口并发下载完整配置时,新建项目的响应可能超过前端超时限制,重复点击会产生多个空项目。现在未选项目时只加载轻量配置,进入项目后再加载完整风格配置;配置未变化时按更新时间返回 304,复用已加载数据。配置下载超时覆盖响应正文读取,完整配置保留 30 秒读取时间。

新建请求使用稳定的项目编号,数据库按主键去重;丢失响应后按编号核对结果,尚未确认时保留编号供重试和刷新恢复。已有项目的内容与账号归属检查保持有效。

验证:8 项专项测试通过,辅助测试 633 项通过、1 项原有跳过,TypeScript、改动文件 lint、日志脱敏、凭据、环境、元数据、测试和制品检查通过。全量 lint 仍有 1005 项历史诊断;发布构建和线上验收另行核对。
2026-11-04 09:46:45 +08:00

110 lines
3.6 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
import { and, desc, eq } from "drizzle-orm";
import { z } from "zod";
import { auth } from "@/app/(auth)/auth";
import { db } from "@/lib/db";
import { canvasProject } from "@/lib/db/schema";
import {
extractAgentProjectStateFromCanvasData,
isAgentProjectRow,
} from "@/lib/agents/agent-project-compat";
import { normalizeAgentGenerationProjectPersistedState } from "@/lib/agents/generation-project-state";
export const dynamic = "force-dynamic";
export const revalidate = 0;
function mapAgentProjectRow(row: typeof canvasProject.$inferSelect) {
return {
id: row.id,
userId: row.userId,
title: row.title,
description: row.description || null,
thumbnail: row.thumbnail || null,
projectState: extractAgentProjectStateFromCanvasData(row.canvasData),
createdAt: row.createdAt,
updatedAt: row.updatedAt,
};
}
export async function GET() {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json({ success: false, error: "未登录" }, { status: 401 });
}
const projects = await db
.select()
.from(canvasProject)
.where(eq(canvasProject.userId, session.user.id))
.orderBy(desc(canvasProject.updatedAt));
return NextResponse.json({
success: true,
data: projects.filter(isAgentProjectRow).map(mapAgentProjectRow),
});
} catch (error) {
console.error("[AgentProjects API] 获取项目列表失败:", error);
return NextResponse.json({ success: false, error: "获取生图项目列表失败" }, { status: 500 });
}
}
export async function POST(request: NextRequest) {
try {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json({ success: false, error: "未登录" }, { status: 401 });
}
const body = await request.json().catch(() => ({}));
const requestedId = body.id === undefined ? undefined : z.string().uuid().safeParse(body.id);
if (requestedId && !requestedId.success) {
return NextResponse.json({ success: false, error: "项目编号无效" }, { status: 400 });
}
const id = requestedId?.data;
const title = String(body.title || "").trim() || "未命名生图项目";
const description = String(body.description || "").trim() || null;
const thumbnail = String(body.thumbnail || "").trim() || null;
const projectState = normalizeAgentGenerationProjectPersistedState(body.projectState);
const [insertedProject] = await db
.insert(canvasProject)
.values({
id,
userId: session.user.id,
title,
description,
thumbnail,
workspaceType: "agent",
canvasData: {
nodes: [],
edges: [],
selectedNodeIds: [],
viewport: { x: 0, y: 0, zoom: 1 },
tool: "select",
agentProjectState: projectState,
} as any,
})
.onConflictDoNothing({ target: canvasProject.id })
.returning();
const project = insertedProject || (id ? (await db
.select()
.from(canvasProject)
.where(and(
eq(canvasProject.id, id),
eq(canvasProject.userId, session.user.id),
eq(canvasProject.workspaceType, "agent")
))
.limit(1))[0] : undefined);
if (!project) {
return NextResponse.json({ success: false, error: "项目编号不可用,请重试" }, { status: 409 });
}
return NextResponse.json({ success: true, data: mapAgentProjectRow(project) });
} catch (error) {
console.error("[AgentProjects API] 创建项目失败:", error);
return NextResponse.json({ success: false, error: "创建生图项目失败" }, { status: 500 });
}
}