import { NextRequest, NextResponse } from "next/server"; import { upsertSystemSetting } from "@/lib/db/queries"; import { auth } from "@/app/(auth)/auth"; import { db } from "@/lib/db"; import { systemSettings } from "@/lib/db/schema"; import { eq } from "drizzle-orm"; import { AGENT_PSD_TEMPLATES_KEY, getEditableAgentPsdTemplateLayers, isAgentPsdTextLayerSlot, isAgentPsdTemplateReady, normalizeAgentPsdTemplateMode, type AgentPsdTemplateListResponse, } from "@/lib/agents/psd-template-config"; import { AGENT_PSD_TEXT_COLOR_CONFIG_KEY, defaultAgentPsdTextColorConfig, normalizeAgentPsdTextColorConfig, resolveAgentPsdTextColorConfigForBrand, } from "@/lib/agents/psd-text-color-config"; import { AGENT_PSD_TEMPLATE_SECONDARY_CATEGORY_CONFIG_KEY, defaultAgentPsdTemplateSecondaryCategoryConfig, normalizeAgentPsdTemplateSecondaryCategoryConfig, } from "@/lib/agents/psd-template-secondary-category-config"; import { AGENT_PSD_TEMPLATE_CATEGORY_TAG_CONFIG_KEY, defaultAgentPsdTemplateCategoryTagConfig, normalizeAgentPsdTemplateCategoryTagConfig, } from "@/lib/agents/psd-template-category-tag-config"; import { readAgentPsdFonts } from "@/lib/agents/psd-font-settings"; import { repairAgentPsdTemplateAssetsIfNeeded } from "@/lib/agents/psd-template-repair"; import { resolveAgentPsdTemplateTextStyles } from "@/lib/agents/psd-template-style-resolver"; 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: AgentPsdTemplateListResponse = { success: false, templates: [], error, }; return NextResponse.json(payload, { status }); } 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 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), ]); const repairedTemplateMap = new Map< string, Awaited>[number] >(); for (const template of allTemplates) { if ( template.status !== "active" || !isAgentPsdTemplateReady(template) || (requestedBrand ? template.brandName !== requestedBrand : false) || (requestedMode ? template.mode !== requestedMode : false) || getEditableAgentPsdTemplateLayers(template).length === 0 ) { continue; } const repairedTemplate = await repairAgentPsdTemplateAssetsIfNeeded(template); if (repairedTemplate !== template) { repairedTemplateMap.set(template.id, repairedTemplate); } } const sourceTemplates = repairedTemplateMap.size > 0 ? allTemplates.map((template) => repairedTemplateMap.get(template.id) || template) : allTemplates; if (repairedTemplateMap.size > 0) { await upsertSystemSetting({ key: AGENT_PSD_TEMPLATES_KEY, value: sourceTemplates, updatedBy: session.user.id, }).catch((error) => { console.warn("[PSD Templates] failed to persist repaired assets:", error); }); } const fonts = (await readAgentPsdFonts().catch( () => [] as Awaited> )) as Awaited>; const fontMap = new Map(fonts.map((font) => [font.id, font])); const templates = await Promise.all( sourceTemplates .filter((template) => template.status === "active") .filter(isAgentPsdTemplateReady) .filter((template) => requestedBrand ? template.brandName === requestedBrand : true ) .filter((template) => (requestedMode ? template.mode === requestedMode : true)) .filter((template) => getEditableAgentPsdTemplateLayers(template).length > 0) .map(async (template) => { const resolvedTemplate = await resolveAgentPsdTemplateTextStyles(template).catch( () => template ); return { ...resolvedTemplate, layers: resolvedTemplate.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; return 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); } catch (error) { console.error("[PSD Templates] list failed:", error); return jsonError(503, "PSD 模板读取失败"); } }