import { eq } from "drizzle-orm"; import { type NextRequest, NextResponse } from "next/server"; import { auth } from "@/app/(auth)/auth"; import { readAgentPsdFonts } from "@/lib/agents/psd-font-settings"; import { AGENT_PSD_TEMPLATE_CATEGORY_TAG_CONFIG_KEY, defaultAgentPsdTemplateCategoryTagConfig, normalizeAgentPsdTemplateCategoryTagConfig, } from "@/lib/agents/psd-template-category-tag-config"; import { type AgentPsdTemplate, type AgentPsdTemplateListResponse, getEditableAgentPsdTemplateLayers, isAgentPsdTemplateReady, isAgentPsdTemplateRuntimeReady, isAgentPsdTextLayerSlot, normalizeAgentPsdTemplateMode, } from "@/lib/agents/psd-template-config"; import { repairAgentPsdTemplateFontBindings } from "@/lib/agents/psd-template-repair"; import { AGENT_PSD_TEMPLATE_SECONDARY_CATEGORY_CONFIG_KEY, defaultAgentPsdTemplateSecondaryCategoryConfig, normalizeAgentPsdTemplateSecondaryCategoryConfig, } from "@/lib/agents/psd-template-secondary-category-config"; import { readAgentPsdTemplates } from "@/lib/agents/psd-template-settings"; import { AGENT_PSD_TEXT_COLOR_CONFIG_KEY, defaultAgentPsdTextColorConfig, normalizeAgentPsdTextColorConfig, resolveAgentPsdTextColorConfigForBrand, } from "@/lib/agents/psd-text-color-config"; import { db } from "@/lib/db"; import { systemSettings } from "@/lib/db/schema"; export const runtime = "nodejs"; export const dynamic = "force-dynamic"; function jsonError(status: number, error: string) { const payload: AgentPsdTemplateListResponse = { success: false, templates: [], error, }; return NextResponse.json(payload, { status }); } function toPublicTemplateSummary(template: AgentPsdTemplate): AgentPsdTemplate { return { ...template, layers: [], }; } export async function GET(request: NextRequest) { const session = await auth().catch(() => null); if (!session?.user?.id) { return jsonError(401, "未登录"); } try { const requestedBrand = String( request.nextUrl.searchParams.get("brand") || "" ).trim(); const requestedModeRaw = String( request.nextUrl.searchParams.get("mode") || "" ).trim(); const summaryOnly = String(request.nextUrl.searchParams.get("summary") || "").trim() === "1"; const requestedMode = requestedModeRaw === "main" || requestedModeRaw === "sku" ? normalizeAgentPsdTemplateMode(requestedModeRaw) : null; const [ allTemplates, textColorSetting, secondaryCategorySetting, categoryTagSetting, ] = await Promise.all([ readAgentPsdTemplates(), db .select() .from(systemSettings) .where(eq(systemSettings.key, AGENT_PSD_TEXT_COLOR_CONFIG_KEY)) .limit(1) .then((rows) => rows[0]) .catch(() => null), db .select() .from(systemSettings) .where( eq( systemSettings.key, AGENT_PSD_TEMPLATE_SECONDARY_CATEGORY_CONFIG_KEY ) ) .limit(1) .then((rows) => rows[0]) .catch(() => null), db .select() .from(systemSettings) .where( eq(systemSettings.key, AGENT_PSD_TEMPLATE_CATEGORY_TAG_CONFIG_KEY) ) .limit(1) .then((rows) => rows[0]) .catch(() => null), ]); let templates = allTemplates .filter((template) => template.status === "active") .filter(isAgentPsdTemplateReady) .filter((template) => requestedBrand ? template.brandName === requestedBrand : true ) .filter((template) => requestedMode ? template.mode === requestedMode : true ) .filter(isAgentPsdTemplateRuntimeReady) .filter( (template) => getEditableAgentPsdTemplateLayers(template).length > 0 ); if (summaryOnly) { templates = templates.map(toPublicTemplateSummary); } else { const fonts = (await readAgentPsdFonts().catch( () => [] as Awaited> )) as Awaited>; const fontMap = new Map(fonts.map((font) => [font.id, font])); templates = templates .map((template) => repairAgentPsdTemplateFontBindings(template, fonts)) .map((template) => ({ ...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 normalizedTextColorConfig = textColorSetting ? normalizeAgentPsdTextColorConfig(textColorSetting.value) : defaultAgentPsdTextColorConfig; const response = NextResponse.json({ success: true, templates, textColorConfig: requestedBrand ? resolveAgentPsdTextColorConfigForBrand( normalizedTextColorConfig, requestedBrand ) : normalizedTextColorConfig, secondaryCategoryConfig: secondaryCategorySetting ? normalizeAgentPsdTemplateSecondaryCategoryConfig( secondaryCategorySetting.value ) : defaultAgentPsdTemplateSecondaryCategoryConfig, categoryTagConfig: categoryTagSetting ? normalizeAgentPsdTemplateCategoryTagConfig(categoryTagSetting.value) : defaultAgentPsdTemplateCategoryTagConfig, } satisfies AgentPsdTemplateListResponse); response.headers.set( "Cache-Control", "private, max-age=60, stale-while-revalidate=300" ); return response; } catch (error) { console.error("[PSD Templates] list failed:", error); return jsonError(503, "PSD 模板读取失败"); } }