diff --git a/README.md b/README.md index 91388b3..6fee402 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,7 @@ services: restart: on-failure ports: - '3000:3000' + - '3001:3001' environment: - USERNAME=admin - PASSWORD=orange @@ -111,6 +112,7 @@ services: restart: on-failure ports: - '3000:3000' + - '3001:3001' environment: - USERNAME=admin - PASSWORD=orange @@ -147,6 +149,7 @@ services: restart: on-failure ports: - '3000:3000' + - '3001:3001' environment: - USERNAME=admin - PASSWORD=orange diff --git a/src/app/api/admin/config/route.ts b/src/app/api/admin/config/route.ts index 7544700..846bab7 100644 --- a/src/app/api/admin/config/route.ts +++ b/src/app/api/admin/config/route.ts @@ -20,41 +20,74 @@ export async function GET(request: NextRequest) { } const authInfo = getAuthInfoFromCookie(request); - if (!authInfo || !authInfo.username) { - return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); - } - const username = authInfo.username; + const username = authInfo?.username; try { const config = await getConfig(); - const result: AdminConfigResult = { - Role: 'owner', - Config: config, - }; + + // 检查用户权限 + let userRole = 'guest'; // 未登录用户为 guest + let isAdmin = false; + if (username === process.env.USERNAME) { - result.Role = 'owner'; - } else { + userRole = 'owner'; + isAdmin = true; + } else if (username) { const user = config.UserConfig.Users.find((u) => u.username === username); if (user && user.role === 'admin' && !user.banned) { - result.Role = 'admin'; + userRole = 'admin'; + isAdmin = true; + } else if (user && !user.banned) { + userRole = 'user'; + } else if (user && user.banned) { + userRole = 'banned'; } else { - return NextResponse.json( - { error: '你是管理员吗你就访问?' }, - { status: 401 } - ); + // 认证了但用户不存在,可能是数据不同步 + userRole = 'unknown'; } } - return NextResponse.json(result, { - headers: { - 'Cache-Control': 'no-store', // 管理员配置不缓存 - }, - }); + // 根据用户权限返回不同的配置信息 + if (isAdmin) { + // 管理员返回完整配置 + const result: AdminConfigResult = { + Role: userRole as 'admin' | 'owner', + Config: config, + }; + + return NextResponse.json(result, { + headers: { + 'Cache-Control': 'no-store', // 管理员配置不缓存 + }, + }); + } else { + // 普通用户或未登录用户只返回公开配置 + const publicConfig = { + ThemeConfig: config.ThemeConfig, + SiteConfig: { + SiteName: config.SiteConfig.SiteName, + Announcement: config.SiteConfig.Announcement, + // 其他公开的站点配置可以在这里添加 + } + }; + + const result = { + Role: userRole, + Config: publicConfig, + }; + + console.log('返回公开配置给', userRole, ',包含主题配置:', !!publicConfig.ThemeConfig); + return NextResponse.json(result, { + headers: { + 'Cache-Control': 'public, max-age=60', // 公开配置可以缓存1分钟 + }, + }); + } } catch (error) { - console.error('获取管理员配置失败:', error); + console.error('获取配置失败:', error); return NextResponse.json( { - error: '获取管理员配置失败', + error: '获取配置失败', details: (error as Error).message, }, { status: 500 } diff --git a/src/app/api/admin/theme/route.ts b/src/app/api/admin/theme/route.ts index 5130bfa..28b3a6c 100644 --- a/src/app/api/admin/theme/route.ts +++ b/src/app/api/admin/theme/route.ts @@ -3,6 +3,7 @@ import { getAuthInfoFromCookie } from '@/lib/auth'; import { db } from '@/lib/db'; import { AdminConfig } from '@/lib/admin.types'; import { headers, cookies } from 'next/headers'; +import { getConfig, setCachedConfig, clearCachedConfig } from '@/lib/config'; export async function GET() { try { @@ -22,12 +23,8 @@ export async function GET() { return NextResponse.json({ error: '认证信息无效' }, { status: 401 }); } - const config = await db.getAdminConfig(); - const themeConfig = config?.ThemeConfig || { - defaultTheme: 'default' as const, - customCSS: '', - allowUserCustomization: true, - }; + const config = await getConfig(); + const themeConfig = config.ThemeConfig; return NextResponse.json({ success: true, @@ -75,40 +72,7 @@ export async function POST(request: Request) { } // 获取当前配置 - const currentConfig = await db.getAdminConfig(); - - // 如果没有配置,创建一个基础配置 - let baseConfig: AdminConfig; - if (!currentConfig) { - baseConfig = { - ConfigSubscribtion: { - URL: "", - AutoUpdate: false, - LastCheck: "", - }, - ConfigFile: "", - SiteConfig: { - SiteName: "OrangeTV", - Announcement: "", - SearchDownstreamMaxPage: 10, - SiteInterfaceCacheTime: 30, - DoubanProxyType: "direct", - DoubanProxy: "", - DoubanImageProxyType: "direct", - DoubanImageProxy: "", - DisableYellowFilter: false, - FluidSearch: true, - RequireDeviceCode: false, - }, - UserConfig: { - Users: [], - }, - SourceConfig: [], - CustomCategories: [], - }; - } else { - baseConfig = currentConfig; - } + const baseConfig = await getConfig(); // 更新主题配置 const updatedConfig: AdminConfig = { @@ -120,10 +84,23 @@ export async function POST(request: Request) { }, }; - console.log('保存主题配置:', updatedConfig.ThemeConfig); + console.log('=== 保存主题配置 ==='); + console.log('请求参数:', { defaultTheme, customCSS, allowUserCustomization }); + console.log('当前存储类型:', process.env.NEXT_PUBLIC_STORAGE_TYPE || 'localstorage'); + console.log('待保存配置:', updatedConfig.ThemeConfig); + console.log('完整配置对象:', JSON.stringify(updatedConfig, null, 2)); + await db.saveAdminConfig(updatedConfig); console.log('主题配置保存成功'); + // 直接更新缓存,确保缓存与数据库同步 + await setCachedConfig(updatedConfig); + console.log('已更新配置缓存'); + + // 立即验证缓存中的配置 + const cachedConfig = await getConfig(); + console.log('保存后验证缓存中的配置:', cachedConfig.ThemeConfig); + return NextResponse.json({ success: true, message: '主题配置已更新', diff --git a/src/app/api/theme/route.ts b/src/app/api/theme/route.ts deleted file mode 100644 index ff47fe5..0000000 --- a/src/app/api/theme/route.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { NextResponse } from 'next/server'; -import { db } from '@/lib/db'; - -export async function GET() { - try { - console.log('API /theme: 开始获取主题配置...'); - const config = await db.getAdminConfig(); - - console.log('API /theme: 获取到的管理员配置:', { - hasConfig: !!config, - hasThemeConfig: !!(config?.ThemeConfig), - themeConfig: config?.ThemeConfig - }); - - const themeConfig = config?.ThemeConfig || { - defaultTheme: 'default' as const, - customCSS: '', - allowUserCustomization: true, - }; - - console.log('API /theme: 最终返回的主题配置:', themeConfig); - - return NextResponse.json({ - success: true, - data: themeConfig, - }); - } catch (error) { - console.error('API /theme: 获取主题配置失败,返回默认配置:', error); - - const defaultThemeConfig = { - defaultTheme: 'default' as const, - customCSS: '', - allowUserCustomization: true, - }; - - return NextResponse.json( - { - success: true, // 改为 success: true,因为我们提供了有效的默认配置 - data: defaultThemeConfig, - fallback: true, // 标记这是备用配置 - error: error instanceof Error ? error.message : '未知错误' - }, - { status: 200 } - ); - } -} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 455031f..5ed01a7 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -6,7 +6,6 @@ import { Inter } from 'next/font/google'; import './globals.css'; import { getConfig } from '@/lib/config'; -import { db } from '@/lib/db'; import { GlobalErrorIndicator } from '../components/GlobalErrorIndicator'; import { SiteProvider } from '../components/SiteProvider'; @@ -44,33 +43,6 @@ export default async function RootLayout({ }) { const storageType = process.env.NEXT_PUBLIC_STORAGE_TYPE || 'localstorage'; - // 预先获取主题配置 - let themeConfig = { - defaultTheme: 'default', - customCSS: '', - allowUserCustomization: true - }; - - try { - if (storageType !== 'localstorage') { - const adminConfig = await db.getAdminConfig(); - if (adminConfig?.ThemeConfig) { - themeConfig = { - defaultTheme: adminConfig.ThemeConfig.defaultTheme || 'default', - customCSS: adminConfig.ThemeConfig.customCSS || '', - allowUserCustomization: adminConfig.ThemeConfig.allowUserCustomization !== false, - }; - console.log('服务端获取主题配置成功:', themeConfig); - } else { - console.log('服务端配置中没有主题配置,使用默认配置'); - } - } else { - console.log('LocalStorage模式,使用默认主题配置'); - } - } catch (error) { - console.error('服务端获取主题配置失败,使用默认配置:', error); - } - let siteName = process.env.NEXT_PUBLIC_SITE_NAME || 'OrangeTV'; let announcement = process.env.ANNOUNCEMENT || @@ -122,7 +94,6 @@ export default async function RootLayout({ CUSTOM_CATEGORIES: customCategories, FLUID_SEARCH: fluidSearch, REQUIRE_DEVICE_CODE: requireDeviceCode, - THEME_CONFIG: themeConfig, }; return ( @@ -141,84 +112,59 @@ export default async function RootLayout({ }} /> - {/* 主题初始化脚本 - 内联执行,确保在生产环境中立即应用主题 */} + {/* 立即从缓存应用主题,避免闪烁 */} {/* eslint-disable-next-line @next/next/no-sync-scripts */}