添加95计费出入去大带宽
This commit is contained in:
@@ -536,6 +536,7 @@
|
|||||||
<option value="tx">仅统计上行 (TX)</option>
|
<option value="tx">仅统计上行 (TX)</option>
|
||||||
<option value="rx">仅统计下行 (RX)</option>
|
<option value="rx">仅统计下行 (RX)</option>
|
||||||
<option value="both">统计上行+下行 (Sum)</option>
|
<option value="both">统计上行+下行 (Sum)</option>
|
||||||
|
<option value="max">出入取大 (Max)</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group" style="margin-top: 15px;">
|
<div class="form-group" style="margin-top: 15px;">
|
||||||
|
|||||||
@@ -928,22 +928,7 @@
|
|||||||
}
|
}
|
||||||
lastMapDataHash = dataFingerprint;
|
lastMapDataHash = dataFingerprint;
|
||||||
|
|
||||||
// 1. Pre-build coord lookup for O(1) route lookup
|
// 1. Prepare geoData for scatter points
|
||||||
const serverCoords = new Map();
|
|
||||||
servers.forEach(s => {
|
|
||||||
if (s.lat && s.lng) {
|
|
||||||
const coords = [shiftLng(s.lng), s.lat];
|
|
||||||
const city = (s.city || '').toLowerCase().trim();
|
|
||||||
const country = (s.country || '').toLowerCase().trim();
|
|
||||||
const countryName = (s.countryName || '').toLowerCase().trim();
|
|
||||||
|
|
||||||
if (city) serverCoords.set(city, coords);
|
|
||||||
if (country) serverCoords.set(country, coords);
|
|
||||||
if (countryName) serverCoords.set(countryName, coords);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2. Prepare geoData for scatter points
|
|
||||||
const geoData = servers
|
const geoData = servers
|
||||||
.filter(s => s.lat && s.lng)
|
.filter(s => s.lat && s.lng)
|
||||||
.map(s => ({
|
.map(s => ({
|
||||||
@@ -978,61 +963,37 @@
|
|||||||
if (currentLatencies && currentLatencies.length > 0) {
|
if (currentLatencies && currentLatencies.length > 0) {
|
||||||
const countryCoords = {
|
const countryCoords = {
|
||||||
'china': [116.4074, 39.9042],
|
'china': [116.4074, 39.9042],
|
||||||
'中国': [116.4074, 39.9042],
|
|
||||||
'beijing': [116.4074, 39.9042],
|
'beijing': [116.4074, 39.9042],
|
||||||
'北京': [116.4074, 39.9042],
|
|
||||||
'shanghai': [121.4737, 31.2304],
|
'shanghai': [121.4737, 31.2304],
|
||||||
'上海': [121.4737, 31.2304],
|
|
||||||
'hong kong': [114.1694, 22.3193],
|
'hong kong': [114.1694, 22.3193],
|
||||||
'香港': [114.1694, 22.3193],
|
|
||||||
'taiwan': [120.9605, 23.6978],
|
'taiwan': [120.9605, 23.6978],
|
||||||
'台湾': [120.9605, 23.6978],
|
|
||||||
'united states': [-95.7129, 37.0902],
|
'united states': [-95.7129, 37.0902],
|
||||||
'美国': [-95.7129, 37.0902],
|
|
||||||
'us seattle': [-122.3321, 47.6062],
|
'us seattle': [-122.3321, 47.6062],
|
||||||
'seattle': [-122.3321, 47.6062],
|
'seattle': [-122.3321, 47.6062],
|
||||||
'西雅图': [-122.3321, 47.6062],
|
|
||||||
'us chicago': [-87.6298, 41.8781],
|
'us chicago': [-87.6298, 41.8781],
|
||||||
'chicago': [-87.6298, 41.8781],
|
'chicago': [-87.6298, 41.8781],
|
||||||
'芝加哥': [-87.6298, 41.8781],
|
|
||||||
'news york': [-74.0060, 40.7128],
|
'news york': [-74.0060, 40.7128],
|
||||||
'new york corp': [-74.0060, 40.7128],
|
'new york corp': [-74.0060, 40.7128],
|
||||||
'new york': [-74.0060, 40.7128],
|
'new york': [-74.0060, 40.7128],
|
||||||
'纽约': [-74.0060, 40.7128],
|
|
||||||
'san francisco': [-122.4194, 37.7749],
|
'san francisco': [-122.4194, 37.7749],
|
||||||
'旧金山': [-122.4194, 37.7749],
|
|
||||||
'los angeles': [-118.2437, 34.0522],
|
'los angeles': [-118.2437, 34.0522],
|
||||||
'洛杉矶': [-118.2437, 34.0522],
|
|
||||||
'japan': [138.2529, 36.2048],
|
'japan': [138.2529, 36.2048],
|
||||||
'日本': [138.2529, 36.2048],
|
|
||||||
'tokyo': [139.6917, 35.6895],
|
'tokyo': [139.6917, 35.6895],
|
||||||
'东京': [139.6917, 35.6895],
|
|
||||||
'singapore': [103.8198, 1.3521],
|
'singapore': [103.8198, 1.3521],
|
||||||
'新加坡': [103.8198, 1.3521],
|
|
||||||
'germany': [10.4515, 51.1657],
|
'germany': [10.4515, 51.1657],
|
||||||
'德国': [10.4515, 51.1657],
|
|
||||||
'frankfurt': [8.6821, 50.1109],
|
'frankfurt': [8.6821, 50.1109],
|
||||||
'法兰克福': [8.6821, 50.1109],
|
|
||||||
'united kingdom': [-3.436, 55.3781],
|
'united kingdom': [-3.436, 55.3781],
|
||||||
'英国': [-3.436, 55.3781],
|
|
||||||
'london': [-0.1276, 51.5074],
|
'london': [-0.1276, 51.5074],
|
||||||
'伦敦': [-0.1276, 51.5074],
|
|
||||||
'france': [2.2137, 46.2276],
|
'france': [2.2137, 46.2276],
|
||||||
'法国': [2.2137, 46.2276],
|
|
||||||
'paris': [2.3522, 48.8566],
|
'paris': [2.3522, 48.8566],
|
||||||
'巴黎': [2.3522, 48.8566],
|
|
||||||
'south korea': [127.7669, 35.9078],
|
'south korea': [127.7669, 35.9078],
|
||||||
'korea': [127.7669, 35.9078],
|
'korea': [127.7669, 35.9078],
|
||||||
'韩国': [127.7669, 35.9078],
|
'seoul': [126.9780, 37.5665]
|
||||||
'seoul': [126.9780, 37.5665],
|
|
||||||
'首尔': [126.9780, 37.5665]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getShiftedCoords = (name) => {
|
const getShiftedCoords = (name) => {
|
||||||
const lower = (name || '').toLowerCase().trim();
|
const lower = (name || '').toLowerCase().trim();
|
||||||
if (countryCoords[lower]) return [shiftLng(countryCoords[lower][0]), countryCoords[lower][1]];
|
if (countryCoords[lower]) return [shiftLng(countryCoords[lower][0]), countryCoords[lower][1]];
|
||||||
const sCoord = serverCoords.get(lower);
|
|
||||||
if (sCoord) return sCoord;
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1107,11 +1068,11 @@
|
|||||||
formatter: (params) => {
|
formatter: (params) => {
|
||||||
const r = params.data.meta;
|
const r = params.data.meta;
|
||||||
if (!r) return '';
|
if (!r) return '';
|
||||||
const latVal = (r.latency !== null && r.latency !== undefined) ? `${r.latency.toFixed(2)} ms` : '测量中...';
|
const latVal = (r.latency !== null && r.latency !== undefined) ? `${r.latency.toFixed(2)} ms` : 'Measuring...';
|
||||||
return `
|
return `
|
||||||
<div style="padding: 4px;">
|
<div style="padding: 4px;">
|
||||||
<div style="font-weight: 700;">${r.source} ↔ ${r.dest}</div>
|
<div style="font-weight: 700;">${r.source} ↔ ${r.dest}</div>
|
||||||
<div style="font-size: 0.75rem; color: var(--accent-indigo); margin-top: 4px;">延时: ${latVal}</div>
|
<div style="font-size: 0.75rem; color: var(--accent-indigo); margin-top: 4px;">Latency: ${latVal}</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -1551,6 +1512,8 @@
|
|||||||
{ key: 'networkTrend', label: '网络流量趋势 (24h)', value: '' }
|
{ key: 'networkTrend', label: '网络流量趋势 (24h)', value: '' }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const types = { tx: '上行', rx: '下行', both: '上行+下行', max: '出入取大' };
|
||||||
|
|
||||||
// Render normal metrics
|
// Render normal metrics
|
||||||
dom.detailMetricsList.innerHTML = metrics.map(m => `
|
dom.detailMetricsList.innerHTML = metrics.map(m => `
|
||||||
<div class="metric-item" id="metric-${m.key}">
|
<div class="metric-item" id="metric-${m.key}">
|
||||||
@@ -1597,7 +1560,7 @@
|
|||||||
<span class="traffic-value" id="stat-${m.key}-tx">0 B</span>
|
<span class="traffic-value" id="stat-${m.key}-tx">0 B</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="traffic-stat traffic-stat-p95">
|
<div class="traffic-stat traffic-stat-p95">
|
||||||
<span class="traffic-label">95计费 (上行)</span>
|
<span class="traffic-label" id="label-${m.key}-p95">95计费 (${types[window.SITE_SETTINGS?.p95_type || 'tx'] || '上行'})</span>
|
||||||
<span class="traffic-value" id="stat-${m.key}-p95">0 B/s</span>
|
<span class="traffic-value" id="stat-${m.key}-p95">0 B/s</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="traffic-stat traffic-stat-total">
|
<div class="traffic-stat traffic-stat-total">
|
||||||
@@ -1715,6 +1678,12 @@
|
|||||||
if (txEl) txEl.textContent = formatBytes(stats.txTotal);
|
if (txEl) txEl.textContent = formatBytes(stats.txTotal);
|
||||||
if (p95El) p95El.textContent = formatBandwidth(stats.p95);
|
if (p95El) p95El.textContent = formatBandwidth(stats.p95);
|
||||||
if (totalEl) totalEl.textContent = formatBytes(stats.total);
|
if (totalEl) totalEl.textContent = formatBytes(stats.total);
|
||||||
|
|
||||||
|
const p95Label = document.getElementById(`label-${metricKey}-p95`);
|
||||||
|
if (p95Label) {
|
||||||
|
const types = { tx: '上行', rx: '下行', both: '上行+下行', max: '出入取大' };
|
||||||
|
p95Label.textContent = `95计费 (${types[window.SITE_SETTINGS?.p95_type || 'tx'] || '上行'})`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1818,8 +1787,14 @@
|
|||||||
dom.legendP95.classList.toggle('disabled', !networkChart.showP95);
|
dom.legendP95.classList.toggle('disabled', !networkChart.showP95);
|
||||||
}
|
}
|
||||||
if (dom.p95LabelText) {
|
if (dom.p95LabelText) {
|
||||||
const types = { tx: '上行', rx: '下行', both: '上行+下行' };
|
const types = { tx: '上行', rx: '下行', both: '上行+下行', max: '出入取大' };
|
||||||
dom.p95LabelText.textContent = types[networkChart.p95Type] || '上行';
|
dom.p95LabelText.textContent = types[networkChart.p95Type] || '上行';
|
||||||
|
|
||||||
|
// Also update the static label in the chart footer
|
||||||
|
const trafficP95Label = document.querySelector('.chart-card-wide .traffic-stat-p95 .traffic-label');
|
||||||
|
if (trafficP95Label) {
|
||||||
|
trafficP95Label.textContent = `95计费 (${dom.p95LabelText.textContent})`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
networkChart.draw();
|
networkChart.draw();
|
||||||
}
|
}
|
||||||
@@ -1907,8 +1882,14 @@
|
|||||||
if (settings.p95_type !== undefined) {
|
if (settings.p95_type !== undefined) {
|
||||||
networkChart.p95Type = settings.p95_type;
|
networkChart.p95Type = settings.p95_type;
|
||||||
if (dom.p95LabelText) {
|
if (dom.p95LabelText) {
|
||||||
const types = { tx: '上行', rx: '下行', both: '上行+下行' };
|
const types = { tx: '上行', rx: '下行', both: '上行+下行', max: '出入取大' };
|
||||||
dom.p95LabelText.textContent = types[settings.p95_type] || '上行';
|
dom.p95LabelText.textContent = types[settings.p95_type] || '上行';
|
||||||
|
|
||||||
|
// Also update the static label in the chart footer
|
||||||
|
const trafficP95Label = document.querySelector('.chart-card-wide .traffic-stat-p95 .traffic-label');
|
||||||
|
if (trafficP95Label) {
|
||||||
|
trafficP95Label.textContent = `95计费 (${dom.p95LabelText.textContent})`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
networkChart.draw();
|
networkChart.draw();
|
||||||
|
|||||||
@@ -93,6 +93,8 @@ class AreaChart {
|
|||||||
combined = data.tx.map(t => t || 0);
|
combined = data.tx.map(t => t || 0);
|
||||||
} else if (this.p95Type === 'rx') {
|
} else if (this.p95Type === 'rx') {
|
||||||
combined = data.rx.map(r => r || 0);
|
combined = data.rx.map(r => r || 0);
|
||||||
|
} else if (this.p95Type === 'max') {
|
||||||
|
combined = data.tx.map((t, i) => Math.max(t || 0, data.rx[i] || 0));
|
||||||
} else {
|
} else {
|
||||||
combined = data.tx.map((t, i) => (t || 0) + (data.rx[i] || 0));
|
combined = data.tx.map((t, i) => (t || 0) + (data.rx[i] || 0));
|
||||||
}
|
}
|
||||||
|
|||||||
1961
server/index.js
1961
server/index.js
File diff suppressed because it is too large
Load Diff
@@ -626,7 +626,7 @@ async function getServerDetails(baseUrl, instance, job) {
|
|||||||
/**
|
/**
|
||||||
* Get historical metrics for a specific server (node)
|
* Get historical metrics for a specific server (node)
|
||||||
*/
|
*/
|
||||||
async function getServerHistory(baseUrl, instance, job, metric, range = '1h', start = null, end = null) {
|
async function getServerHistory(baseUrl, instance, job, metric, range = '1h', start = null, end = null, p95Type = 'tx') {
|
||||||
const url = normalizeUrl(baseUrl);
|
const url = normalizeUrl(baseUrl);
|
||||||
const node = resolveToken(instance);
|
const node = resolveToken(instance);
|
||||||
|
|
||||||
@@ -681,9 +681,22 @@ async function getServerHistory(baseUrl, instance, job, metric, range = '1h', st
|
|||||||
txTotal += (tx[i] || 0) * duration;
|
txTotal += (tx[i] || 0) * duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sortedTx = [...tx].sort((a, b) => a - b);
|
// Calculate P95 based on p95Type
|
||||||
const p95Idx = Math.floor(sortedTx.length * 0.95);
|
let combined = [];
|
||||||
const p95 = sortedTx.length > 0 ? sortedTx[p95Idx] : 0;
|
if (p95Type === 'rx') {
|
||||||
|
combined = [...rx];
|
||||||
|
} else if (p95Type === 'both') {
|
||||||
|
combined = tx.map((t, i) => (t || 0) + (rx[i] || 0));
|
||||||
|
} else if (p95Type === 'max') {
|
||||||
|
combined = tx.map((t, i) => Math.max(t || 0, rx[i] || 0));
|
||||||
|
} else {
|
||||||
|
// Default to tx
|
||||||
|
combined = [...tx];
|
||||||
|
}
|
||||||
|
|
||||||
|
const sorted = combined.sort((a, b) => a - b);
|
||||||
|
const p95Idx = Math.floor(sorted.length * 0.95);
|
||||||
|
const p95 = sorted.length > 0 ? sorted[p95Idx] : 0;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
timestamps,
|
timestamps,
|
||||||
|
|||||||
Reference in New Issue
Block a user