Your Name 4db458a69a
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
feat: improve psd template layer editing
2026-05-12 14:44:29 +08:00

121 lines
3.6 KiB
TypeScript

import { NextResponse } from "next/server";
import { auth } from "@/app/(auth)/auth";
import { upsertSystemSetting } from "@/lib/db/queries";
import { readAgentPsdFonts } from "@/lib/agents/psd-font-settings";
import {
AGENT_PSD_TEMPLATES_KEY,
type AgentPsdTemplateMutationResponse,
getEditableAgentPsdTemplateLayers,
isAgentPsdTemplateReady,
isAgentPsdTemplateRuntimeReady,
isAgentPsdTextLayerSlot,
} from "@/lib/agents/psd-template-config";
import {
repairAgentPsdTemplateAssetsIfNeeded,
repairAgentPsdTemplateFontBindings,
} from "@/lib/agents/psd-template-repair";
import { readAgentPsdTemplates } from "@/lib/agents/psd-template-settings";
export const runtime = "nodejs";
export const dynamic = "force-dynamic";
function jsonError(status: number, error: string) {
const payload: AgentPsdTemplateMutationResponse = {
success: false,
error,
};
return NextResponse.json(payload, { status });
}
export async function GET(
_request: Request,
context: { params: Promise<{ id: string }> }
) {
const session = await auth().catch(() => null);
if (!session?.user?.id) {
return jsonError(401, "未登录");
}
try {
const { id } = await context.params;
const [templates, fonts] = await Promise.all([
readAgentPsdTemplates(),
readAgentPsdFonts().catch(
() => [] as Awaited<ReturnType<typeof readAgentPsdFonts>>
),
]);
const fontMap = new Map(fonts.map((font) => [font.id, font]));
const currentTemplate = templates.find(
(candidateTemplate) => candidateTemplate.id === id
);
if (!currentTemplate || currentTemplate.status !== "active") {
return jsonError(404, "未找到 PSD 模板");
}
const repairedTemplate = await repairAgentPsdTemplateAssetsIfNeeded(
currentTemplate
);
if (repairedTemplate !== currentTemplate) {
await upsertSystemSetting({
key: AGENT_PSD_TEMPLATES_KEY,
value: templates.map((entry) =>
entry.id === currentTemplate.id ? repairedTemplate : entry
),
updatedBy: session.user.id,
}).catch((error) => {
console.warn("[PSD Templates] failed to persist repaired detail assets:", {
templateId: currentTemplate.id,
error,
});
});
}
if (!isAgentPsdTemplateReady(repairedTemplate)) {
return jsonError(409, "PSD 模板尚未完成解析");
}
if (!isAgentPsdTemplateRuntimeReady(repairedTemplate)) {
return jsonError(409, "PSD 模板资源尚未准备完成,请稍后重试");
}
if (getEditableAgentPsdTemplateLayers(repairedTemplate).length === 0) {
return jsonError(409, "当前模板没有可编辑图层");
}
const template = repairAgentPsdTemplateFontBindings(repairedTemplate, fonts);
const normalizedTemplate = {
...template,
layers: template.layers.map((layer) => {
if (!isAgentPsdTextLayerSlot(layer) || !layer.fontId) {
return layer;
}
const font = fontMap.get(layer.fontId);
if (!font) {
return layer;
}
return {
...layer,
fontFileUrl: font.fileUrl,
fontContentType: font.contentType,
};
}),
};
const response = NextResponse.json({
success: true,
template: normalizedTemplate,
} satisfies AgentPsdTemplateMutationResponse);
response.headers.set(
"Cache-Control",
"private, max-age=60, stale-while-revalidate=300"
);
return response;
} catch (error) {
console.error("[PSD Templates] detail failed:", error);
return jsonError(503, "PSD 模板详情读取失败");
}
}