添加设置项
This commit is contained in:
@@ -507,6 +507,15 @@
|
|||||||
<option value="0">隐藏 (Hide)</option>
|
<option value="0">隐藏 (Hide)</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group" style="margin-top: 15px;">
|
||||||
|
<label for="requireLoginForServerDetailsInput">服务器详情是否仅登录后可查看</label>
|
||||||
|
<select id="requireLoginForServerDetailsInput"
|
||||||
|
style="padding: 10px 14px; background: var(--bg-input); border: 1px solid var(--border-color); border-radius: var(--radius-sm); color: var(--text-primary); width: 100%;">
|
||||||
|
<option value="1">仅登录后可查看</option>
|
||||||
|
<option value="0">允许公开查看</option>
|
||||||
|
</select>
|
||||||
|
<p style="font-size: 0.72rem; color: var(--text-muted); margin-top: 6px;">开启后,未登录访客仍可看到大屏总览,但点击单台服务器时需要先登录。</p>
|
||||||
|
</div>
|
||||||
<div class="form-group" style="margin-top: 15px;">
|
<div class="form-group" style="margin-top: 15px;">
|
||||||
<label for="logoUrlInput">Logo URL (白天/默认,支持图片链接)</label>
|
<label for="logoUrlInput">Logo URL (白天/默认,支持图片链接)</label>
|
||||||
<input type="url" id="logoUrlInput" placeholder="https://example.com/logo_light.png">
|
<input type="url" id="logoUrlInput" placeholder="https://example.com/logo_light.png">
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
faviconUrlInput: document.getElementById('faviconUrlInput'),
|
faviconUrlInput: document.getElementById('faviconUrlInput'),
|
||||||
logoUrlDarkInput: document.getElementById('logoUrlDarkInput'),
|
logoUrlDarkInput: document.getElementById('logoUrlDarkInput'),
|
||||||
showPageNameInput: document.getElementById('showPageNameInput'),
|
showPageNameInput: document.getElementById('showPageNameInput'),
|
||||||
|
requireLoginForServerDetailsInput: document.getElementById('requireLoginForServerDetailsInput'),
|
||||||
// Site Settings
|
// Site Settings
|
||||||
modalTabs: document.querySelectorAll('.modal-tab'),
|
modalTabs: document.querySelectorAll('.modal-tab'),
|
||||||
tabContents: document.querySelectorAll('.tab-content'),
|
tabContents: document.querySelectorAll('.tab-content'),
|
||||||
@@ -417,6 +418,10 @@
|
|||||||
const job = row.getAttribute('data-job');
|
const job = row.getAttribute('data-job');
|
||||||
const source = row.getAttribute('data-source');
|
const source = row.getAttribute('data-source');
|
||||||
if (instance && job && source) {
|
if (instance && job && source) {
|
||||||
|
if (requiresLoginForServerDetails() && !user) {
|
||||||
|
promptLogin('登录后可查看服务器详细指标');
|
||||||
|
return;
|
||||||
|
}
|
||||||
openServerDetail(instance, job, source);
|
openServerDetail(instance, job, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -528,6 +533,7 @@
|
|||||||
if (dom.defaultThemeInput) dom.defaultThemeInput.value = window.SITE_SETTINGS.default_theme || 'dark';
|
if (dom.defaultThemeInput) dom.defaultThemeInput.value = window.SITE_SETTINGS.default_theme || 'dark';
|
||||||
if (dom.show95BandwidthInput) dom.show95BandwidthInput.value = window.SITE_SETTINGS.show_95_bandwidth ? "1" : "0";
|
if (dom.show95BandwidthInput) dom.show95BandwidthInput.value = window.SITE_SETTINGS.show_95_bandwidth ? "1" : "0";
|
||||||
if (dom.p95TypeSelect) dom.p95TypeSelect.value = window.SITE_SETTINGS.p95_type || 'tx';
|
if (dom.p95TypeSelect) dom.p95TypeSelect.value = window.SITE_SETTINGS.p95_type || 'tx';
|
||||||
|
if (dom.requireLoginForServerDetailsInput) dom.requireLoginForServerDetailsInput.value = window.SITE_SETTINGS.require_login_for_server_details ? "1" : "0";
|
||||||
if (dom.icpFilingInput) dom.icpFilingInput.value = window.SITE_SETTINGS.icp_filing || '';
|
if (dom.icpFilingInput) dom.icpFilingInput.value = window.SITE_SETTINGS.icp_filing || '';
|
||||||
if (dom.psFilingInput) dom.psFilingInput.value = window.SITE_SETTINGS.ps_filing || '';
|
if (dom.psFilingInput) dom.psFilingInput.value = window.SITE_SETTINGS.ps_filing || '';
|
||||||
if (dom.logoUrlDarkInput) dom.logoUrlDarkInput.value = window.SITE_SETTINGS.logo_url_dark || '';
|
if (dom.logoUrlDarkInput) dom.logoUrlDarkInput.value = window.SITE_SETTINGS.logo_url_dark || '';
|
||||||
@@ -692,6 +698,11 @@
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function requiresLoginForServerDetails() {
|
||||||
|
if (!window.SITE_SETTINGS) return true;
|
||||||
|
return !!window.SITE_SETTINGS.require_login_for_server_details;
|
||||||
|
}
|
||||||
|
|
||||||
function renderLogoImage(url) {
|
function renderLogoImage(url) {
|
||||||
if (!dom.logoIconContainer) return;
|
if (!dom.logoIconContainer) return;
|
||||||
const safeUrl = sanitizeAssetUrl(url);
|
const safeUrl = sanitizeAssetUrl(url);
|
||||||
@@ -1895,6 +1906,7 @@
|
|||||||
if (dom.logoUrlDarkInput) dom.logoUrlDarkInput.value = settings.logo_url_dark || '';
|
if (dom.logoUrlDarkInput) dom.logoUrlDarkInput.value = settings.logo_url_dark || '';
|
||||||
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";
|
||||||
|
|
||||||
// Handle Theme Priority: localStorage > Site Default
|
// Handle Theme Priority: localStorage > Site Default
|
||||||
const savedTheme = localStorage.getItem('theme');
|
const savedTheme = localStorage.getItem('theme');
|
||||||
@@ -2016,6 +2028,7 @@
|
|||||||
logo_url_dark: dom.logoUrlDarkInput ? dom.logoUrlDarkInput.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() : '',
|
||||||
show_page_name: dom.showPageNameInput ? parseInt(dom.showPageNameInput.value) : 1,
|
show_page_name: dom.showPageNameInput ? parseInt(dom.showPageNameInput.value) : 1,
|
||||||
|
require_login_for_server_details: dom.requireLoginForServerDetailsInput ? (dom.requireLoginForServerDetailsInput.value === "1") : true,
|
||||||
default_theme: dom.defaultThemeInput ? dom.defaultThemeInput.value : 'dark',
|
default_theme: dom.defaultThemeInput ? dom.defaultThemeInput.value : 'dark',
|
||||||
show_95_bandwidth: dom.show95BandwidthInput ? (dom.show95BandwidthInput.value === "1") : false,
|
show_95_bandwidth: dom.show95BandwidthInput ? (dom.show95BandwidthInput.value === "1") : false,
|
||||||
p95_type: dom.p95TypeSelect ? dom.p95TypeSelect.value : 'tx',
|
p95_type: dom.p95TypeSelect ? dom.p95TypeSelect.value : 'tx',
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ async function checkAndFixDatabase() {
|
|||||||
await addColumn('show_page_name', "ALTER TABLE site_settings ADD COLUMN show_page_name TINYINT(1) DEFAULT 1 AFTER page_name");
|
await addColumn('show_page_name', "ALTER TABLE site_settings ADD COLUMN show_page_name TINYINT(1) DEFAULT 1 AFTER page_name");
|
||||||
await addColumn('show_95_bandwidth', "ALTER TABLE site_settings ADD COLUMN show_95_bandwidth TINYINT(1) DEFAULT 0 AFTER default_theme");
|
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('p95_type', "ALTER TABLE site_settings ADD COLUMN p95_type VARCHAR(20) DEFAULT 'tx' AFTER show_95_bandwidth");
|
||||||
|
await addColumn('require_login_for_server_details', "ALTER TABLE site_settings ADD COLUMN require_login_for_server_details TINYINT(1) DEFAULT 1 AFTER p95_type");
|
||||||
await addColumn('blackbox_source_id', "ALTER TABLE site_settings ADD COLUMN blackbox_source_id INT AFTER p95_type");
|
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_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_dest', "ALTER TABLE site_settings ADD COLUMN latency_dest VARCHAR(100) AFTER latency_source");
|
||||||
@@ -135,6 +136,7 @@ async function createTable(tableName) {
|
|||||||
default_theme VARCHAR(20) DEFAULT 'dark',
|
default_theme VARCHAR(20) DEFAULT 'dark',
|
||||||
show_95_bandwidth TINYINT(1) DEFAULT 0,
|
show_95_bandwidth TINYINT(1) DEFAULT 0,
|
||||||
p95_type VARCHAR(20) DEFAULT 'tx',
|
p95_type VARCHAR(20) DEFAULT 'tx',
|
||||||
|
require_login_for_server_details TINYINT(1) DEFAULT 1,
|
||||||
blackbox_source_id INT,
|
blackbox_source_id INT,
|
||||||
latency_source VARCHAR(100),
|
latency_source VARCHAR(100),
|
||||||
latency_dest VARCHAR(100),
|
latency_dest VARCHAR(100),
|
||||||
|
|||||||
@@ -140,11 +140,37 @@ function getPublicSiteSettings(settings = {}) {
|
|||||||
default_theme: settings.default_theme || 'dark',
|
default_theme: settings.default_theme || 'dark',
|
||||||
show_95_bandwidth: settings.show_95_bandwidth ? 1 : 0,
|
show_95_bandwidth: settings.show_95_bandwidth ? 1 : 0,
|
||||||
p95_type: settings.p95_type || 'tx',
|
p95_type: settings.p95_type || 'tx',
|
||||||
|
require_login_for_server_details: settings.require_login_for_server_details !== undefined
|
||||||
|
? (settings.require_login_for_server_details ? 1 : 0)
|
||||||
|
: 1,
|
||||||
icp_filing: settings.icp_filing || null,
|
icp_filing: settings.icp_filing || null,
|
||||||
ps_filing: settings.ps_filing || null
|
ps_filing: settings.ps_filing || null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getSiteSettingsRow() {
|
||||||
|
const [rows] = await db.query('SELECT * FROM site_settings WHERE id = 1');
|
||||||
|
return rows.length > 0 ? rows[0] : {};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function requireServerDetailsAccess(req, res, next) {
|
||||||
|
try {
|
||||||
|
const settings = await getSiteSettingsRow();
|
||||||
|
const requiresLogin = settings.require_login_for_server_details !== undefined
|
||||||
|
? !!settings.require_login_for_server_details
|
||||||
|
: true;
|
||||||
|
|
||||||
|
if (!requiresLogin) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
return requireAuth(req, res, next);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Server details access check failed:', err);
|
||||||
|
return res.status(500).json({ error: 'Failed to verify detail access' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getCookieOptions(req, maxAgeSeconds) {
|
function getCookieOptions(req, maxAgeSeconds) {
|
||||||
const options = ['Path=/', 'HttpOnly', 'SameSite=Strict'];
|
const options = ['Path=/', 'HttpOnly', 'SameSite=Strict'];
|
||||||
if (typeof maxAgeSeconds === 'number') {
|
if (typeof maxAgeSeconds === 'number') {
|
||||||
@@ -512,6 +538,7 @@ app.post('/api/setup/init', ensureSetupAccess, async (req, res) => {
|
|||||||
default_theme VARCHAR(20) DEFAULT 'dark',
|
default_theme VARCHAR(20) DEFAULT 'dark',
|
||||||
show_95_bandwidth TINYINT(1) DEFAULT 0,
|
show_95_bandwidth TINYINT(1) DEFAULT 0,
|
||||||
p95_type VARCHAR(20) DEFAULT 'tx',
|
p95_type VARCHAR(20) DEFAULT 'tx',
|
||||||
|
require_login_for_server_details TINYINT(1) DEFAULT 1,
|
||||||
blackbox_source_id INT,
|
blackbox_source_id INT,
|
||||||
latency_source VARCHAR(100),
|
latency_source VARCHAR(100),
|
||||||
latency_dest VARCHAR(100),
|
latency_dest VARCHAR(100),
|
||||||
@@ -530,6 +557,7 @@ app.post('/api/setup/init', ensureSetupAccess, async (req, res) => {
|
|||||||
await connection.query("ALTER TABLE prometheus_sources ADD COLUMN IF NOT EXISTS is_server_source TINYINT(1) DEFAULT 1 AFTER description");
|
await connection.query("ALTER TABLE prometheus_sources ADD COLUMN IF NOT EXISTS is_server_source TINYINT(1) DEFAULT 1 AFTER description");
|
||||||
await connection.query("ALTER TABLE prometheus_sources ADD COLUMN IF NOT EXISTS type VARCHAR(50) DEFAULT 'prometheus' AFTER is_server_source");
|
await connection.query("ALTER TABLE prometheus_sources ADD COLUMN IF NOT EXISTS type VARCHAR(50) DEFAULT 'prometheus' AFTER is_server_source");
|
||||||
await connection.query("ALTER TABLE site_settings ADD COLUMN IF NOT EXISTS show_page_name TINYINT(1) DEFAULT 1 AFTER page_name");
|
await connection.query("ALTER TABLE site_settings ADD COLUMN IF NOT EXISTS show_page_name TINYINT(1) DEFAULT 1 AFTER page_name");
|
||||||
|
await connection.query("ALTER TABLE site_settings ADD COLUMN IF NOT EXISTS require_login_for_server_details TINYINT(1) DEFAULT 1 AFTER p95_type");
|
||||||
await connection.query(`
|
await connection.query(`
|
||||||
CREATE TABLE IF NOT EXISTS latency_routes (
|
CREATE TABLE IF NOT EXISTS latency_routes (
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
@@ -880,7 +908,7 @@ app.post('/api/settings', requireAuth, async (req, res) => {
|
|||||||
// 2. Destructure fields from body
|
// 2. Destructure fields from body
|
||||||
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,
|
default_theme, show_95_bandwidth, p95_type, require_login_for_server_details,
|
||||||
icp_filing, ps_filing
|
icp_filing, ps_filing
|
||||||
} = req.body;
|
} = req.body;
|
||||||
|
|
||||||
@@ -895,6 +923,9 @@ app.post('/api/settings', requireAuth, async (req, res) => {
|
|||||||
default_theme: default_theme !== undefined ? default_theme : (current.default_theme || 'dark'),
|
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),
|
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'),
|
p95_type: p95_type !== undefined ? p95_type : (current.p95_type || 'tx'),
|
||||||
|
require_login_for_server_details: require_login_for_server_details !== undefined
|
||||||
|
? (require_login_for_server_details ? 1 : 0)
|
||||||
|
: (current.require_login_for_server_details !== undefined ? current.require_login_for_server_details : 1),
|
||||||
blackbox_source_id: current.blackbox_source_id || null, // UI doesn't send this
|
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_source: current.latency_source || null, // UI doesn't send this
|
||||||
latency_dest: current.latency_dest || null, // UI doesn't send this
|
latency_dest: current.latency_dest || null, // UI doesn't send this
|
||||||
@@ -907,10 +938,10 @@ app.post('/api/settings', requireAuth, async (req, res) => {
|
|||||||
await db.query(
|
await db.query(
|
||||||
`INSERT INTO site_settings (
|
`INSERT INTO site_settings (
|
||||||
id, page_name, show_page_name, title, logo_url, logo_url_dark, favicon_url,
|
id, page_name, show_page_name, title, logo_url, logo_url_dark, favicon_url,
|
||||||
default_theme, show_95_bandwidth, p95_type,
|
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
|
icp_filing, ps_filing
|
||||||
) 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),
|
||||||
@@ -921,6 +952,7 @@ app.post('/api/settings', requireAuth, async (req, res) => {
|
|||||||
default_theme = VALUES(default_theme),
|
default_theme = VALUES(default_theme),
|
||||||
show_95_bandwidth = VALUES(show_95_bandwidth),
|
show_95_bandwidth = VALUES(show_95_bandwidth),
|
||||||
p95_type = VALUES(p95_type),
|
p95_type = VALUES(p95_type),
|
||||||
|
require_login_for_server_details = VALUES(require_login_for_server_details),
|
||||||
blackbox_source_id = VALUES(blackbox_source_id),
|
blackbox_source_id = VALUES(blackbox_source_id),
|
||||||
latency_source = VALUES(latency_source),
|
latency_source = VALUES(latency_source),
|
||||||
latency_dest = VALUES(latency_dest),
|
latency_dest = VALUES(latency_dest),
|
||||||
@@ -929,7 +961,7 @@ app.post('/api/settings', requireAuth, async (req, res) => {
|
|||||||
ps_filing = VALUES(ps_filing)`,
|
ps_filing = VALUES(ps_filing)`,
|
||||||
[
|
[
|
||||||
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.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.icp_filing, settings.ps_filing
|
||||||
]
|
]
|
||||||
@@ -1153,7 +1185,7 @@ app.get('/api/metrics/cpu-history', async (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Get detailed metrics for a specific server
|
// Get detailed metrics for a specific server
|
||||||
app.get('/api/metrics/server-details', requireAuth, async (req, res) => {
|
app.get('/api/metrics/server-details', requireServerDetailsAccess, async (req, res) => {
|
||||||
const { instance, job, source } = req.query;
|
const { instance, job, source } = req.query;
|
||||||
|
|
||||||
if (!instance || !job || !source) {
|
if (!instance || !job || !source) {
|
||||||
@@ -1178,7 +1210,7 @@ app.get('/api/metrics/server-details', requireAuth, async (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Get historical metrics for a specific server
|
// Get historical metrics for a specific server
|
||||||
app.get('/api/metrics/server-history', requireAuth, async (req, res) => {
|
app.get('/api/metrics/server-history', requireServerDetailsAccess, async (req, res) => {
|
||||||
const { instance, job, source, metric, range, start, end } = req.query;
|
const { instance, job, source, metric, range, start, end } = req.query;
|
||||||
|
|
||||||
if (!instance || !job || !source || !metric) {
|
if (!instance || !job || !source || !metric) {
|
||||||
|
|||||||
Reference in New Issue
Block a user