From 24af251fd32721ffdef724c3fd85561345532be6 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 18 Jan 2026 15:21:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=B3=BB=E7=BB=9F=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=BB=98=E8=AE=A4=E4=B8=BB=E9=A2=98=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 管理员可以设置网站默认使用深色/浅色/跟随系统模式 - 新增 defaultTheme 字段到 SiteSettings 表 - 前端 ThemeProvider 从数据库读取默认主题设置 --- .../settings/admin-settings-client.tsx | 22 +++++++++++++++++++ app/api/site-settings/route.ts | 3 +++ app/layout.tsx | 8 +++++-- lib/db/queries.ts | 4 ++-- lib/db/schema.ts | 1 + 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/app/(admin)/settings/admin-settings-client.tsx b/app/(admin)/settings/admin-settings-client.tsx index 4f9a3ac..155c9ec 100644 --- a/app/(admin)/settings/admin-settings-client.tsx +++ b/app/(admin)/settings/admin-settings-client.tsx @@ -151,6 +151,7 @@ type SiteSettings = { usageTimeStart: string; usageTimeEnd: string; usageTimeMessage: string; + defaultTheme: "light" | "dark" | "system"; }; type NavLink = { @@ -340,6 +341,7 @@ export function AdminSettingsClient() { usageTimeStart: "08:00", usageTimeEnd: "20:00", usageTimeMessage: "由壹点累了也是需要休息的", + defaultTheme: "system", }); useEffect(() => { @@ -354,6 +356,7 @@ export function AdminSettingsClient() { usageTimeStart: siteSettingsData.usageTimeStart || "08:00", usageTimeEnd: siteSettingsData.usageTimeEnd || "20:00", usageTimeMessage: siteSettingsData.usageTimeMessage || "由壹点累了也是需要休息的", + defaultTheme: siteSettingsData.defaultTheme || "system", }); } }, [siteSettingsData]); @@ -2281,6 +2284,25 @@ export function AdminSettingsClient() { placeholder="https://example.com/favicon.ico" /> +
+ + +
+ 设置新用户首次访问时的默认主题模式 +
+
diff --git a/app/api/site-settings/route.ts b/app/api/site-settings/route.ts index 5dac60b..646e341 100644 --- a/app/api/site-settings/route.ts +++ b/app/api/site-settings/route.ts @@ -26,6 +26,7 @@ export async function GET() { siteLogoDark: null, favicon: null, showAutoModel: true, + defaultTheme: "system", usageTimeEnabled: false, usageTimeStart: "08:00", usageTimeEnd: "20:00", @@ -58,6 +59,7 @@ const updateSchema = z.object({ 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(), @@ -106,6 +108,7 @@ export async function PUT(request: NextRequest) { siteLogoDark: data.siteLogoDark, favicon: data.favicon, showAutoModel: data.showAutoModel ?? true, + defaultTheme: data.defaultTheme ?? "system", usageTimeEnabled: data.usageTimeEnabled ?? false, usageTimeStart: data.usageTimeStart ?? "08:00", usageTimeEnd: data.usageTimeEnd ?? "20:00", diff --git a/app/layout.tsx b/app/layout.tsx index e6af49c..0d4e294 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -125,11 +125,15 @@ const CHUNK_ERROR_RECOVERY_SCRIPT = `\ }); })();`; -export default function RootLayout({ +export default async function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { + // 获取网站设置中的默认主题 + const settings = await getSiteSettings(); + const defaultTheme = settings.defaultTheme || "system"; + return ( diff --git a/lib/db/queries.ts b/lib/db/queries.ts index ec646b5..5cc0ba2 100644 --- a/lib/db/queries.ts +++ b/lib/db/queries.ts @@ -1510,9 +1510,9 @@ export async function getSubModelsByParentModelId(parentModelId: string) { export async function getSiteSettings() { try { const [settings] = await db.select().from(siteSettings).limit(1); - return settings || { siteName: "AI Chatbot", siteLogo: null, siteLogoDark: null, favicon: null }; + return settings || { siteName: "AI Chatbot", siteLogo: null, siteLogoDark: null, favicon: null, defaultTheme: "system" }; } catch (_error) { - return { siteName: "AI Chatbot", siteLogo: null, siteLogoDark: null, favicon: null }; + return { siteName: "AI Chatbot", siteLogo: null, siteLogoDark: null, favicon: null, defaultTheme: "system" }; } } diff --git a/lib/db/schema.ts b/lib/db/schema.ts index 2b06fb7..7dbbb13 100644 --- a/lib/db/schema.ts +++ b/lib/db/schema.ts @@ -286,6 +286,7 @@ export const siteSettings = pgTable("SiteSettings", { siteLogoDark: text("siteLogoDark"), // 黑夜模式 LOGO favicon: text("favicon"), showAutoModel: boolean("showAutoModel").notNull().default(true), // 是否显示"自动"模型选项 + defaultTheme: varchar("defaultTheme", { length: 16 }).notNull().default("system"), // 默认主题:system | light | dark // 使用时间限制 usageTimeEnabled: boolean("usageTimeEnabled").notNull().default(false), // 是否启用时间限制 usageTimeStart: varchar("usageTimeStart", { length: 5 }).default("08:00"), // 开始时间(HH:mm)