feat: 系统设置增加默认主题模式配置

- 管理员可以设置网站默认使用深色/浅色/跟随系统模式
- 新增 defaultTheme 字段到 SiteSettings 表
- 前端 ThemeProvider 从数据库读取默认主题设置
This commit is contained in:
Your Name 2026-01-18 15:21:17 +08:00
parent aee826c688
commit 24af251fd3
5 changed files with 34 additions and 4 deletions

View File

@ -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"
/>
</div>
<div className="space-y-2">
<Label htmlFor="defaultTheme">默认主题模式</Label>
<Select
value={siteSettings.defaultTheme}
onValueChange={(value: "light" | "dark" | "system") => setSiteSettings({ ...siteSettings, defaultTheme: value })}
>
<SelectTrigger id="defaultTheme">
<SelectValue placeholder="选择默认主题" />
</SelectTrigger>
<SelectContent>
<SelectItem value="system">跟随系统</SelectItem>
<SelectItem value="light">浅色模式</SelectItem>
<SelectItem value="dark">深色模式</SelectItem>
</SelectContent>
</Select>
<div className="text-xs text-muted-foreground">
设置新用户首次访问时的默认主题模式
</div>
</div>
<div className="flex items-center justify-between space-x-2 rounded-lg border p-4">
<div className="space-y-0.5">
<Label htmlFor="showAutoModel">显示"自动"模型选项</Label>

View File

@ -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",

View File

@ -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 (
<html
className={`${geist.variable} ${geistMono.variable}`}
@ -158,7 +162,7 @@ export default function RootLayout({
<FaviconUpdater />
<ThemeProvider
attribute="class"
defaultTheme="dark"
defaultTheme={defaultTheme}
disableTransitionOnChange
enableSystem
>

View File

@ -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" };
}
}

View File

@ -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)