diff --git a/public/js/app.js b/public/js/app.js index d1ed0b5..220520e 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -1813,22 +1813,17 @@ const settings = { page_name: dom.pageNameInput.value.trim(), - title: dom.siteTitleInput.value.trim(), - logo_url: dom.logoUrlInput.value.trim(), - default_theme: dom.defaultThemeInput.value, - show_95_bandwidth: dom.show95BandwidthInput.value === "1" ? 1 : 0, - p95_type: dom.p95TypeSelect.value, - ps_filing: dom.psFilingInput ? dom.psFilingInput.value : '', - icp_filing: dom.icpFilingInput ? dom.icpFilingInput.value : '', + title: dom.siteTitleInput ? dom.siteTitleInput.value.trim() : dom.pageNameInput.value.trim(), + logo_url: dom.logoUrlInput ? dom.logoUrlInput.value.trim() : '', logo_url_dark: dom.logoUrlDarkInput ? dom.logoUrlDarkInput.value.trim() : '', - favicon_url: dom.faviconUrlInput ? dom.faviconUrlInput.value.trim() : '' + favicon_url: dom.faviconUrlInput ? dom.faviconUrlInput.value.trim() : '', + default_theme: dom.defaultThemeInput ? dom.defaultThemeInput.value : 'dark', + show_95_bandwidth: dom.show95BandwidthInput ? (dom.show95BandwidthInput.value === "1") : false, + p95_type: dom.p95TypeSelect ? dom.p95TypeSelect.value : 'tx', + ps_filing: dom.psFilingInput ? dom.psFilingInput.value.trim() : '', + icp_filing: dom.icpFilingInput ? dom.icpFilingInput.value.trim() : '' }; - // If user sets default to auto, we should clear their manual override or set it to auto - if (settings.default_theme === 'auto') { - localStorage.setItem('theme', 'auto'); - } - dom.btnSaveSiteSettings.disabled = true; dom.btnSaveSiteSettings.textContent = '保存中...'; @@ -1841,17 +1836,20 @@ if (response.ok) { showSiteMessage('设置保存成功', 'success'); - applySiteSettings(settings); + // Update global object and UI immediately + window.SITE_SETTINGS = { ...window.SITE_SETTINGS, ...settings }; + applySiteSettings(window.SITE_SETTINGS); } else { const err = await response.json(); - showSiteMessage(`保存失败: ${err.error}`, 'error'); + showSiteMessage(`保存失败: ${err.error || '未知错误'}`, 'error'); if (response.status === 401) openLoginModal(); } } catch (err) { showSiteMessage(`保存失败: ${err.message}`, 'error'); + console.error('Save settings error:', err); } finally { dom.btnSaveSiteSettings.disabled = false; - dom.btnSaveSiteSettings.textContent = '保存基础设置'; + dom.btnSaveSiteSettings.textContent = '保存设置'; } } diff --git a/server/db-integrity-check.js b/server/db-integrity-check.js index f17e77d..08069b8 100644 --- a/server/db-integrity-check.js +++ b/server/db-integrity-check.js @@ -57,58 +57,41 @@ async function checkAndFixDatabase() { // Check for new columns in site_settings const [columns] = await db.query("SHOW COLUMNS FROM site_settings"); const columnNames = columns.map(c => c.Field); - if (!columnNames.includes('show_95_bandwidth')) { - console.log(`[Database Integrity] ⚠️ Missing column 'show_95_bandwidth' in 'site_settings'. Adding it...`); - await db.query("ALTER TABLE site_settings ADD COLUMN show_95_bandwidth TINYINT(1) DEFAULT 0 AFTER default_theme"); - console.log(`[Database Integrity] ✅ Column 'show_95_bandwidth' added.`); - } - if (!columnNames.includes('p95_type')) { - console.log(`[Database Integrity] ⚠️ Missing column 'p95_type' in 'site_settings'. Adding it...`); - await db.query("ALTER TABLE site_settings ADD COLUMN p95_type VARCHAR(20) DEFAULT 'tx' AFTER show_95_bandwidth"); - console.log(`[Database Integrity] ✅ Column 'p95_type' added.`); - } - if (!columnNames.includes('blackbox_source_id')) { - console.log(`[Database Integrity] ⚠️ Missing column 'blackbox_source_id' in 'site_settings'. Adding it...`); - await db.query("ALTER TABLE site_settings ADD COLUMN blackbox_source_id INT AFTER p95_type"); - console.log(`[Database Integrity] ✅ Column 'blackbox_source_id' added.`); - } - if (!columnNames.includes('latency_source')) { - console.log(`[Database Integrity] ⚠️ Missing column 'latency_source' in 'site_settings'. Adding it...`); - await db.query("ALTER TABLE site_settings ADD COLUMN latency_source VARCHAR(100) AFTER blackbox_source_id"); - console.log(`[Database Integrity] ✅ Column 'latency_source' added.`); - } - if (!columnNames.includes('latency_dest')) { - console.log(`[Database Integrity] ⚠️ Missing column 'latency_dest' in 'site_settings'. Adding it...`); - await db.query("ALTER TABLE site_settings ADD COLUMN latency_dest VARCHAR(100) AFTER latency_source"); - console.log(`[Database Integrity] ✅ Column 'latency_dest' added.`); - } - if (!columnNames.includes('latency_target')) { - console.log(`[Database Integrity] ⚠️ Missing column 'latency_target' in 'site_settings'. Adding it...`); - await db.query("ALTER TABLE site_settings ADD COLUMN latency_target VARCHAR(255) AFTER latency_dest"); - console.log(`[Database Integrity] ✅ Column 'latency_target' added.`); - } - if (!columnNames.includes('icp_filing')) { - console.log(`[Database Integrity] ⚠️ Missing column 'icp_filing' in 'site_settings'. Adding it...`); - await db.query("ALTER TABLE site_settings ADD COLUMN icp_filing VARCHAR(255) AFTER latency_target"); - console.log(`[Database Integrity] ✅ Column 'icp_filing' added.`); - } - if (!columnNames.includes('ps_filing')) { - console.log(`[Database Integrity] ⚠️ Missing column 'ps_filing' in 'site_settings'. Adding it...`); - await db.query("ALTER TABLE site_settings ADD COLUMN ps_filing VARCHAR(255) AFTER icp_filing"); - console.log(`[Database Integrity] ✅ Column 'ps_filing' added.`); - } - if (!columnNames.includes('logo_url_dark')) { - console.log(`[Database Integrity] ⚠️ Missing column 'logo_url_dark' in 'site_settings'. Adding it...`); - await db.query("ALTER TABLE site_settings ADD COLUMN logo_url_dark TEXT AFTER logo_url"); - console.log(`[Database Integrity] ✅ Column 'logo_url_dark' added.`); - } - if (!columnNames.includes('favicon_url')) { - console.log(`[Database Integrity] ⚠️ Missing column 'favicon_url' in 'site_settings'. Adding it...`); - await db.query("ALTER TABLE site_settings ADD COLUMN favicon_url TEXT AFTER logo_url_dark"); - console.log(`[Database Integrity] ✅ Column 'favicon_url' added.`); - } + const addColumn = async (columnName, sql) => { + if (!columnNames.includes(columnName)) { + try { + console.log(`[Database Integrity] ⚠️ Missing column '${columnName}' in 'site_settings'. Adding it...`); + await db.query(sql); + console.log(`[Database Integrity] ✅ Column '${columnName}' added.`); + } catch (err) { + console.error(`[Database Integrity] ❌ Failed to add column '${columnName}':`, err.message); + // Try without AFTER if it exists + if (sql.includes('AFTER')) { + try { + const fallback = sql.split(' AFTER')[0]; + console.log(`[Database Integrity] 🔄 Retrying column '${columnName}' WITHOUT 'AFTER'...`); + await db.query(fallback); + console.log(`[Database Integrity] ✅ Column '${columnName}' added via fallback.`); + } catch (err2) { + console.error(`[Database Integrity] ❌ Fallback also failed:`, err2.message); + } + } + } + } + }; + + await addColumn('show_95_bandwidth', "ALTER TABLE site_settings ADD COLUMN show_95_bandwidth TINYINT(1) DEFAULT 0 AFTER default_theme"); + await addColumn('p95_type', "ALTER TABLE site_settings ADD COLUMN p95_type VARCHAR(20) DEFAULT 'tx' AFTER show_95_bandwidth"); + await addColumn('blackbox_source_id', "ALTER TABLE site_settings ADD COLUMN blackbox_source_id INT AFTER p95_type"); + await addColumn('latency_source', "ALTER TABLE site_settings ADD COLUMN latency_source VARCHAR(100) AFTER blackbox_source_id"); + await addColumn('latency_dest', "ALTER TABLE site_settings ADD COLUMN latency_dest VARCHAR(100) AFTER latency_source"); + await addColumn('latency_target', "ALTER TABLE site_settings ADD COLUMN latency_target VARCHAR(255) AFTER latency_dest"); + await addColumn('icp_filing', "ALTER TABLE site_settings ADD COLUMN icp_filing VARCHAR(255) AFTER latency_target"); + await addColumn('ps_filing', "ALTER TABLE site_settings ADD COLUMN ps_filing VARCHAR(255) AFTER icp_filing"); + await addColumn('logo_url_dark', "ALTER TABLE site_settings ADD COLUMN logo_url_dark TEXT AFTER logo_url"); + await addColumn('favicon_url', "ALTER TABLE site_settings ADD COLUMN favicon_url TEXT AFTER logo_url_dark"); } catch (err) { - console.error('[Database Integrity] ❌ Error checking integrity:', err.message); + console.error('[Database Integrity] ❌ Overall site_settings check error:', err.message); } } diff --git a/server/index.js b/server/index.js index dff8037..a0eb227 100644 --- a/server/index.js +++ b/server/index.js @@ -588,34 +588,67 @@ app.get('/api/settings', async (req, res) => { // Update site settings app.post('/api/settings', requireAuth, async (req, res) => { - const { page_name, title, logo_url, logo_url_dark, favicon_url, default_theme, show_95_bandwidth, p95_type, blackbox_source_id, latency_source, latency_dest, latency_target, icp_filing, ps_filing } = req.body; - try { - await db.query( - `INSERT INTO site_settings (id, page_name, title, logo_url, logo_url_dark, favicon_url, default_theme, show_95_bandwidth, p95_type, blackbox_source_id, latency_source, latency_dest, latency_target, icp_filing, ps_filing) - VALUES (1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - ON DUPLICATE KEY UPDATE - page_name = VALUES(page_name), - title = VALUES(title), - logo_url = VALUES(logo_url), - logo_url_dark = VALUES(logo_url_dark), - favicon_url = VALUES(favicon_url), - default_theme = VALUES(default_theme), - show_95_bandwidth = VALUES(show_95_bandwidth), - p95_type = VALUES(p95_type), - blackbox_source_id = VALUES(blackbox_source_id), - latency_source = VALUES(latency_source), - latency_dest = VALUES(latency_dest), - latency_target = VALUES(latency_target), - icp_filing = VALUES(icp_filing), - ps_filing = VALUES(ps_filing)`, - [ - page_name, title, logo_url, logo_url_dark, favicon_url, default_theme, - show_95_bandwidth ? 1 : 0, p95_type || 'tx', - blackbox_source_id || null, latency_source || null, - latency_dest || null, latency_target || null, - icp_filing || null, ps_filing || null - ] - ); + try { + // 1. Fetch current settings first to preserve fields not sent by the UI + const [rows] = await db.query('SELECT * FROM site_settings WHERE id = 1'); + let current = rows.length > 0 ? rows[0] : {}; + + // 2. Destructure fields from body + const { + page_name, title, logo_url, logo_url_dark, favicon_url, + default_theme, show_95_bandwidth, p95_type, + icp_filing, ps_filing + } = req.body; + + // 3. Prepare parameters, prioritizing body but falling back to current + const settings = { + page_name: page_name !== undefined ? page_name : (current.page_name || '数据可视化展示大屏'), + title: title !== undefined ? title : (current.title || '数据可视化展示大屏'), + logo_url: logo_url !== undefined ? logo_url : (current.logo_url || null), + logo_url_dark: logo_url_dark !== undefined ? logo_url_dark : (current.logo_url_dark || null), + favicon_url: favicon_url !== undefined ? favicon_url : (current.favicon_url || null), + default_theme: default_theme !== undefined ? default_theme : (current.default_theme || 'dark'), + show_95_bandwidth: show_95_bandwidth !== undefined ? (show_95_bandwidth ? 1 : 0) : (current.show_95_bandwidth || 0), + p95_type: p95_type !== undefined ? p95_type : (current.p95_type || 'tx'), + blackbox_source_id: current.blackbox_source_id || null, // UI doesn't send this + latency_source: current.latency_source || null, // UI doesn't send this + latency_dest: current.latency_dest || null, // UI doesn't send this + latency_target: current.latency_target || null, // UI doesn't send this + icp_filing: icp_filing !== undefined ? icp_filing : (current.icp_filing || null), + ps_filing: ps_filing !== undefined ? ps_filing : (current.ps_filing || null) + }; + + // 4. Update database + await db.query( + `INSERT INTO site_settings ( + id, page_name, title, logo_url, logo_url_dark, favicon_url, + default_theme, show_95_bandwidth, p95_type, + blackbox_source_id, latency_source, latency_dest, latency_target, + icp_filing, ps_filing + ) VALUES (1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ON DUPLICATE KEY UPDATE + page_name = VALUES(page_name), + title = VALUES(title), + logo_url = VALUES(logo_url), + logo_url_dark = VALUES(logo_url_dark), + favicon_url = VALUES(favicon_url), + default_theme = VALUES(default_theme), + show_95_bandwidth = VALUES(show_95_bandwidth), + p95_type = VALUES(p95_type), + blackbox_source_id = VALUES(blackbox_source_id), + latency_source = VALUES(latency_source), + latency_dest = VALUES(latency_dest), + latency_target = VALUES(latency_target), + icp_filing = VALUES(icp_filing), + ps_filing = VALUES(ps_filing)`, + [ + settings.page_name, settings.title, settings.logo_url, settings.logo_url_dark, settings.favicon_url, + settings.default_theme, settings.show_95_bandwidth, settings.p95_type, + settings.blackbox_source_id, settings.latency_source, settings.latency_dest, settings.latency_target, + settings.icp_filing, settings.ps_filing + ] + ); + res.json({ success: true }); } catch (err) { console.error('Error updating settings:', err);