diff --git a/src/app/api/theme/route.ts b/src/app/api/theme/route.ts index a0393ea..ff47fe5 100644 --- a/src/app/api/theme/route.ts +++ b/src/app/api/theme/route.ts @@ -3,29 +3,44 @@ 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('获取主题配置失败:', error); + console.error('API /theme: 获取主题配置失败,返回默认配置:', error); + + const defaultThemeConfig = { + defaultTheme: 'default' as const, + customCSS: '', + allowUserCustomization: true, + }; + return NextResponse.json( { - success: false, - data: { - defaultTheme: 'default' as const, - customCSS: '', - allowUserCustomization: true, - } + success: true, // 改为 success: true,因为我们提供了有效的默认配置 + data: defaultThemeConfig, + fallback: true, // 标记这是备用配置 + error: error instanceof Error ? error.message : '未知错误' }, - { status: 200 } // 返回默认配置而不是错误 + { status: 200 } ); } } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 9b453e9..455031f 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -55,11 +55,20 @@ export default async function RootLayout({ if (storageType !== 'localstorage') { const adminConfig = await db.getAdminConfig(); if (adminConfig?.ThemeConfig) { - themeConfig = 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); + console.error('服务端获取主题配置失败,使用默认配置:', error); } let siteName = process.env.NEXT_PUBLIC_SITE_NAME || 'OrangeTV'; @@ -141,46 +150,70 @@ export default async function RootLayout({ try { console.log('开始初始化主题...'); + // 应用主题函数 + function applyTheme(themeId, css) { + try { + const html = document.documentElement; + + // 移除所有主题属性 + html.removeAttribute('data-theme'); + + // 应用主题 + if (themeId && themeId !== 'default') { + html.setAttribute('data-theme', themeId); + } + + // 应用自定义CSS + if (css) { + let customStyleEl = document.getElementById('custom-theme-css'); + if (!customStyleEl) { + customStyleEl = document.createElement('style'); + customStyleEl.id = 'custom-theme-css'; + document.head.appendChild(customStyleEl); + } + customStyleEl.textContent = css; + } + return true; + } catch (e) { + console.error('应用主题失败:', e); + return false; + } + } + // 获取预设的主题配置 - const themeConfig = window.RUNTIME_CONFIG?.THEME_CONFIG || { + let themeConfig = { defaultTheme: 'default', customCSS: '' }; - console.log('服务端主题配置:', themeConfig); - - // 应用主题函数 - function applyTheme(themeId, css) { - const html = document.documentElement; - - // 移除所有主题属性 - html.removeAttribute('data-theme'); - - // 应用主题 - if (themeId !== 'default') { - html.setAttribute('data-theme', themeId); - } - - // 应用自定义CSS - if (css) { - let customStyleEl = document.getElementById('custom-theme-css'); - if (!customStyleEl) { - customStyleEl = document.createElement('style'); - customStyleEl.id = 'custom-theme-css'; - document.head.appendChild(customStyleEl); - } - customStyleEl.textContent = css; + try { + if (window.RUNTIME_CONFIG && window.RUNTIME_CONFIG.THEME_CONFIG) { + themeConfig = window.RUNTIME_CONFIG.THEME_CONFIG; + console.log('使用服务端主题配置:', themeConfig); + } else { + console.log('未找到服务端主题配置,使用默认配置'); } + } catch (e) { + console.warn('获取服务端主题配置失败:', e); } - // 立即应用服务端主题配置 - applyTheme(themeConfig.defaultTheme, themeConfig.customCSS); - console.log('主题已初始化:', themeConfig.defaultTheme); + // 立即应用主题配置 + const success = applyTheme(themeConfig.defaultTheme, themeConfig.customCSS); + if (success) { + console.log('主题已初始化:', themeConfig.defaultTheme); + } else { + console.log('主题初始化失败,将等待客户端重新加载'); + } } catch (error) { - console.error('主题初始化失败:', error); - // 失败时应用默认主题 - document.documentElement.removeAttribute('data-theme'); + console.error('主题初始化过程失败:', error); + // 最终备用方案:确保HTML至少没有错误的主题属性 + try { + document.documentElement.removeAttribute('data-theme'); + console.log('已清除主题属性作为备用方案'); + } catch (e) { + console.error('连备用方案也失败了:', e); + } } })(); `, diff --git a/src/components/GlobalThemeLoader.tsx b/src/components/GlobalThemeLoader.tsx index 7782331..aba0422 100644 --- a/src/components/GlobalThemeLoader.tsx +++ b/src/components/GlobalThemeLoader.tsx @@ -2,43 +2,86 @@ import { useEffect } from 'react'; -// 全局主题加载器组件 - 作为服务端主题配置的同步和备份机制 +// 全局主题加载器组件 - 确保主题配置始终正确,优先信任服务端配置 const GlobalThemeLoader = () => { useEffect(() => { - const syncGlobalTheme = async () => { + const validateAndSyncTheme = async () => { try { - // 检查是否已有服务端预设的主题配置 + // 检查服务端预设的配置 const runtimeConfig = (window as any).RUNTIME_CONFIG; const serverThemeConfig = runtimeConfig?.THEME_CONFIG; - console.log('检查服务端主题配置:', serverThemeConfig); + console.log('检查服务端预设主题配置:', serverThemeConfig); - if (serverThemeConfig) { - // 服务端已经应用了主题配置,检查是否需要同步更新 - console.log('服务端主题配置已存在,无需重新加载'); + if (serverThemeConfig && serverThemeConfig.defaultTheme !== 'default') { + // 服务端有非默认配置,优先使用服务端配置 + console.log('使用服务端主题配置,跳过API检查:', serverThemeConfig); + + // 确保服务端配置已正确应用到DOM + const html = document.documentElement; + const currentTheme = html.getAttribute('data-theme'); + + if (currentTheme !== serverThemeConfig.defaultTheme) { + console.log('DOM主题与服务端配置不一致,重新应用:', { + current: currentTheme, + expected: serverThemeConfig.defaultTheme + }); + applyTheme(serverThemeConfig.defaultTheme, serverThemeConfig.customCSS || ''); + } else { + console.log('服务端主题配置已正确应用,无需更新'); + } return; } - // 如果没有服务端配置,则从API获取(备用方案) - console.log('未检测到服务端主题配置,尝试从API加载...'); + // 只有当服务端配置为默认值时,才从API获取配置 + console.log('服务端为默认配置,从API获取最新配置...'); const response = await fetch('/api/theme'); const result = await response.json(); if (result.success && result.data) { const { defaultTheme, customCSS } = result.data; - console.log('从API获取到主题配置:', { defaultTheme, customCSS }); + const isFallback = result.fallback; - // 应用从API获取的配置 - applyTheme(defaultTheme, customCSS); - console.log('已应用API主题配置:', defaultTheme); + console.log('从API获取到主题配置:', { + defaultTheme, + customCSS, + isFallback: !!isFallback, + error: result.error + }); + + if (isFallback) { + console.log('API返回备用配置,保持服务端设置不变'); + return; + } + + // 只有API返回非默认配置且非备用配置时才应用 + if (defaultTheme !== 'default' || customCSS) { + console.log('应用API获取的有效主题配置:', { defaultTheme, customCSS }); + applyTheme(defaultTheme, customCSS); + + // 更新运行时配置 + if (runtimeConfig) { + runtimeConfig.THEME_CONFIG = { defaultTheme, customCSS, allowUserCustomization: true }; + } + } else { + console.log('API返回默认配置,保持当前状态'); + } + } else { + console.log('API获取失败,保持当前主题配置'); } } catch (error) { - console.error('同步全站主题配置失败:', error); - // 失败时检查当前HTML状态,如果没有主题则应用默认 - const html = document.documentElement; - if (!html.hasAttribute('data-theme')) { + console.error('主题配置验证失败:', error); + + // 出错时优先使用服务端配置 + const runtimeConfig = (window as any).RUNTIME_CONFIG; + const serverThemeConfig = runtimeConfig?.THEME_CONFIG; + + if (serverThemeConfig) { + console.log('错误恢复:使用服务端配置:', serverThemeConfig); + applyTheme(serverThemeConfig.defaultTheme, serverThemeConfig.customCSS || ''); + } else { + console.log('错误恢复:使用默认主题'); applyTheme('default', ''); - console.log('应用默认主题作为备用'); } } }; @@ -65,9 +108,9 @@ const GlobalThemeLoader = () => { customStyleEl.textContent = css; }; - // 稍作延迟,确保DOM完全加载后再同步 + // 稍作延迟,确保DOM完全加载后再验证主题 const timer = setTimeout(() => { - syncGlobalTheme(); + validateAndSyncTheme(); }, 100); return () => clearTimeout(timer); diff --git a/src/components/ThemeManager.tsx b/src/components/ThemeManager.tsx index 0ae689c..be7e575 100644 --- a/src/components/ThemeManager.tsx +++ b/src/components/ThemeManager.tsx @@ -295,6 +295,9 @@ const ThemeManager = ({ showAlert, role }: ThemeManagerProps) => { const response = await fetch('/api/theme'); const result = await response.json(); if (result.success) { + if (result.fallback) { + console.log('API返回备用配置,可能存在数据库访问问题'); + } setGlobalThemeConfig(result.data); return result.data; } @@ -327,6 +330,10 @@ const ThemeManager = ({ showAlert, role }: ThemeManagerProps) => { console.log('已更新运行时主题配置:', result.data); } + // 立即应用新的主题配置,确保当前页面也能看到更改 + applyTheme(result.data.defaultTheme, result.data.customCSS); + console.log('已立即应用新主题配置:', result.data.defaultTheme); + showAlert({ type: 'success', title: '全站主题配置已保存', @@ -500,6 +507,16 @@ const ThemeManager = ({ showAlert, role }: ThemeManagerProps) => { customCSS: '', allowUserCustomization: globalThemeConfig?.allowUserCustomization ?? true, }); + + // 更新运行时配置 + const runtimeConfig = (window as any).RUNTIME_CONFIG; + if (runtimeConfig) { + runtimeConfig.THEME_CONFIG = { + defaultTheme: currentTheme, + customCSS: '', + allowUserCustomization: globalThemeConfig?.allowUserCustomization ?? true, + }; + } } showAlert({