Your Name dfc5f704b4
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
chore: sync latest app updates
2026-04-12 23:45:00 +08:00

2547 lines
87 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";
import { db } from "@/lib/db";
import { siteSettings, systemSettings } from "@/lib/db/schema";
import { eq } from "drizzle-orm";
import { auth } from "@/app/(auth)/auth";
import { isAgentWorkflowAdminType, isSiteAdminType } from "@/lib/middleware/admin";
import {
defaultMembershipConfig,
defaultMembershipUserOverrides,
normalizeMembershipConfig,
normalizeMembershipUserOverrides,
} from "@/lib/membership/config";
import {
defaultPointsPackages,
defaultPointsSystemConfig,
normalizePointsPackages,
normalizePointsSystemConfig,
POINTS_PACKAGES_KEY,
POINTS_SYSTEM_CONFIG_KEY,
} from "@/lib/points/config";
import {
defaultDulupayConfig,
DULUPAY_CONFIG_KEY,
normalizeDulupayConfig,
normalizeDulupayForPublic,
} from "@/lib/payment/dulupay-config";
import {
AGENT_SECONDARY_TYPE_CONFIG_KEY,
defaultAgentSecondaryTypeConfig,
normalizeAgentSecondaryTypeConfig,
} from "@/lib/agents/secondary-type-config";
import {
AGENT_WORKFLOW_UI_CONFIG_KEY,
defaultAgentWorkflowUiConfig,
normalizeAgentWorkflowUiConfig,
} from "@/lib/agents/workflow-ui-config";
import {
AGENT_WORKFLOW_BRAND_MODEL_CONFIG_KEY,
defaultAgentWorkflowBrandModelConfig,
normalizeAgentWorkflowBrandModelConfig,
} from "@/lib/agents/workflow-brand-model-config";
import {
AGENT_WORKFLOW_MATERIAL_API_CONFIG_KEY,
defaultAgentWorkflowMaterialApiConfig,
normalizeAgentWorkflowMaterialApiConfig,
normalizeAgentWorkflowMaterialApiConfigForPublic,
} from "@/lib/agents/workflow-material-config";
import {
AGENT_WORKFLOW_GOODS_INFO_API_CONFIG_KEY,
defaultAgentWorkflowGoodsInfoApiConfig,
normalizeAgentWorkflowGoodsInfoApiConfig,
normalizeAgentWorkflowGoodsInfoApiConfigForPublic,
} from "@/lib/agents/workflow-goods-info-config";
import {
AGENT_WORKFLOW_SHOWCASE_CONFIG_KEY,
defaultAgentWorkflowShowcaseConfig,
normalizeAgentWorkflowShowcaseConfig,
} from "@/lib/agents/workflow-showcase-config";
import {
AGENT_PSD_TEXT_COLOR_CONFIG_KEY,
defaultAgentPsdTextColorConfig,
normalizeAgentPsdTextColorConfig,
} 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,
buildAgentPsdTemplateCategoryTagIndex,
defaultAgentPsdTemplateCategoryTagConfig,
defaultAgentPsdTemplateCategoryTagIndex,
normalizeAgentPsdTemplateCategoryTagConfig,
} from "@/lib/agents/psd-template-category-tag-config";
import { readAgentPsdTemplates } from "@/lib/agents/psd-template-settings";
import {
AGENT_PRESET_LIBRARY_CONFIG_KEY,
defaultAgentPresetLibraryConfig,
normalizeAgentPresetLibraryConfig,
} from "@/lib/agents/preset-library-config";
import {
defaultOssImageMigrationConfig,
normalizeOssImageMigrationConfig,
OSS_MIGRATION_CONFIG_KEY,
} from "@/lib/storage/migration-config";
import {
getHomeChatAnimationHtmlBytes,
HOME_CHAT_ANIMATION_CONFIG_KEY,
HOME_CHAT_ANIMATION_MAX_BYTES,
normalizeHomeChatAnimationConfig,
} from "@/lib/home/home-animation-config";
import type { AgentCategoryTreeConfig } from "@/types/agent";
const HOME_VARIANT_KEY = "home_variant";
// Historically stored as "home_surprise_categories" but used for the featured gallery categories.
const HOME_SURPRISE_CATEGORIES_KEY = "home_surprise_categories";
const AI_DETAIL_GENERATOR_ENABLED_KEY = "ai_detail_generator_enabled";
const LOVART_COMPOSER_PREVIEW_TEXTS_KEY = "lovart_composer_preview_texts";
const LOVART_COMPOSER_PREFIX_KEY = "lovart_composer_prefix";
const LOVART_PROMPT_TAG_VISIBILITY_KEY = "lovart_prompt_tag_visibility";
const CONTACT_CONFIG_KEY = "contact_config";
const MEMBERSHIP_CONFIG_KEY = "membership_config";
const MEMBERSHIP_USER_OVERRIDES_KEY = "membership_user_plan_overrides";
const STORAGE_FAILOVER_CONFIG_KEY = "storage_failover_config";
const REALTIME_CANVAS_CONFIG_KEY = "realtime_canvas_config";
const LAYER_SPLIT_CONFIG_KEY = "layer_split_config";
const AGENT_CATEGORY_TREE_CONFIG_KEY = "agent_category_tree_config";
const CANVAS_AGENT_MODE_ENABLED_KEY = "canvas_agent_mode_enabled";
const VIDEO_CANVAS_SIDEBAR_ENABLED_KEY = "video_canvas_sidebar_enabled";
function normalizeHomeVariant(value: unknown): "classic" | "lovart" {
return value === "lovart" ? "lovart" : "classic";
}
function normalizeSurpriseCategories(value: unknown): string[] {
if (!Array.isArray(value)) {
return ["全部", "精选"];
}
const normalized = value
.map((item) => String(item || "").trim())
.filter(Boolean)
// legacy typo compatibility: treat "惊喜" as "精选"
.map((item) => (item === "惊喜" ? "精选" : item))
.slice(0, 12);
if (normalized.length === 0) {
return ["全部", "精选"];
}
const unique = Array.from(new Set(normalized));
if (!unique.includes("全部")) {
unique.unshift("全部");
}
return unique;
}
function normalizeLovartComposerPreviewTexts(value: unknown): string[] {
const defaults = [
"打造引人注目的社交媒体视觉",
"帮我把这张产品图做成高级电商海报",
"基于参考图延展 3 套同风格方案",
];
if (!Array.isArray(value)) {
return defaults;
}
const normalized = value
.map((item) => String(item || "").trim())
.filter(Boolean)
.slice(0, 20);
return normalized.length > 0 ? normalized : defaults;
}
function normalizeLovartComposerPrefix(value: unknown): string {
const normalized = String(value || "").trim();
if (!normalized) {
return "让Buyi-ai";
}
return normalized.slice(0, 40);
}
function normalizeLovartPromptTagVisibility(value: unknown): {
nanoBananaPro: boolean;
design: boolean;
branding: boolean;
illustration: boolean;
ecommerce: boolean;
video: boolean;
} {
const raw =
value && typeof value === "object" && !Array.isArray(value)
? (value as Record<string, unknown>)
: {};
return {
nanoBananaPro: raw.nanoBananaPro !== false,
design: raw.design !== false,
branding: raw.branding !== false,
illustration: raw.illustration !== false,
ecommerce: raw.ecommerce !== false,
video: raw.video !== false,
};
}
function normalizeContactConfig(value: unknown): {
phone: string;
wechatQrUrl: string;
} {
const raw =
value && typeof value === "object" && !Array.isArray(value)
? (value as Record<string, unknown>)
: {};
const phone = String(raw.phone || "").trim().slice(0, 64);
const wechatQrUrl = String(raw.wechatQrUrl || "").trim().slice(0, 1000);
return {
phone,
wechatQrUrl,
};
}
function normalizeStorageFailoverConfig(value: unknown): {
enabled: boolean;
backupStorageConfigId: string;
} {
const raw =
value && typeof value === "object" && !Array.isArray(value)
? (value as Record<string, unknown>)
: {};
const backupStorageConfigId = String(raw.backupStorageConfigId || "").trim();
return {
enabled: raw.enabled === true,
backupStorageConfigId,
};
}
function normalizeCanvasAgentModeEnabled(value: unknown): boolean {
return value !== false;
}
function normalizeVideoCanvasSidebarEnabled(value: unknown): boolean {
return value !== false;
}
function normalizeLayerSplitEnabled(value: unknown): boolean {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return false;
}
return (value as { enabled?: unknown }).enabled === true;
}
function normalizeAgentCategoryTreeConfig(value: unknown): AgentCategoryTreeConfig {
const raw =
value && typeof value === "object" && !Array.isArray(value)
? (value as Record<string, unknown>)
: {};
const normalizeList = (input: unknown) => {
if (!Array.isArray(input)) return [] as string[];
return Array.from(
new Set(
input
.map((item) => String(item || "").trim())
.filter(Boolean)
.slice(0, 200)
)
);
};
return {
productCategories: normalizeList(raw.productCategories),
audienceTags: normalizeList(raw.audienceTags),
usageScenarios: normalizeList(raw.usageScenarios),
brands: normalizeList(raw.brands),
};
}
// GET /api/site-settings - 获取网站设置 (公开)
export async function GET() {
try {
const session = await auth().catch(() => null);
const isAdmin = isSiteAdminType(session?.user?.type);
const canManageAgentWorkflow = isAgentWorkflowAdminType(session?.user?.type);
const [
settings,
notificationSetting,
homeVariantSetting,
surpriseCategoriesSetting,
aiDetailGeneratorEnabledSetting,
lovartComposerPreviewTextsSetting,
lovartComposerPrefixSetting,
lovartPromptTagVisibilitySetting,
contactConfigSetting,
membershipConfigSetting,
membershipOverridesSetting,
pointsSystemConfigSetting,
pointsPackagesSetting,
dulupayConfigSetting,
realtimeCanvasConfigSetting,
layerSplitConfigSetting,
canvasAgentModeEnabledSetting,
videoCanvasSidebarEnabledSetting,
storageFailoverConfigSetting,
ossImageMigrationConfigSetting,
agentPresetLibraryConfigSetting,
agentCategoryTreeConfigSetting,
agentSecondaryTypeConfigSetting,
agentWorkflowUiConfigSetting,
agentWorkflowMaterialApiConfigSetting,
agentWorkflowGoodsInfoApiConfigSetting,
agentWorkflowBrandModelConfigSetting,
agentWorkflowShowcaseConfigSetting,
agentPsdTextColorConfigSetting,
agentPsdTemplateSecondaryCategoryConfigSetting,
agentPsdTemplateCategoryTagConfigSetting,
agentPsdTemplates,
] = await Promise.all([
db.select().from(siteSettings).limit(1).then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, "login_notification"))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, HOME_VARIANT_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, HOME_SURPRISE_CATEGORIES_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, AI_DETAIL_GENERATOR_ENABLED_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, LOVART_COMPOSER_PREVIEW_TEXTS_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, LOVART_COMPOSER_PREFIX_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, LOVART_PROMPT_TAG_VISIBILITY_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, CONTACT_CONFIG_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, MEMBERSHIP_CONFIG_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, MEMBERSHIP_USER_OVERRIDES_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, POINTS_SYSTEM_CONFIG_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, POINTS_PACKAGES_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, DULUPAY_CONFIG_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, REALTIME_CANVAS_CONFIG_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, LAYER_SPLIT_CONFIG_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, CANVAS_AGENT_MODE_ENABLED_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, VIDEO_CANVAS_SIDEBAR_ENABLED_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, STORAGE_FAILOVER_CONFIG_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, OSS_MIGRATION_CONFIG_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, AGENT_PRESET_LIBRARY_CONFIG_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, AGENT_CATEGORY_TREE_CONFIG_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, AGENT_SECONDARY_TYPE_CONFIG_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, AGENT_WORKFLOW_UI_CONFIG_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, AGENT_WORKFLOW_MATERIAL_API_CONFIG_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, AGENT_WORKFLOW_GOODS_INFO_API_CONFIG_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, AGENT_WORKFLOW_BRAND_MODEL_CONFIG_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, AGENT_WORKFLOW_SHOWCASE_CONFIG_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, AGENT_PSD_TEXT_COLOR_CONFIG_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, AGENT_PSD_TEMPLATE_SECONDARY_CATEGORY_CONFIG_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, AGENT_PSD_TEMPLATE_CATEGORY_TAG_CONFIG_KEY))
.limit(1)
.then(rows => rows[0]),
readAgentPsdTemplates().catch(() => []),
]);
const notification = notificationSetting?.value || { enabled: false, title: "", content: "" };
const homeVariant = normalizeHomeVariant(homeVariantSetting?.value);
const surpriseCategories = normalizeSurpriseCategories(surpriseCategoriesSetting?.value);
const aiDetailGenerationEnabled = Boolean(aiDetailGeneratorEnabledSetting?.value);
const lovartComposerPreviewTexts = normalizeLovartComposerPreviewTexts(
lovartComposerPreviewTextsSetting?.value
);
const lovartComposerPrefix = normalizeLovartComposerPrefix(
lovartComposerPrefixSetting?.value
);
const lovartPromptTagVisibility = normalizeLovartPromptTagVisibility(
lovartPromptTagVisibilitySetting?.value
);
const contactConfig = normalizeContactConfig(contactConfigSetting?.value);
const membershipConfig = normalizeMembershipConfig(membershipConfigSetting?.value);
const membershipUserOverrides = normalizeMembershipUserOverrides(
membershipOverridesSetting?.value
);
const pointsSystemConfig = normalizePointsSystemConfig(
pointsSystemConfigSetting?.value
);
const pointsPackages = normalizePointsPackages(pointsPackagesSetting?.value);
const dulupayConfig = isAdmin
? normalizeDulupayConfig(dulupayConfigSetting?.value)
: normalizeDulupayForPublic(dulupayConfigSetting?.value);
const realtimeCanvasServiceEnabled =
(realtimeCanvasConfigSetting?.value as { enabled?: boolean } | undefined)?.enabled !== false;
const layerSplitEnabled = normalizeLayerSplitEnabled(
layerSplitConfigSetting?.value
);
const canvasAgentModeEnabled = normalizeCanvasAgentModeEnabled(
canvasAgentModeEnabledSetting?.value
);
const videoCanvasSidebarEnabled = normalizeVideoCanvasSidebarEnabled(
videoCanvasSidebarEnabledSetting?.value
);
const storageFailoverConfig = normalizeStorageFailoverConfig(
storageFailoverConfigSetting?.value
);
const ossImageMigrationConfig = normalizeOssImageMigrationConfig(
ossImageMigrationConfigSetting?.value
);
const agentPresetLibraryConfig = normalizeAgentPresetLibraryConfig(
agentPresetLibraryConfigSetting?.value
);
const agentCategoryTreeConfig = normalizeAgentCategoryTreeConfig(
agentCategoryTreeConfigSetting?.value
);
const agentSecondaryTypeConfig = normalizeAgentSecondaryTypeConfig(
agentSecondaryTypeConfigSetting?.value
);
const agentWorkflowUiConfig = normalizeAgentWorkflowUiConfig(
agentWorkflowUiConfigSetting?.value
);
const agentWorkflowMaterialApiConfig = canManageAgentWorkflow
? normalizeAgentWorkflowMaterialApiConfig(agentWorkflowMaterialApiConfigSetting?.value)
: normalizeAgentWorkflowMaterialApiConfigForPublic(
agentWorkflowMaterialApiConfigSetting?.value
);
const agentWorkflowGoodsInfoApiConfig = canManageAgentWorkflow
? normalizeAgentWorkflowGoodsInfoApiConfig(agentWorkflowGoodsInfoApiConfigSetting?.value)
: normalizeAgentWorkflowGoodsInfoApiConfigForPublic(
agentWorkflowGoodsInfoApiConfigSetting?.value
);
const agentWorkflowBrandModelConfig = normalizeAgentWorkflowBrandModelConfig(
agentWorkflowBrandModelConfigSetting?.value
);
const agentWorkflowShowcaseConfig = normalizeAgentWorkflowShowcaseConfig(
agentWorkflowShowcaseConfigSetting?.value
);
const agentPsdTextColorConfig = normalizeAgentPsdTextColorConfig(
agentPsdTextColorConfigSetting?.value
);
const agentPsdTemplateSecondaryCategoryConfig =
normalizeAgentPsdTemplateSecondaryCategoryConfig(
agentPsdTemplateSecondaryCategoryConfigSetting?.value
);
const agentPsdTemplateCategoryTagConfig =
normalizeAgentPsdTemplateCategoryTagConfig(
agentPsdTemplateCategoryTagConfigSetting?.value
);
const agentPsdTemplateCategoryTagIndex = buildAgentPsdTemplateCategoryTagIndex({
templates: agentPsdTemplates,
config: agentPsdTemplateCategoryTagConfig,
});
// 如果没有设置记录,返回默认值
const baseSettings = settings || {
siteName: "AI Chatbot",
siteLogo: null,
siteLogoDark: null,
favicon: null,
showAutoModel: true,
defaultTheme: "system",
usageTimeEnabled: false,
usageTimeStart: "08:00",
usageTimeEnd: "20:00",
usageTimeMessage: "由壹点累了也是需要休息的",
bannerEnabled: true,
bannerText: "升级会员, Nano Banana Pro 免费365天!",
bannerLink: null,
toolbox1Name: "工具箱",
toolbox1Enabled: true,
toolbox2Name: "工具箱2",
toolbox2Enabled: false,
tutorialVideoUrl: null,
tutorialEnabled: false,
rankingEnabled: true,
productPlanningEnabled: true,
canvasEnabled: true,
agentEnabled: true,
canvasAgentModeEnabled: true,
videoCanvasSidebarEnabled: true,
agentPresetLibraryConfig: defaultAgentPresetLibraryConfig,
agentCategoryTreeConfig: normalizeAgentCategoryTreeConfig(undefined),
agentSecondaryTypeConfig: defaultAgentSecondaryTypeConfig,
agentWorkflowUiConfig: defaultAgentWorkflowUiConfig,
agentWorkflowMaterialApiConfig: defaultAgentWorkflowMaterialApiConfig,
agentWorkflowGoodsInfoApiConfig: defaultAgentWorkflowGoodsInfoApiConfig,
agentWorkflowBrandModelConfig: defaultAgentWorkflowBrandModelConfig,
agentWorkflowShowcaseConfig: defaultAgentWorkflowShowcaseConfig,
agentPsdTextColorConfig: defaultAgentPsdTextColorConfig,
agentPsdTemplateSecondaryCategoryConfig:
defaultAgentPsdTemplateSecondaryCategoryConfig,
agentPsdTemplateCategoryTagConfig:
defaultAgentPsdTemplateCategoryTagConfig,
agentPsdTemplateCategoryTagIndex:
defaultAgentPsdTemplateCategoryTagIndex,
realtimeCanvasEnabled: true,
realtimeCanvasServiceEnabled: true,
layerSplitEnabled,
storageFailoverConfig,
ossImageMigrationConfig,
canvasDefaultModelId: null,
canvasAutoModeDefaultModelId: null,
canvasDetailDefaultModelId: null,
canvasDetailAgentModelId: null,
lovartPromoText: "现在升级,立享 Kling 3.0 与 Nano Banana Pro,最高 5 折优惠",
lovartPromoActionText: "立即升级",
lovartHeroTitle: "由壹点AI 让设计更简单",
lovartHeroSubtitle: "懂你的设计代理,帮你搞定一切",
homeVariant,
surpriseCategories,
aiDetailGenerationEnabled,
lovartComposerPrefix,
lovartComposerPreviewTexts,
lovartPromptTagVisibility,
contactConfig,
membershipConfig,
membershipUserOverrides,
pointsSystemConfig,
pointsPackages,
dulupayConfig,
};
const response = NextResponse.json({
...baseSettings,
lovartPromoText:
baseSettings.lovartPromoText ||
"现在升级,立享 Kling 3.0 与 Nano Banana Pro,最高 5 折优惠",
lovartPromoActionText: baseSettings.lovartPromoActionText || "立即升级",
lovartHeroTitle: baseSettings.lovartHeroTitle || "由壹点AI 让设计更简单",
lovartHeroSubtitle: baseSettings.lovartHeroSubtitle || "懂你的设计代理,帮你搞定一切",
notification,
homeVariant,
surpriseCategories,
aiDetailGenerationEnabled,
lovartComposerPrefix,
lovartComposerPreviewTexts,
lovartPromptTagVisibility,
contactConfig,
agentPresetLibraryConfig,
agentCategoryTreeConfig,
agentSecondaryTypeConfig,
agentWorkflowUiConfig,
agentWorkflowMaterialApiConfig,
agentWorkflowGoodsInfoApiConfig,
agentWorkflowBrandModelConfig,
agentWorkflowShowcaseConfig,
agentPsdTextColorConfig,
agentPsdTemplateSecondaryCategoryConfig,
agentPsdTemplateCategoryTagConfig,
agentPsdTemplateCategoryTagIndex,
membershipConfig,
membershipUserOverrides,
pointsSystemConfig,
pointsPackages,
dulupayConfig,
realtimeCanvasServiceEnabled,
layerSplitEnabled,
canvasAgentModeEnabled,
videoCanvasSidebarEnabled,
storageFailoverConfig,
ossImageMigrationConfig,
});
// 禁用缓存,确保总是获取最新设置
response.headers.set("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate");
response.headers.set("Pragma", "no-cache");
response.headers.set("Expires", "0");
return response;
} catch (error) {
console.error("[Site Settings API] Get error:", error);
return NextResponse.json(
{ error: "Failed to fetch site settings" },
{ status: 500 }
);
}
}
const AGENT_WORKFLOW_INPUT_OPTIONS_MAX_ITEMS = 5000;
const updateSchema = z.object({
siteName: z.string().min(1).max(128).optional(),
siteLogo: z.string().nullable().optional(),
siteLogoDark: z.string().nullable().optional(),
favicon: z.string().nullable().optional(),
showAutoModel: z.boolean().optional(),
defaultTheme: z.enum(["system", "light", "dark"]).optional(),
usageTimeEnabled: z.boolean().optional(),
usageTimeStart: z.string().length(5).optional(),
usageTimeEnd: z.string().length(5).optional(),
usageTimeMessage: z.string().optional(),
bannerEnabled: z.boolean().optional(),
bannerText: z.string().optional(),
bannerLink: z.string().nullable().optional(),
toolbox1Name: z.string().max(64).optional(),
toolbox1Enabled: z.boolean().optional(),
toolbox2Name: z.string().max(64).optional(),
toolbox2Enabled: z.boolean().optional(),
tutorialVideoUrl: z.string().nullable().optional(),
tutorialEnabled: z.boolean().optional(),
rankingEnabled: z.boolean().optional(),
productPlanningEnabled: z.boolean().optional(),
canvasEnabled: z.boolean().optional(),
agentEnabled: z.boolean().optional(),
canvasAgentModeEnabled: z.boolean().optional(),
videoCanvasSidebarEnabled: z.boolean().optional(),
agentPresetLibraryConfig: z
.object({
sections: z
.array(
z.object({
id: z.string().trim().min(1).max(64).optional(),
label: z.string().trim().min(1).max(64),
description: z.string().trim().max(200).nullable().optional(),
enabled: z.boolean().optional(),
sortOrder: z.number().min(0).max(999).optional(),
categories: z
.array(
z.lazy(() =>
z.object({
id: z.string().trim().min(1).max(64).optional(),
name: z.string().trim().min(1).max(64),
enabled: z.boolean().optional(),
sortOrder: z.number().min(0).max(999).optional(),
children: z
.array(
z.lazy(() =>
z.object({
id: z.string().trim().min(1).max(64).optional(),
name: z.string().trim().min(1).max(64),
enabled: z.boolean().optional(),
sortOrder: z.number().min(0).max(999).optional(),
children: z
.array(
z.object({
id: z.string().trim().min(1).max(64).optional(),
name: z.string().trim().min(1).max(64),
enabled: z.boolean().optional(),
sortOrder: z.number().min(0).max(999).optional(),
children: z.array(z.any()).optional(),
})
)
.max(100)
.optional(),
})
)
)
.max(100)
.optional(),
})
)
)
.max(100)
.optional(),
})
)
.max(30),
})
.optional(),
agentCategoryTreeConfig: z
.object({
productCategories: z.array(z.string().trim().min(1).max(64)).max(200).optional(),
audienceTags: z.array(z.string().trim().min(1).max(64)).max(200).optional(),
usageScenarios: z.array(z.string().trim().min(1).max(64)).max(200).optional(),
brands: z.array(z.string().trim().min(1).max(64)).max(200).optional(),
})
.optional(),
agentSecondaryTypeConfig: z
.object({
image: z.array(z.string().trim().min(1).max(64)).max(200).optional(),
video: z.array(z.string().trim().min(1).max(64)).max(200).optional(),
text: z.array(z.string().trim().min(1).max(64)).max(200).optional(),
})
.optional(),
agentWorkflowUiConfig: z
.object({
inputOptions: z
.object({
brands: z
.array(z.string().trim().min(1).max(64))
.max(AGENT_WORKFLOW_INPUT_OPTIONS_MAX_ITEMS)
.optional(),
stores: z
.array(z.string().trim().min(1).max(64))
.max(AGENT_WORKFLOW_INPUT_OPTIONS_MAX_ITEMS)
.optional(),
categoryLabels: z
.object({
firstCategory: z.string().trim().min(1).max(24).optional(),
secondCategory: z.string().trim().min(1).max(24).optional(),
thirdCategory: z.string().trim().min(1).max(24).optional(),
fourthCategory: z.string().trim().min(1).max(24).optional(),
fifthCategory: z.string().trim().min(1).max(24).optional(),
})
.optional(),
thirdCategories: z
.array(z.string().trim().min(1).max(64))
.max(AGENT_WORKFLOW_INPUT_OPTIONS_MAX_ITEMS)
.optional(),
fourthCategories: z
.array(z.string().trim().min(1).max(64))
.max(AGENT_WORKFLOW_INPUT_OPTIONS_MAX_ITEMS)
.optional(),
fifthCategories: z
.array(z.string().trim().min(1).max(64))
.max(AGENT_WORKFLOW_INPUT_OPTIONS_MAX_ITEMS)
.optional(),
priceBands: z
.array(z.string().trim().min(1).max(64))
.max(AGENT_WORKFLOW_INPUT_OPTIONS_MAX_ITEMS)
.optional(),
brandStoreEntries: z
.array(
z.object({
brandName: z.string().trim().min(1).max(64),
stores: z
.array(z.string().trim().min(1).max(64))
.max(AGENT_WORKFLOW_INPUT_OPTIONS_MAX_ITEMS)
.optional(),
storeEntries: z
.array(
z.object({
storeName: z.string().trim().min(1).max(64),
thirdCategories: z
.array(z.string().trim().min(1).max(64))
.max(AGENT_WORKFLOW_INPUT_OPTIONS_MAX_ITEMS)
.optional(),
thirdCategoryEntries: z
.array(
z.object({
categoryName: z.string().trim().min(1).max(64),
fourthCategories: z
.array(z.string().trim().min(1).max(64))
.max(AGENT_WORKFLOW_INPUT_OPTIONS_MAX_ITEMS)
.optional(),
fourthCategoryEntries: z
.array(
z.object({
categoryName: z.string().trim().min(1).max(64),
fifthCategories: z
.array(z.string().trim().min(1).max(64))
.max(AGENT_WORKFLOW_INPUT_OPTIONS_MAX_ITEMS)
.optional(),
sortOrder: z.number().min(0).max(999).optional(),
})
)
.max(AGENT_WORKFLOW_INPUT_OPTIONS_MAX_ITEMS)
.optional(),
sortOrder: z.number().min(0).max(999).optional(),
})
)
.max(AGENT_WORKFLOW_INPUT_OPTIONS_MAX_ITEMS)
.optional(),
sortOrder: z.number().min(0).max(999).optional(),
})
)
.max(AGENT_WORKFLOW_INPUT_OPTIONS_MAX_ITEMS)
.optional(),
sortOrder: z.number().min(0).max(999).optional(),
})
)
.max(AGENT_WORKFLOW_INPUT_OPTIONS_MAX_ITEMS)
.optional(),
})
.optional(),
constraintSettings: z
.object({
crossLevelMutualExclusionEnabled: z.boolean().optional(),
})
.optional(),
steps: z
.array(
z.object({
key: z.string().trim().min(1).max(64),
title: z.string().trim().min(1).max(64),
description: z.string().trim().max(300).nullable().optional(),
enabled: z.boolean().optional(),
sortOrder: z.number().min(0).max(999).optional(),
options: z
.array(
z.lazy(() =>
z.object({
key: z.string().trim().min(1).max(64),
buttonName: z.string().trim().min(1).max(64),
description: z.string().trim().max(300).nullable().optional(),
previewImageUrl: z.string().trim().max(1000).nullable().optional(),
enabled: z.boolean().optional(),
sortOrder: z.number().min(0).max(999).optional(),
promptFragment: z.string().trim().max(1000).nullable().optional(),
blockedOptionKeys: z
.array(z.string().trim().min(1).max(64))
.max(100)
.optional(),
children: z.array(z.any()).max(100).optional(),
})
)
)
.max(100),
})
)
.max(20),
})
.optional(),
agentWorkflowMaterialApiConfig: z
.object({
enabled: z.boolean().optional(),
baseUrl: z.string().trim().max(255).optional(),
apiKey: z.string().trim().max(500).optional(),
})
.optional(),
agentWorkflowGoodsInfoApiConfig: z
.object({
enabled: z.boolean().optional(),
baseUrl: z.string().trim().max(255).optional(),
clientKey: z.string().trim().max(255).optional(),
secret: z.string().trim().max(255).optional(),
})
.optional(),
agentWorkflowBrandModelConfig: z
.object({
entries: z
.array(
z.object({
brandName: z.string().trim().min(1).max(64),
images: z
.array(
z.object({
id: z.string().trim().min(1).max(128).optional(),
assetId: z.string().trim().max(128).nullable().optional(),
imageUrl: z.string().trim().min(1).max(2000),
displayName: z.string().trim().max(255).nullable().optional(),
mimeType: z.string().trim().max(128).nullable().optional(),
sortOrder: z.number().min(0).max(999).optional(),
})
)
.max(100),
})
)
.max(300),
})
.optional(),
agentWorkflowShowcaseConfig: z
.object({
enabled: z.boolean().optional(),
title: z.string().max(200).optional(),
subtitle: z.string().max(300).optional(),
actionText: z.string().max(48).optional(),
videoUrl: z.string().max(2000).optional(),
posterUrl: z.string().max(2000).nullable().optional(),
overlayText: z.string().max(200).optional(),
footerText: z.string().max(64).optional(),
})
.optional(),
agentPsdTextColorConfig: z
.object({
enabled: z.boolean().optional(),
colors: z.array(z.string().trim().max(32)).length(2).optional(),
brandConfigs: z
.array(
z.object({
brandName: z.string().trim().min(1).max(64),
enabled: z.boolean().optional(),
colors: z.array(z.string().trim().max(32)).length(2).optional(),
})
)
.max(300)
.optional(),
})
.optional(),
agentPsdTemplateSecondaryCategoryConfig: z
.object({
enabled: z.boolean().optional(),
})
.optional(),
agentPsdTemplateCategoryTagConfig: z
.object({
tags: z.array(z.string().trim().min(1).max(64)).max(200).optional(),
})
.optional(),
realtimeCanvasEnabled: z.boolean().optional(),
aiDetailGenerationEnabled: z.boolean().optional(),
canvasDefaultModelId: z.string().nullable().optional(),
canvasAutoModeDefaultModelId: z.string().nullable().optional(),
canvasDetailDefaultModelId: z.string().nullable().optional(),
canvasDetailAgentModelId: z.string().nullable().optional(),
lovartPromoText: z.string().max(300).optional(),
lovartPromoActionText: z.string().max(32).optional(),
lovartHeroTitle: z.string().max(300).optional(),
lovartHeroSubtitle: z.string().max(300).optional(),
homeVariant: z.enum(["classic", "lovart"]).optional(),
surpriseCategories: z.array(z.string().trim().min(1).max(20)).max(12).optional(),
lovartComposerPrefix: z.string().trim().min(1).max(40).optional(),
lovartComposerPreviewTexts: z.array(z.string().trim().min(1).max(120)).max(20).optional(),
lovartPromptTagVisibility: z
.object({
nanoBananaPro: z.boolean().optional(),
design: z.boolean().optional(),
branding: z.boolean().optional(),
illustration: z.boolean().optional(),
ecommerce: z.boolean().optional(),
video: z.boolean().optional(),
})
.optional(),
contactConfig: z
.object({
phone: z.string().max(64).optional(),
wechatQrUrl: z.string().max(1000).optional(),
})
.optional(),
membershipConfig: z.unknown().optional(),
membershipUserOverrides: z.unknown().optional(),
pointsSystemConfig: z.unknown().optional(),
pointsPackages: z.unknown().optional(),
dulupayConfig: z.unknown().optional(),
storageFailoverConfig: z
.object({
enabled: z.boolean().optional(),
backupStorageConfigId: z.string().max(128).optional(),
})
.optional(),
ossImageMigrationConfig: z
.object({
enabled: z.boolean().optional(),
preferAliyunForUploads: z.boolean().optional(),
sourceStorageConfigId: z.string().max(128).optional(),
targetStorageConfigId: z.string().max(128).optional(),
migrateAfterHours: z.number().min(1).max(720).optional(),
cleanupAfterHours: z.number().min(1).max(1440).optional(),
batchSize: z.number().min(1).max(100).optional(),
})
.optional(),
homeAnimationConfig: z
.object({
enabled: z.boolean().optional(),
fileName: z.string().trim().max(255).optional(),
htmlContent: z.string().max(2_000_000).optional(),
updatedAt: z.string().nullable().optional(),
})
.optional(),
});
// PUT /api/site-settings - 更新网站设置(管理员 / 风格化管理员)
export async function PUT(request: NextRequest) {
try {
const session = await auth();
if (!session?.user) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const isAdmin = isSiteAdminType(session.user.type);
const canManageAgentWorkflow = isAgentWorkflowAdminType(session.user.type);
if (!canManageAgentWorkflow) {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}
const body = await request.json();
if (!isAdmin) {
const allowedKeys = new Set([
"agentPresetLibraryConfig",
"agentWorkflowUiConfig",
"agentWorkflowMaterialApiConfig",
"agentWorkflowGoodsInfoApiConfig",
"agentWorkflowBrandModelConfig",
"agentWorkflowShowcaseConfig",
"agentPsdTextColorConfig",
"agentPsdTemplateSecondaryCategoryConfig",
"agentPsdTemplateCategoryTagConfig",
]);
const hasRestrictedKeys = Object.keys(body || {}).some((key) => !allowedKeys.has(key));
if (hasRestrictedKeys) {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}
}
const data = updateSchema.parse(body);
const {
homeVariant,
surpriseCategories,
aiDetailGenerationEnabled,
lovartComposerPrefix,
lovartComposerPreviewTexts,
lovartPromptTagVisibility,
contactConfig,
agentPresetLibraryConfig,
agentCategoryTreeConfig,
agentSecondaryTypeConfig,
agentWorkflowUiConfig,
agentWorkflowMaterialApiConfig,
agentWorkflowGoodsInfoApiConfig,
agentWorkflowBrandModelConfig,
agentWorkflowShowcaseConfig,
agentPsdTextColorConfig,
agentPsdTemplateSecondaryCategoryConfig,
agentPsdTemplateCategoryTagConfig,
membershipConfig,
membershipUserOverrides,
pointsSystemConfig,
pointsPackages,
dulupayConfig,
storageFailoverConfig,
ossImageMigrationConfig,
canvasAgentModeEnabled,
videoCanvasSidebarEnabled,
homeAnimationConfig,
...siteSettingsPayload
} = data;
const persistHomeAnimationConfig = async () => {
if (homeAnimationConfig === undefined) {
return;
}
const normalized = normalizeHomeChatAnimationConfig(homeAnimationConfig);
const htmlBytes = getHomeChatAnimationHtmlBytes(normalized.htmlContent);
if (htmlBytes > HOME_CHAT_ANIMATION_MAX_BYTES) {
throw new Error(
`首页动画 HTML 超过限制,当前 ${(htmlBytes / 1024).toFixed(1)}KB,最大 ${(
HOME_CHAT_ANIMATION_MAX_BYTES / 1024
).toFixed(0)}KB`,
);
}
await db
.insert(systemSettings)
.values({
key: HOME_CHAT_ANIMATION_CONFIG_KEY,
value: {
...normalized,
updatedAt: new Date().toISOString(),
},
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: {
...normalized,
updatedAt: new Date().toISOString(),
},
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
};
// 查找现有设置
const [existing] = await db.select().from(siteSettings).limit(1);
if (existing) {
// 更新现有设置
const [updated] = await db
.update(siteSettings)
.set({
...siteSettingsPayload,
agentEnabled: siteSettingsPayload.agentEnabled ?? existing.agentEnabled ?? true,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.where(eq(siteSettings.id, existing.id))
.returning();
if (homeVariant !== undefined) {
await db
.insert(systemSettings)
.values({
key: HOME_VARIANT_KEY,
value: homeVariant,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: homeVariant,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (surpriseCategories !== undefined) {
const normalized = normalizeSurpriseCategories(surpriseCategories);
await db
.insert(systemSettings)
.values({
key: HOME_SURPRISE_CATEGORIES_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (aiDetailGenerationEnabled !== undefined) {
await db
.insert(systemSettings)
.values({
key: AI_DETAIL_GENERATOR_ENABLED_KEY,
value: Boolean(aiDetailGenerationEnabled),
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: Boolean(aiDetailGenerationEnabled),
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (lovartComposerPreviewTexts !== undefined) {
const normalized = normalizeLovartComposerPreviewTexts(lovartComposerPreviewTexts);
await db
.insert(systemSettings)
.values({
key: LOVART_COMPOSER_PREVIEW_TEXTS_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (lovartComposerPrefix !== undefined) {
const normalized = normalizeLovartComposerPrefix(lovartComposerPrefix);
await db
.insert(systemSettings)
.values({
key: LOVART_COMPOSER_PREFIX_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (lovartPromptTagVisibility !== undefined) {
const normalized = normalizeLovartPromptTagVisibility(lovartPromptTagVisibility);
await db
.insert(systemSettings)
.values({
key: LOVART_PROMPT_TAG_VISIBILITY_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (contactConfig !== undefined) {
const normalized = normalizeContactConfig(contactConfig);
await db
.insert(systemSettings)
.values({
key: CONTACT_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (canvasAgentModeEnabled !== undefined) {
const normalized = normalizeCanvasAgentModeEnabled(canvasAgentModeEnabled);
await db
.insert(systemSettings)
.values({
key: CANVAS_AGENT_MODE_ENABLED_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (videoCanvasSidebarEnabled !== undefined) {
const normalized = normalizeVideoCanvasSidebarEnabled(videoCanvasSidebarEnabled);
await db
.insert(systemSettings)
.values({
key: VIDEO_CANVAS_SIDEBAR_ENABLED_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentPresetLibraryConfig !== undefined) {
const normalized = normalizeAgentPresetLibraryConfig(agentPresetLibraryConfig);
await db
.insert(systemSettings)
.values({
key: AGENT_PRESET_LIBRARY_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentCategoryTreeConfig !== undefined) {
const normalized = normalizeAgentCategoryTreeConfig(agentCategoryTreeConfig);
await db
.insert(systemSettings)
.values({
key: AGENT_CATEGORY_TREE_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentSecondaryTypeConfig !== undefined) {
const normalized = normalizeAgentSecondaryTypeConfig(agentSecondaryTypeConfig);
await db
.insert(systemSettings)
.values({
key: AGENT_SECONDARY_TYPE_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentWorkflowUiConfig !== undefined) {
const normalized = normalizeAgentWorkflowUiConfig(agentWorkflowUiConfig);
await db
.insert(systemSettings)
.values({
key: AGENT_WORKFLOW_UI_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentWorkflowMaterialApiConfig !== undefined) {
const normalized = normalizeAgentWorkflowMaterialApiConfig(
agentWorkflowMaterialApiConfig
);
await db
.insert(systemSettings)
.values({
key: AGENT_WORKFLOW_MATERIAL_API_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentWorkflowGoodsInfoApiConfig !== undefined) {
const normalized = normalizeAgentWorkflowGoodsInfoApiConfig(
agentWorkflowGoodsInfoApiConfig
);
await db
.insert(systemSettings)
.values({
key: AGENT_WORKFLOW_GOODS_INFO_API_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentWorkflowBrandModelConfig !== undefined) {
const normalized = normalizeAgentWorkflowBrandModelConfig(
agentWorkflowBrandModelConfig
);
await db
.insert(systemSettings)
.values({
key: AGENT_WORKFLOW_BRAND_MODEL_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentWorkflowShowcaseConfig !== undefined) {
const normalized = normalizeAgentWorkflowShowcaseConfig(agentWorkflowShowcaseConfig);
await db
.insert(systemSettings)
.values({
key: AGENT_WORKFLOW_SHOWCASE_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentPsdTextColorConfig !== undefined) {
const normalized = normalizeAgentPsdTextColorConfig(agentPsdTextColorConfig);
await db
.insert(systemSettings)
.values({
key: AGENT_PSD_TEXT_COLOR_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentPsdTemplateSecondaryCategoryConfig !== undefined) {
const normalized = normalizeAgentPsdTemplateSecondaryCategoryConfig(
agentPsdTemplateSecondaryCategoryConfig
);
await db
.insert(systemSettings)
.values({
key: AGENT_PSD_TEMPLATE_SECONDARY_CATEGORY_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentPsdTemplateSecondaryCategoryConfig !== undefined) {
const normalized = normalizeAgentPsdTemplateSecondaryCategoryConfig(
agentPsdTemplateSecondaryCategoryConfig
);
await db
.insert(systemSettings)
.values({
key: AGENT_PSD_TEMPLATE_SECONDARY_CATEGORY_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentPsdTemplateCategoryTagConfig !== undefined) {
const normalized = normalizeAgentPsdTemplateCategoryTagConfig(
agentPsdTemplateCategoryTagConfig
);
await db
.insert(systemSettings)
.values({
key: AGENT_PSD_TEMPLATE_CATEGORY_TAG_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (membershipConfig !== undefined) {
const normalized = normalizeMembershipConfig(membershipConfig);
await db
.insert(systemSettings)
.values({
key: MEMBERSHIP_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (membershipUserOverrides !== undefined) {
const normalized = normalizeMembershipUserOverrides(membershipUserOverrides);
await db
.insert(systemSettings)
.values({
key: MEMBERSHIP_USER_OVERRIDES_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (pointsSystemConfig !== undefined) {
const normalized = normalizePointsSystemConfig(pointsSystemConfig);
await db
.insert(systemSettings)
.values({
key: POINTS_SYSTEM_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (pointsPackages !== undefined) {
const normalized = normalizePointsPackages(pointsPackages);
await db
.insert(systemSettings)
.values({
key: POINTS_PACKAGES_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (dulupayConfig !== undefined) {
const normalized = normalizeDulupayConfig(dulupayConfig);
await db
.insert(systemSettings)
.values({
key: DULUPAY_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (storageFailoverConfig !== undefined) {
const normalized = normalizeStorageFailoverConfig(storageFailoverConfig);
await db
.insert(systemSettings)
.values({
key: STORAGE_FAILOVER_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (ossImageMigrationConfig !== undefined) {
const normalized = normalizeOssImageMigrationConfig(ossImageMigrationConfig);
await db
.insert(systemSettings)
.values({
key: OSS_MIGRATION_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
await persistHomeAnimationConfig();
return NextResponse.json({
...updated,
homeVariant: homeVariant ?? normalizeHomeVariant(undefined),
surpriseCategories:
surpriseCategories !== undefined
? normalizeSurpriseCategories(surpriseCategories)
: normalizeSurpriseCategories(undefined),
aiDetailGenerationEnabled: aiDetailGenerationEnabled ?? false,
lovartComposerPrefix:
lovartComposerPrefix !== undefined
? normalizeLovartComposerPrefix(lovartComposerPrefix)
: normalizeLovartComposerPrefix(undefined),
lovartComposerPreviewTexts:
lovartComposerPreviewTexts !== undefined
? normalizeLovartComposerPreviewTexts(lovartComposerPreviewTexts)
: normalizeLovartComposerPreviewTexts(undefined),
lovartPromptTagVisibility:
lovartPromptTagVisibility !== undefined
? normalizeLovartPromptTagVisibility(lovartPromptTagVisibility)
: normalizeLovartPromptTagVisibility(undefined),
contactConfig:
contactConfig !== undefined
? normalizeContactConfig(contactConfig)
: normalizeContactConfig(undefined),
agentPresetLibraryConfig:
agentPresetLibraryConfig !== undefined
? normalizeAgentPresetLibraryConfig(agentPresetLibraryConfig)
: defaultAgentPresetLibraryConfig,
agentCategoryTreeConfig:
agentCategoryTreeConfig !== undefined
? normalizeAgentCategoryTreeConfig(agentCategoryTreeConfig)
: normalizeAgentCategoryTreeConfig(undefined),
agentSecondaryTypeConfig:
agentSecondaryTypeConfig !== undefined
? normalizeAgentSecondaryTypeConfig(agentSecondaryTypeConfig)
: defaultAgentSecondaryTypeConfig,
agentWorkflowUiConfig:
agentWorkflowUiConfig !== undefined
? normalizeAgentWorkflowUiConfig(agentWorkflowUiConfig)
: defaultAgentWorkflowUiConfig,
agentWorkflowMaterialApiConfig:
agentWorkflowMaterialApiConfig !== undefined
? normalizeAgentWorkflowMaterialApiConfig(agentWorkflowMaterialApiConfig)
: defaultAgentWorkflowMaterialApiConfig,
agentWorkflowGoodsInfoApiConfig:
agentWorkflowGoodsInfoApiConfig !== undefined
? normalizeAgentWorkflowGoodsInfoApiConfig(agentWorkflowGoodsInfoApiConfig)
: defaultAgentWorkflowGoodsInfoApiConfig,
agentWorkflowBrandModelConfig:
agentWorkflowBrandModelConfig !== undefined
? normalizeAgentWorkflowBrandModelConfig(agentWorkflowBrandModelConfig)
: defaultAgentWorkflowBrandModelConfig,
agentWorkflowShowcaseConfig:
agentWorkflowShowcaseConfig !== undefined
? normalizeAgentWorkflowShowcaseConfig(agentWorkflowShowcaseConfig)
: defaultAgentWorkflowShowcaseConfig,
agentPsdTextColorConfig:
agentPsdTextColorConfig !== undefined
? normalizeAgentPsdTextColorConfig(agentPsdTextColorConfig)
: defaultAgentPsdTextColorConfig,
agentPsdTemplateSecondaryCategoryConfig:
agentPsdTemplateSecondaryCategoryConfig !== undefined
? normalizeAgentPsdTemplateSecondaryCategoryConfig(
agentPsdTemplateSecondaryCategoryConfig
)
: defaultAgentPsdTemplateSecondaryCategoryConfig,
agentPsdTemplateCategoryTagConfig:
agentPsdTemplateCategoryTagConfig !== undefined
? normalizeAgentPsdTemplateCategoryTagConfig(agentPsdTemplateCategoryTagConfig)
: defaultAgentPsdTemplateCategoryTagConfig,
membershipConfig:
membershipConfig !== undefined
? normalizeMembershipConfig(membershipConfig)
: defaultMembershipConfig,
membershipUserOverrides:
membershipUserOverrides !== undefined
? normalizeMembershipUserOverrides(membershipUserOverrides)
: defaultMembershipUserOverrides,
pointsSystemConfig:
pointsSystemConfig !== undefined
? normalizePointsSystemConfig(pointsSystemConfig)
: defaultPointsSystemConfig,
pointsPackages:
pointsPackages !== undefined
? normalizePointsPackages(pointsPackages)
: defaultPointsPackages,
dulupayConfig:
dulupayConfig !== undefined
? normalizeDulupayConfig(dulupayConfig)
: defaultDulupayConfig,
storageFailoverConfig:
storageFailoverConfig !== undefined
? normalizeStorageFailoverConfig(storageFailoverConfig)
: normalizeStorageFailoverConfig(undefined),
ossImageMigrationConfig:
ossImageMigrationConfig !== undefined
? normalizeOssImageMigrationConfig(ossImageMigrationConfig)
: defaultOssImageMigrationConfig,
canvasAgentModeEnabled:
canvasAgentModeEnabled !== undefined
? normalizeCanvasAgentModeEnabled(canvasAgentModeEnabled)
: normalizeCanvasAgentModeEnabled(undefined),
videoCanvasSidebarEnabled:
videoCanvasSidebarEnabled !== undefined
? normalizeVideoCanvasSidebarEnabled(videoCanvasSidebarEnabled)
: normalizeVideoCanvasSidebarEnabled(undefined),
});
} else {
// 创建新设置
const [created] = await db
.insert(siteSettings)
.values({
siteName: siteSettingsPayload.siteName || "AI Chatbot",
siteLogo: siteSettingsPayload.siteLogo,
siteLogoDark: siteSettingsPayload.siteLogoDark,
favicon: siteSettingsPayload.favicon,
showAutoModel: siteSettingsPayload.showAutoModel ?? true,
defaultTheme: siteSettingsPayload.defaultTheme ?? "system",
usageTimeEnabled: siteSettingsPayload.usageTimeEnabled ?? false,
usageTimeStart: siteSettingsPayload.usageTimeStart ?? "08:00",
usageTimeEnd: siteSettingsPayload.usageTimeEnd ?? "20:00",
usageTimeMessage: siteSettingsPayload.usageTimeMessage ?? "由壹点累了也是需要休息的",
bannerEnabled: siteSettingsPayload.bannerEnabled ?? true,
bannerText: siteSettingsPayload.bannerText ?? "升级会员, Nano Banana Pro 免费365天!",
bannerLink: siteSettingsPayload.bannerLink,
toolbox1Name: siteSettingsPayload.toolbox1Name ?? "工具箱",
toolbox1Enabled: siteSettingsPayload.toolbox1Enabled ?? true,
toolbox2Name: siteSettingsPayload.toolbox2Name ?? "工具箱2",
toolbox2Enabled: siteSettingsPayload.toolbox2Enabled ?? false,
tutorialVideoUrl: siteSettingsPayload.tutorialVideoUrl,
tutorialEnabled: siteSettingsPayload.tutorialEnabled ?? false,
rankingEnabled: siteSettingsPayload.rankingEnabled ?? true,
productPlanningEnabled: siteSettingsPayload.productPlanningEnabled ?? true,
canvasEnabled: siteSettingsPayload.canvasEnabled ?? true,
agentEnabled: siteSettingsPayload.agentEnabled ?? true,
realtimeCanvasEnabled: siteSettingsPayload.realtimeCanvasEnabled ?? true,
canvasDefaultModelId: siteSettingsPayload.canvasDefaultModelId,
canvasAutoModeDefaultModelId: siteSettingsPayload.canvasAutoModeDefaultModelId,
canvasDetailDefaultModelId: siteSettingsPayload.canvasDetailDefaultModelId,
canvasDetailAgentModelId: siteSettingsPayload.canvasDetailAgentModelId,
lovartPromoText:
siteSettingsPayload.lovartPromoText ??
"现在升级,立享 Kling 3.0 与 Nano Banana Pro,最高 5 折优惠",
lovartPromoActionText: siteSettingsPayload.lovartPromoActionText ?? "立即升级",
lovartHeroTitle: siteSettingsPayload.lovartHeroTitle ?? "由壹点AI 让设计更简单",
lovartHeroSubtitle: siteSettingsPayload.lovartHeroSubtitle ?? "懂你的设计代理,帮你搞定一切",
updatedBy: session.user.id,
})
.returning();
if (homeVariant !== undefined) {
await db
.insert(systemSettings)
.values({
key: HOME_VARIANT_KEY,
value: homeVariant,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: homeVariant,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (surpriseCategories !== undefined) {
const normalized = normalizeSurpriseCategories(surpriseCategories);
await db
.insert(systemSettings)
.values({
key: HOME_SURPRISE_CATEGORIES_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
await persistHomeAnimationConfig();
if (aiDetailGenerationEnabled !== undefined) {
await db
.insert(systemSettings)
.values({
key: AI_DETAIL_GENERATOR_ENABLED_KEY,
value: Boolean(aiDetailGenerationEnabled),
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: Boolean(aiDetailGenerationEnabled),
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (lovartComposerPreviewTexts !== undefined) {
const normalized = normalizeLovartComposerPreviewTexts(lovartComposerPreviewTexts);
await db
.insert(systemSettings)
.values({
key: LOVART_COMPOSER_PREVIEW_TEXTS_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (lovartComposerPrefix !== undefined) {
const normalized = normalizeLovartComposerPrefix(lovartComposerPrefix);
await db
.insert(systemSettings)
.values({
key: LOVART_COMPOSER_PREFIX_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (lovartPromptTagVisibility !== undefined) {
const normalized = normalizeLovartPromptTagVisibility(lovartPromptTagVisibility);
await db
.insert(systemSettings)
.values({
key: LOVART_PROMPT_TAG_VISIBILITY_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (contactConfig !== undefined) {
const normalized = normalizeContactConfig(contactConfig);
await db
.insert(systemSettings)
.values({
key: CONTACT_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (canvasAgentModeEnabled !== undefined) {
const normalized = normalizeCanvasAgentModeEnabled(canvasAgentModeEnabled);
await db
.insert(systemSettings)
.values({
key: CANVAS_AGENT_MODE_ENABLED_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (videoCanvasSidebarEnabled !== undefined) {
const normalized = normalizeVideoCanvasSidebarEnabled(videoCanvasSidebarEnabled);
await db
.insert(systemSettings)
.values({
key: VIDEO_CANVAS_SIDEBAR_ENABLED_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentPresetLibraryConfig !== undefined) {
const normalized = normalizeAgentPresetLibraryConfig(agentPresetLibraryConfig);
await db
.insert(systemSettings)
.values({
key: AGENT_PRESET_LIBRARY_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentCategoryTreeConfig !== undefined) {
const normalized = normalizeAgentCategoryTreeConfig(agentCategoryTreeConfig);
await db
.insert(systemSettings)
.values({
key: AGENT_CATEGORY_TREE_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentSecondaryTypeConfig !== undefined) {
const normalized = normalizeAgentSecondaryTypeConfig(agentSecondaryTypeConfig);
await db
.insert(systemSettings)
.values({
key: AGENT_SECONDARY_TYPE_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentWorkflowUiConfig !== undefined) {
const normalized = normalizeAgentWorkflowUiConfig(agentWorkflowUiConfig);
await db
.insert(systemSettings)
.values({
key: AGENT_WORKFLOW_UI_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentWorkflowMaterialApiConfig !== undefined) {
const normalized = normalizeAgentWorkflowMaterialApiConfig(
agentWorkflowMaterialApiConfig
);
await db
.insert(systemSettings)
.values({
key: AGENT_WORKFLOW_MATERIAL_API_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentWorkflowBrandModelConfig !== undefined) {
const normalized = normalizeAgentWorkflowBrandModelConfig(
agentWorkflowBrandModelConfig
);
await db
.insert(systemSettings)
.values({
key: AGENT_WORKFLOW_BRAND_MODEL_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentWorkflowShowcaseConfig !== undefined) {
const normalized = normalizeAgentWorkflowShowcaseConfig(agentWorkflowShowcaseConfig);
await db
.insert(systemSettings)
.values({
key: AGENT_WORKFLOW_SHOWCASE_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentPsdTextColorConfig !== undefined) {
const normalized = normalizeAgentPsdTextColorConfig(agentPsdTextColorConfig);
await db
.insert(systemSettings)
.values({
key: AGENT_PSD_TEXT_COLOR_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentPsdTemplateCategoryTagConfig !== undefined) {
const normalized = normalizeAgentPsdTemplateCategoryTagConfig(
agentPsdTemplateCategoryTagConfig
);
await db
.insert(systemSettings)
.values({
key: AGENT_PSD_TEMPLATE_CATEGORY_TAG_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (membershipConfig !== undefined) {
const normalized = normalizeMembershipConfig(membershipConfig);
await db
.insert(systemSettings)
.values({
key: MEMBERSHIP_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (membershipUserOverrides !== undefined) {
const normalized = normalizeMembershipUserOverrides(membershipUserOverrides);
await db
.insert(systemSettings)
.values({
key: MEMBERSHIP_USER_OVERRIDES_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (pointsSystemConfig !== undefined) {
const normalized = normalizePointsSystemConfig(pointsSystemConfig);
await db
.insert(systemSettings)
.values({
key: POINTS_SYSTEM_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (pointsPackages !== undefined) {
const normalized = normalizePointsPackages(pointsPackages);
await db
.insert(systemSettings)
.values({
key: POINTS_PACKAGES_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (dulupayConfig !== undefined) {
const normalized = normalizeDulupayConfig(dulupayConfig);
await db
.insert(systemSettings)
.values({
key: DULUPAY_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (storageFailoverConfig !== undefined) {
const normalized = normalizeStorageFailoverConfig(storageFailoverConfig);
await db
.insert(systemSettings)
.values({
key: STORAGE_FAILOVER_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (ossImageMigrationConfig !== undefined) {
const normalized = normalizeOssImageMigrationConfig(ossImageMigrationConfig);
await db
.insert(systemSettings)
.values({
key: OSS_MIGRATION_CONFIG_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
return NextResponse.json({
...created,
homeVariant: homeVariant ?? normalizeHomeVariant(undefined),
surpriseCategories:
surpriseCategories !== undefined
? normalizeSurpriseCategories(surpriseCategories)
: normalizeSurpriseCategories(undefined),
aiDetailGenerationEnabled: aiDetailGenerationEnabled ?? false,
lovartComposerPrefix:
lovartComposerPrefix !== undefined
? normalizeLovartComposerPrefix(lovartComposerPrefix)
: normalizeLovartComposerPrefix(undefined),
lovartComposerPreviewTexts:
lovartComposerPreviewTexts !== undefined
? normalizeLovartComposerPreviewTexts(lovartComposerPreviewTexts)
: normalizeLovartComposerPreviewTexts(undefined),
lovartPromptTagVisibility:
lovartPromptTagVisibility !== undefined
? normalizeLovartPromptTagVisibility(lovartPromptTagVisibility)
: normalizeLovartPromptTagVisibility(undefined),
contactConfig:
contactConfig !== undefined
? normalizeContactConfig(contactConfig)
: normalizeContactConfig(undefined),
agentPresetLibraryConfig:
agentPresetLibraryConfig !== undefined
? normalizeAgentPresetLibraryConfig(agentPresetLibraryConfig)
: defaultAgentPresetLibraryConfig,
agentCategoryTreeConfig:
agentCategoryTreeConfig !== undefined
? normalizeAgentCategoryTreeConfig(agentCategoryTreeConfig)
: normalizeAgentCategoryTreeConfig(undefined),
agentSecondaryTypeConfig:
agentSecondaryTypeConfig !== undefined
? normalizeAgentSecondaryTypeConfig(agentSecondaryTypeConfig)
: defaultAgentSecondaryTypeConfig,
agentWorkflowUiConfig:
agentWorkflowUiConfig !== undefined
? normalizeAgentWorkflowUiConfig(agentWorkflowUiConfig)
: defaultAgentWorkflowUiConfig,
agentWorkflowMaterialApiConfig:
agentWorkflowMaterialApiConfig !== undefined
? normalizeAgentWorkflowMaterialApiConfig(agentWorkflowMaterialApiConfig)
: defaultAgentWorkflowMaterialApiConfig,
agentWorkflowGoodsInfoApiConfig:
agentWorkflowGoodsInfoApiConfig !== undefined
? normalizeAgentWorkflowGoodsInfoApiConfig(agentWorkflowGoodsInfoApiConfig)
: defaultAgentWorkflowGoodsInfoApiConfig,
agentWorkflowBrandModelConfig:
agentWorkflowBrandModelConfig !== undefined
? normalizeAgentWorkflowBrandModelConfig(agentWorkflowBrandModelConfig)
: defaultAgentWorkflowBrandModelConfig,
agentWorkflowShowcaseConfig:
agentWorkflowShowcaseConfig !== undefined
? normalizeAgentWorkflowShowcaseConfig(agentWorkflowShowcaseConfig)
: defaultAgentWorkflowShowcaseConfig,
agentPsdTextColorConfig:
agentPsdTextColorConfig !== undefined
? normalizeAgentPsdTextColorConfig(agentPsdTextColorConfig)
: defaultAgentPsdTextColorConfig,
agentPsdTemplateSecondaryCategoryConfig:
agentPsdTemplateSecondaryCategoryConfig !== undefined
? normalizeAgentPsdTemplateSecondaryCategoryConfig(
agentPsdTemplateSecondaryCategoryConfig
)
: defaultAgentPsdTemplateSecondaryCategoryConfig,
agentPsdTemplateCategoryTagConfig:
agentPsdTemplateCategoryTagConfig !== undefined
? normalizeAgentPsdTemplateCategoryTagConfig(agentPsdTemplateCategoryTagConfig)
: defaultAgentPsdTemplateCategoryTagConfig,
membershipConfig:
membershipConfig !== undefined
? normalizeMembershipConfig(membershipConfig)
: defaultMembershipConfig,
membershipUserOverrides:
membershipUserOverrides !== undefined
? normalizeMembershipUserOverrides(membershipUserOverrides)
: defaultMembershipUserOverrides,
pointsSystemConfig:
pointsSystemConfig !== undefined
? normalizePointsSystemConfig(pointsSystemConfig)
: defaultPointsSystemConfig,
pointsPackages:
pointsPackages !== undefined
? normalizePointsPackages(pointsPackages)
: defaultPointsPackages,
dulupayConfig:
dulupayConfig !== undefined
? normalizeDulupayConfig(dulupayConfig)
: defaultDulupayConfig,
storageFailoverConfig:
storageFailoverConfig !== undefined
? normalizeStorageFailoverConfig(storageFailoverConfig)
: normalizeStorageFailoverConfig(undefined),
ossImageMigrationConfig:
ossImageMigrationConfig !== undefined
? normalizeOssImageMigrationConfig(ossImageMigrationConfig)
: defaultOssImageMigrationConfig,
canvasAgentModeEnabled:
canvasAgentModeEnabled !== undefined
? normalizeCanvasAgentModeEnabled(canvasAgentModeEnabled)
: normalizeCanvasAgentModeEnabled(undefined),
videoCanvasSidebarEnabled:
videoCanvasSidebarEnabled !== undefined
? normalizeVideoCanvasSidebarEnabled(videoCanvasSidebarEnabled)
: normalizeVideoCanvasSidebarEnabled(undefined),
});
}
} catch (error) {
console.error("[Site Settings API] Update error:", error);
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: "Invalid request data", details: error.errors },
{ status: 400 }
);
}
if (error instanceof Error) {
return NextResponse.json(
{ error: error.message || "Failed to update site settings" },
{ status: 500 }
);
}
return NextResponse.json(
{ error: "Failed to update site settings" },
{ status: 500 }
);
}
}