修复项目逻辑错误
新增数据库检查
This commit is contained in:
@@ -587,7 +587,7 @@
|
||||
<p style="font-size: 0.72rem; color: var(--text-muted); margin-top: 6px;">开启后,未登录访客仍可看到大屏总览,但点击单台服务器时需要先登录。</p>
|
||||
</div>
|
||||
<div class="form-group" style="margin-top: 15px;">
|
||||
<label for="showServerIpInput">服务器详情内是否显示 IPv4 和 IPv6 地址</label>
|
||||
<label for="showServerIpInput">是否在服务器详情中显示公网 IP</label>
|
||||
<select id="showServerIpInput"
|
||||
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">显示 (Show)</option>
|
||||
@@ -595,23 +595,14 @@
|
||||
</select>
|
||||
<p style="font-size: 0.72rem; color: var(--text-muted); margin-top: 6px;">开启后,点击服务器详情时会显示该服务器的公网 IP 地址。</p>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 25px; padding-top: 15px; border-top: 1px dashed var(--border-color);">
|
||||
<h4 style="margin-bottom: 12px; color: var(--text-secondary); font-size: 0.95rem;">高级指标配置 (可选)</h4>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="ipMetricNameInput">IP 发现指标 (Metric Name)</label>
|
||||
<input type="text" id="ipMetricNameInput" placeholder="例如: node_network_address_info"
|
||||
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%;">
|
||||
<p style="font-size: 0.72rem; color: var(--text-muted); margin-top: 6px;">留空则使用 Prometheus Target 自动发现。若需兼容 <code>node_exporter</code> 自定义指标(如 textfile),请在此输入指标名。</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-top: 12px;">
|
||||
<label for="ipLabelNameInput">IP 提取标签 (Label Name)</label>
|
||||
<input type="text" id="ipLabelNameInput" placeholder="address"
|
||||
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%;">
|
||||
<p style="font-size: 0.72rem; color: var(--text-muted); margin-top: 6px;">从该指标的哪个标签提取 IP?默认为 <code>address</code>。</p>
|
||||
</div>
|
||||
<div class="form-group" style="margin-top: 15px;">
|
||||
<label for="ipMetricNameInput">自定义 IP 采集指标 (可选)</label>
|
||||
<input type="text" id="ipMetricNameInput" placeholder="例:node_network_address_info">
|
||||
<p style="font-size: 0.72rem; color: var(--text-muted); margin-top: 6px;">如果您的 Prometheus 中有专门记录 IP 的指标,请在此输入。留空则尝试自动发现。</p>
|
||||
</div>
|
||||
<div class="form-group" style="margin-top: 15px;">
|
||||
<label for="ipLabelNameInput">IP 指标中的 Label 名称</label>
|
||||
<input type="text" id="ipLabelNameInput" placeholder="默认:address">
|
||||
</div>
|
||||
<div class="form-actions" style="margin-top: 25px; display: flex; justify-content: flex-end;">
|
||||
<button class="btn btn-add" id="btnSaveSecuritySettings">保存安全设置</button>
|
||||
@@ -620,6 +611,26 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Custom Detail Metrics Tab -->
|
||||
<div class="tab-content" id="tab-details-metrics">
|
||||
<div class="metrics-settings-form">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
|
||||
<h3 style="margin: 0;">服务器详情指标配置</h3>
|
||||
<button class="btn btn-add" id="btnAddCustomMetric" style="padding: 6px 12px; font-size: 0.8rem;">
|
||||
<i class="fas fa-plus"></i> 添加指标
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="customMetricsList" class="custom-metrics-list" style="max-height: 400px; overflow-y: auto; padding-right: 5px;">
|
||||
<!-- Dynamic rows will be added here -->
|
||||
</div>
|
||||
|
||||
<div class="form-actions" style="margin-top: 25px; display: flex; justify-content: flex-end;">
|
||||
<button class="btn btn-add" id="btnSaveCustomMetrics">保存指标配置</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Latency Routes Tab -->
|
||||
<div class="tab-content" id="tab-latency">
|
||||
<div class="latency-settings-form">
|
||||
|
||||
106
public/js/app.js
106
public/js/app.js
@@ -121,9 +121,13 @@
|
||||
icpFilingInput: document.getElementById('icpFilingInput'),
|
||||
psFilingInput: document.getElementById('psFilingInput'),
|
||||
icpFilingDisplay: document.getElementById('icpFilingDisplay'),
|
||||
psFilingDisplay: document.getElementById('psFilingDisplay'),
|
||||
psFilingText: document.getElementById('psFilingText'),
|
||||
copyrightYear: document.getElementById('copyrightYear')
|
||||
ps_filingDisplay: document.getElementById('psFilingDisplay'),
|
||||
ps_filingText: document.getElementById('psFilingText'),
|
||||
copyrightYear: document.getElementById('copyrightYear'),
|
||||
customMetricsList: document.getElementById('customMetricsList'),
|
||||
btnAddCustomMetric: document.getElementById('btnAddCustomMetric'),
|
||||
btnSaveCustomMetrics: document.getElementById('btnSaveCustomMetrics'),
|
||||
customDataContainer: document.getElementById('customDataContainer')
|
||||
};
|
||||
|
||||
// ---- State ----
|
||||
@@ -193,6 +197,71 @@
|
||||
// Network chart
|
||||
networkChart = new AreaChart(dom.networkCanvas);
|
||||
|
||||
// ---- Custom Metrics Helpers ----
|
||||
|
||||
function addMetricRow(config = {}) {
|
||||
const row = document.createElement('div');
|
||||
row.className = 'metric-row';
|
||||
row.style = 'background: rgba(255,255,255,0.03); padding: 12px; border-radius: 8px; margin-bottom: 10px; border: 1px solid var(--border-color);';
|
||||
row.innerHTML = `
|
||||
<div style="display: grid; grid-template-columns: 1fr 1.5fr 1fr; gap: 10px; margin-bottom: 8px;">
|
||||
<input type="text" placeholder="显示名 (如:内核)" class="metric-display-name" value="${config.name || ''}" style="padding: 6px; background: var(--bg-input); border: 1px solid var(--border-color); border-radius: 4px; color: var(--text-primary); font-size: 0.85rem;">
|
||||
<input type="text" placeholder="指标名 (PromQL)" class="metric-query" value="${config.metric || ''}" style="padding: 6px; background: var(--bg-input); border: 1px solid var(--border-color); border-radius: 4px; color: var(--text-primary); font-size: 0.85rem;">
|
||||
<input type="text" placeholder="取值标签" class="metric-label" value="${config.label || ''}" style="padding: 6px; background: var(--bg-input); border: 1px solid var(--border-color); border-radius: 4px; color: var(--text-primary); font-size: 0.85rem;">
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<label style="font-size: 0.75rem; color: var(--text-muted); display: flex; align-items: center; cursor: pointer;">
|
||||
<input type="checkbox" class="metric-is-ip" ${config.is_ip ? 'checked' : ''} style="margin-right: 5px;"> 设为 IP 发现源
|
||||
</label>
|
||||
<button class="btn-remove-metric" style="background: none; border: none; color: #ff4d4f; cursor: pointer; font-size: 0.75rem;">
|
||||
<i class="fas fa-trash"></i> 删除
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
row.querySelector('.btn-remove-metric').onclick = () => row.remove();
|
||||
dom.customMetricsList.appendChild(row);
|
||||
}
|
||||
|
||||
function loadCustomMetricsUI(metrics) {
|
||||
if (!dom.customMetricsList) return;
|
||||
dom.customMetricsList.innerHTML = '';
|
||||
let list = [];
|
||||
try {
|
||||
list = typeof metrics === 'string' ? JSON.parse(metrics) : (metrics || []);
|
||||
} catch(e) {}
|
||||
|
||||
if (Array.isArray(list)) {
|
||||
list.forEach(m => addMetricRow(m));
|
||||
}
|
||||
|
||||
if (list.length === 0) {
|
||||
// Add a placeholder/default row if empty
|
||||
}
|
||||
}
|
||||
|
||||
function getCustomMetricsFromUI() {
|
||||
const rows = dom.customMetricsList.querySelectorAll('.metric-row');
|
||||
const metrics = [];
|
||||
rows.forEach(row => {
|
||||
const name = row.querySelector('.metric-display-name').value.trim();
|
||||
const metric = row.querySelector('.metric-query').value.trim();
|
||||
const label = row.querySelector('.metric-label').value.trim();
|
||||
const is_ip = row.querySelector('.metric-is-ip').checked;
|
||||
if (metric) {
|
||||
metrics.push({ name, metric, label, is_ip });
|
||||
}
|
||||
});
|
||||
return metrics;
|
||||
}
|
||||
|
||||
// Bind Events
|
||||
if (dom.btnAddCustomMetric) dom.btnAddCustomMetric.onclick = () => addMetricRow();
|
||||
if (dom.btnSaveCustomMetrics) {
|
||||
dom.btnSaveCustomMetrics.onclick = saveSiteSettings;
|
||||
}
|
||||
})();
|
||||
|
||||
// Initial map
|
||||
initMap2D();
|
||||
|
||||
@@ -547,6 +616,9 @@
|
||||
|
||||
// Apply security dependency
|
||||
updateSecurityDependency();
|
||||
|
||||
// Load custom metrics
|
||||
loadCustomMetricsUI(window.SITE_SETTINGS.custom_metrics);
|
||||
}
|
||||
|
||||
loadSiteSettings();
|
||||
@@ -1715,7 +1787,25 @@
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
// Handle partitions integration: Move the expandable partition section UNDER the Disk Usage metric
|
||||
// Render Custom Data
|
||||
const customDataContainer = dom.customDataContainer;
|
||||
if (customDataContainer) {
|
||||
customDataContainer.innerHTML = '';
|
||||
if (data.custom_data && data.custom_data.length > 0) {
|
||||
data.custom_data.forEach(item => {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'detail-metric-card';
|
||||
card.style.flex = '1 1 calc(50% - 10px)';
|
||||
card.innerHTML = `
|
||||
<span class="detail-metric-label">${item.name}</span>
|
||||
<span class="detail-metric-value">${item.value || '-'}</span>
|
||||
`;
|
||||
customDataContainer.appendChild(card);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Partitions
|
||||
if (data.partitions && data.partitions.length > 0) {
|
||||
dom.detailPartitionsContainer.style.display = 'block';
|
||||
dom.partitionSummary.textContent = `${data.partitions.length} 个本地分区`;
|
||||
@@ -1997,8 +2087,11 @@
|
||||
// Update IP visibility input
|
||||
if (dom.showServerIpInput) dom.showServerIpInput.value = settings.show_server_ip ? "1" : "0";
|
||||
if (dom.ipMetricNameInput) dom.ipMetricNameInput.value = settings.ip_metric_name || '';
|
||||
if (dom.ipLabelNameInput) dom.ipLabelNameInput.value = settings.ip_label_name || 'address';
|
||||
if (dom.ipLabelNameInput) dom.ipLabelNameInput.value = settings.ip_label_name || '';
|
||||
|
||||
// Load Custom Metrics
|
||||
loadCustomMetricsUI(settings.custom_metrics);
|
||||
|
||||
// Sync security tab dependency
|
||||
updateSecurityDependency();
|
||||
} catch (err) {
|
||||
@@ -2118,7 +2211,8 @@
|
||||
network_data_sources: Array.from(dom.networkSourceSelector.querySelectorAll('input[type="checkbox"]:checked')).map(cb => cb.value).join(','),
|
||||
show_server_ip: dom.showServerIpInput ? (dom.showServerIpInput.value === "1") : false,
|
||||
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()
|
||||
};
|
||||
|
||||
// UI Feedback for both potential save buttons
|
||||
|
||||
Reference in New Issue
Block a user