支持为静态资源设置独立地址
This commit is contained in:
@@ -596,6 +596,11 @@
|
|||||||
<label for="icpFilingInput">ICP 备案号 (如:京ICP备12345678号)</label>
|
<label for="icpFilingInput">ICP 备案号 (如:京ICP备12345678号)</label>
|
||||||
<input type="text" id="icpFilingInput" placeholder="请输入 ICP 备案号">
|
<input type="text" id="icpFilingInput" placeholder="请输入 ICP 备案号">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group" style="margin-top: 15px;">
|
||||||
|
<label for="cdnUrlInput">静态资源 CDN 地址 (例如: https://cdn.example.com)</label>
|
||||||
|
<input type="url" id="cdnUrlInput" placeholder="留空则使用本地服务器资源">
|
||||||
|
<p style="font-size: 0.72rem; color: var(--text-muted); margin-top: 6px;">开启后,页面中的 JS/CSS/图片等资源将尝试从该 CDN 加载。请确保 CDN 已正确镜像相关资源。</p>
|
||||||
|
</div>
|
||||||
<div class="form-actions" style="margin-top: 25px; display: flex; justify-content: flex-end;">
|
<div class="form-actions" style="margin-top: 25px; display: flex; justify-content: flex-end;">
|
||||||
<button class="btn btn-add" id="btnSaveSiteSettings">保存基础设置</button>
|
<button class="btn btn-add" id="btnSaveSiteSettings">保存基础设置</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -131,7 +131,8 @@
|
|||||||
customMetricsList: document.getElementById('customMetricsList'),
|
customMetricsList: document.getElementById('customMetricsList'),
|
||||||
btnAddCustomMetric: document.getElementById('btnAddCustomMetric'),
|
btnAddCustomMetric: document.getElementById('btnAddCustomMetric'),
|
||||||
btnSaveCustomMetrics: document.getElementById('btnSaveCustomMetrics'),
|
btnSaveCustomMetrics: document.getElementById('btnSaveCustomMetrics'),
|
||||||
customDataContainer: document.getElementById('customDataContainer')
|
customDataContainer: document.getElementById('customDataContainer'),
|
||||||
|
cdnUrlInput: document.getElementById('cdnUrlInput')
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---- State ----
|
// ---- State ----
|
||||||
@@ -2146,13 +2147,13 @@
|
|||||||
if (dom.faviconUrlInput) dom.faviconUrlInput.value = settings.favicon_url || '';
|
if (dom.faviconUrlInput) dom.faviconUrlInput.value = settings.favicon_url || '';
|
||||||
if (dom.showPageNameInput) dom.showPageNameInput.value = settings.show_page_name !== undefined ? settings.show_page_name.toString() : "1";
|
if (dom.showPageNameInput) dom.showPageNameInput.value = settings.show_page_name !== undefined ? settings.show_page_name.toString() : "1";
|
||||||
if (dom.requireLoginForServerDetailsInput) dom.requireLoginForServerDetailsInput.value = settings.require_login_for_server_details ? "1" : "0";
|
if (dom.requireLoginForServerDetailsInput) dom.requireLoginForServerDetailsInput.value = settings.require_login_for_server_details ? "1" : "0";
|
||||||
|
if (dom.showServerIpInput) dom.showServerIpInput.value = settings.show_server_ip ? "1" : "0";
|
||||||
|
if (dom.cdnUrlInput) dom.cdnUrlInput.value = settings.cdn_url || '';
|
||||||
|
|
||||||
// Handle Theme Priority: localStorage > Site Default
|
// Handle Theme Priority: localStorage > Site Default
|
||||||
const savedTheme = localStorage.getItem('theme');
|
const savedTheme = localStorage.getItem('theme');
|
||||||
const themeToApply = savedTheme || settings.default_theme || 'dark';
|
const themeToApply = savedTheme || settings.default_theme || 'dark';
|
||||||
applyTheme(themeToApply);
|
applyTheme(themeToApply);
|
||||||
|
|
||||||
// Listen for system theme changes if set to auto (cleanup existing listener first)
|
|
||||||
if (siteThemeQuery && siteThemeHandler) {
|
if (siteThemeQuery && siteThemeHandler) {
|
||||||
siteThemeQuery.removeEventListener('change', siteThemeHandler);
|
siteThemeQuery.removeEventListener('change', siteThemeHandler);
|
||||||
}
|
}
|
||||||
@@ -2309,7 +2310,8 @@
|
|||||||
show_server_ip: dom.showServerIpInput ? (dom.showServerIpInput.value === "1") : false,
|
show_server_ip: dom.showServerIpInput ? (dom.showServerIpInput.value === "1") : false,
|
||||||
ip_metric_name: dom.ipMetricNameInput ? dom.ipMetricNameInput.value.trim() : null,
|
ip_metric_name: dom.ipMetricNameInput ? dom.ipMetricNameInput.value.trim() : null,
|
||||||
ip_label_name: dom.ipLabelNameInput ? dom.ipLabelNameInput.value.trim() : 'address',
|
ip_label_name: dom.ipLabelNameInput ? dom.ipLabelNameInput.value.trim() : 'address',
|
||||||
custom_metrics: getCustomMetricsFromUI()
|
custom_metrics: getCustomMetricsFromUI(),
|
||||||
|
cdn_url: dom.cdnUrlInput ? dom.cdnUrlInput.value.trim() : ''
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ const SCHEMA = {
|
|||||||
ip_metric_name VARCHAR(100) DEFAULT NULL,
|
ip_metric_name VARCHAR(100) DEFAULT NULL,
|
||||||
ip_label_name VARCHAR(100) DEFAULT 'address',
|
ip_label_name VARCHAR(100) DEFAULT 'address',
|
||||||
custom_metrics JSON DEFAULT NULL,
|
custom_metrics JSON DEFAULT NULL,
|
||||||
|
cdn_url VARCHAR(500) DEFAULT NULL,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||||
`,
|
`,
|
||||||
@@ -103,7 +104,8 @@ const SCHEMA = {
|
|||||||
{ name: 'show_server_ip', sql: "ALTER TABLE site_settings ADD COLUMN show_server_ip TINYINT(1) DEFAULT 0 AFTER ps_filing" },
|
{ name: 'show_server_ip', sql: "ALTER TABLE site_settings ADD COLUMN show_server_ip TINYINT(1) DEFAULT 0 AFTER ps_filing" },
|
||||||
{ name: 'ip_metric_name', sql: "ALTER TABLE site_settings ADD COLUMN ip_metric_name VARCHAR(100) DEFAULT NULL AFTER show_server_ip" },
|
{ name: 'ip_metric_name', sql: "ALTER TABLE site_settings ADD COLUMN ip_metric_name VARCHAR(100) DEFAULT NULL AFTER show_server_ip" },
|
||||||
{ name: 'ip_label_name', sql: "ALTER TABLE site_settings ADD COLUMN ip_label_name VARCHAR(100) DEFAULT 'address' AFTER ip_metric_name" },
|
{ name: 'ip_label_name', sql: "ALTER TABLE site_settings ADD COLUMN ip_label_name VARCHAR(100) DEFAULT 'address' AFTER ip_metric_name" },
|
||||||
{ name: 'custom_metrics', sql: "ALTER TABLE site_settings ADD COLUMN custom_metrics JSON DEFAULT NULL AFTER ip_label_name" }
|
{ name: 'custom_metrics', sql: "ALTER TABLE site_settings ADD COLUMN custom_metrics JSON DEFAULT NULL AFTER ip_label_name" },
|
||||||
|
{ name: 'cdn_url', sql: "ALTER TABLE site_settings ADD COLUMN cdn_url VARCHAR(500) DEFAULT NULL AFTER custom_metrics" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
traffic_stats: {
|
traffic_stats: {
|
||||||
|
|||||||
@@ -151,7 +151,8 @@ function getPublicSiteSettings(settings = {}) {
|
|||||||
show_server_ip: settings.show_server_ip ? 1 : 0,
|
show_server_ip: settings.show_server_ip ? 1 : 0,
|
||||||
ip_metric_name: settings.ip_metric_name || null,
|
ip_metric_name: settings.ip_metric_name || null,
|
||||||
ip_label_name: settings.ip_label_name || 'address',
|
ip_label_name: settings.ip_label_name || 'address',
|
||||||
custom_metrics: settings.custom_metrics || []
|
custom_metrics: settings.custom_metrics || [],
|
||||||
|
cdn_url: settings.cdn_url || null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -780,6 +781,14 @@ const serveIndex = async (req, res) => {
|
|||||||
|
|
||||||
// Replace <head> with <head> + injection
|
// Replace <head> with <head> + injection
|
||||||
html = html.replace('<head>', '<head>' + injection);
|
html = html.replace('<head>', '<head>' + injection);
|
||||||
|
|
||||||
|
// Apply CDN URL if set
|
||||||
|
if (settings.cdn_url) {
|
||||||
|
const cdnBase = settings.cdn_url.replace(/\/+$/, '');
|
||||||
|
// Replace relative paths for css, js, fonts, vendor, images
|
||||||
|
// Matches href="/css/...", src="/js/...", etc.
|
||||||
|
html = html.replace(/(href|src)="\/+(css|js|fonts|vendor|images|assets)\//g, `$1="${cdnBase}/$2/`);
|
||||||
|
}
|
||||||
|
|
||||||
res.send(html);
|
res.send(html);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -943,7 +952,8 @@ app.post('/api/settings', requireAuth, async (req, res) => {
|
|||||||
const {
|
const {
|
||||||
page_name, show_page_name, title, logo_url, logo_url_dark, favicon_url,
|
page_name, show_page_name, title, logo_url, logo_url_dark, favicon_url,
|
||||||
default_theme, show_95_bandwidth, p95_type, require_login_for_server_details,
|
default_theme, show_95_bandwidth, p95_type, require_login_for_server_details,
|
||||||
icp_filing, ps_filing, show_server_ip, ip_metric_name, ip_label_name, custom_metrics
|
icp_filing, ps_filing, show_server_ip, ip_metric_name, ip_label_name, custom_metrics,
|
||||||
|
cdn_url
|
||||||
} = req.body;
|
} = req.body;
|
||||||
|
|
||||||
// 3. Prepare parameters, prioritizing body but falling back to current
|
// 3. Prepare parameters, prioritizing body but falling back to current
|
||||||
@@ -969,7 +979,8 @@ app.post('/api/settings', requireAuth, async (req, res) => {
|
|||||||
show_server_ip: show_server_ip !== undefined ? (show_server_ip ? 1 : 0) : (current.show_server_ip || 0),
|
show_server_ip: show_server_ip !== undefined ? (show_server_ip ? 1 : 0) : (current.show_server_ip || 0),
|
||||||
ip_metric_name: ip_metric_name !== undefined ? ip_metric_name : (current.ip_metric_name || null),
|
ip_metric_name: ip_metric_name !== undefined ? ip_metric_name : (current.ip_metric_name || null),
|
||||||
ip_label_name: ip_label_name !== undefined ? ip_label_name : (current.ip_label_name || 'address'),
|
ip_label_name: ip_label_name !== undefined ? ip_label_name : (current.ip_label_name || 'address'),
|
||||||
custom_metrics: custom_metrics !== undefined ? JSON.stringify(custom_metrics) : (current.custom_metrics || '[]')
|
custom_metrics: custom_metrics !== undefined ? JSON.stringify(custom_metrics) : (current.custom_metrics || '[]'),
|
||||||
|
cdn_url: cdn_url !== undefined ? cdn_url : (current.cdn_url || null)
|
||||||
};
|
};
|
||||||
|
|
||||||
await db.query(`
|
await db.query(`
|
||||||
@@ -978,8 +989,8 @@ app.post('/api/settings', requireAuth, async (req, res) => {
|
|||||||
default_theme, show_95_bandwidth, p95_type, require_login_for_server_details,
|
default_theme, show_95_bandwidth, p95_type, require_login_for_server_details,
|
||||||
blackbox_source_id, latency_source, latency_dest, latency_target,
|
blackbox_source_id, latency_source, latency_dest, latency_target,
|
||||||
icp_filing, ps_filing, show_server_ip, ip_metric_name, ip_label_name,
|
icp_filing, ps_filing, show_server_ip, ip_metric_name, ip_label_name,
|
||||||
custom_metrics
|
custom_metrics, cdn_url
|
||||||
) VALUES (1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
) VALUES (1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
ON DUPLICATE KEY UPDATE
|
ON DUPLICATE KEY UPDATE
|
||||||
page_name = VALUES(page_name),
|
page_name = VALUES(page_name),
|
||||||
show_page_name = VALUES(show_page_name),
|
show_page_name = VALUES(show_page_name),
|
||||||
@@ -1000,13 +1011,15 @@ app.post('/api/settings', requireAuth, async (req, res) => {
|
|||||||
show_server_ip = VALUES(show_server_ip),
|
show_server_ip = VALUES(show_server_ip),
|
||||||
ip_metric_name = VALUES(ip_metric_name),
|
ip_metric_name = VALUES(ip_metric_name),
|
||||||
ip_label_name = VALUES(ip_label_name),
|
ip_label_name = VALUES(ip_label_name),
|
||||||
custom_metrics = VALUES(custom_metrics)`,
|
custom_metrics = VALUES(custom_metrics),
|
||||||
|
cdn_url = VALUES(cdn_url)`,
|
||||||
[
|
[
|
||||||
settings.page_name, settings.show_page_name, settings.title, settings.logo_url, settings.logo_url_dark, settings.favicon_url,
|
settings.page_name, settings.show_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.require_login_for_server_details,
|
settings.default_theme, settings.show_95_bandwidth, settings.p95_type, settings.require_login_for_server_details,
|
||||||
settings.blackbox_source_id, settings.latency_source, settings.latency_dest, settings.latency_target,
|
settings.blackbox_source_id, settings.latency_source, settings.latency_dest, settings.latency_target,
|
||||||
settings.icp_filing, settings.ps_filing, settings.show_server_ip,
|
settings.icp_filing, settings.ps_filing, settings.show_server_ip,
|
||||||
settings.ip_metric_name, settings.ip_label_name, settings.custom_metrics
|
settings.ip_metric_name, settings.ip_label_name, settings.custom_metrics,
|
||||||
|
settings.cdn_url
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user