네트워크 품질 표 가독성 보강
This commit is contained in:
+43
-2
@@ -236,6 +236,9 @@
|
||||
logFilterConnection: 'Connection',
|
||||
logFilterSystem: 'System',
|
||||
logFilterNoLines: 'No log lines match this filter.',
|
||||
qualityOk: 'OK',
|
||||
qualityWarn: 'Increasing',
|
||||
qualityBad: 'Attention',
|
||||
remoteSaved: 'Saved',
|
||||
remotePending: 'Pending',
|
||||
serviceLogs: 'Logs',
|
||||
@@ -467,6 +470,9 @@
|
||||
logFilterConnection: '연결',
|
||||
logFilterSystem: '시스템',
|
||||
logFilterNoLines: '필터에 맞는 로그가 없습니다.',
|
||||
qualityOk: '정상',
|
||||
qualityWarn: '증가',
|
||||
qualityBad: '주의',
|
||||
remoteSaved: '저장',
|
||||
remotePending: '대기',
|
||||
serviceLogs: '로그',
|
||||
@@ -2571,6 +2577,36 @@
|
||||
return Math.max(0, Math.round(numeric)).toLocaleString();
|
||||
}
|
||||
|
||||
function recentNetworkQuality(rows, direction, windowSeconds = 600) {
|
||||
const now = Date.now() / 1000;
|
||||
const cutoff = now - windowSeconds;
|
||||
let previousAt = null;
|
||||
let errors = 0;
|
||||
let drops = 0;
|
||||
|
||||
rows.forEach(row => {
|
||||
const recordedAt = Date.parse(String(row.time || '').replace(' ', 'T')) / 1000;
|
||||
if (!Number.isFinite(recordedAt) || recordedAt < cutoff) return;
|
||||
|
||||
const seconds = previousAt === null ? 1 : Math.max(1, Math.min(60, recordedAt - previousAt));
|
||||
previousAt = recordedAt;
|
||||
const errorRate = Number(row[direction === 'rx' ? 'rx_errors_per_sec' : 'tx_errors_per_sec'] || 0);
|
||||
const dropRate = Number(row[direction === 'rx' ? 'rx_dropped_per_sec' : 'tx_dropped_per_sec'] || 0);
|
||||
errors += Math.max(0, Number.isFinite(errorRate) ? errorRate : 0) * seconds;
|
||||
drops += Math.max(0, Number.isFinite(dropRate) ? dropRate : 0) * seconds;
|
||||
});
|
||||
|
||||
const errorCount = Math.round(errors);
|
||||
const dropCount = Math.round(drops);
|
||||
const stateName = errorCount > 0 || dropCount >= 10 ? 'bad' : (dropCount > 0 ? 'warn' : 'ok');
|
||||
return {
|
||||
errors: errorCount,
|
||||
drops: dropCount,
|
||||
state: stateName,
|
||||
label: t(stateName === 'bad' ? 'qualityBad' : (stateName === 'warn' ? 'qualityWarn' : 'qualityOk')),
|
||||
};
|
||||
}
|
||||
|
||||
function networkQualitySummary(elementId, totals, direction, rows = []) {
|
||||
const el = $('#' + elementId);
|
||||
if (!el) return;
|
||||
@@ -2583,17 +2619,22 @@
|
||||
const currentTitle = direction === 'rx' ? t('downloadRxPackets') : t('uploadTxPackets');
|
||||
const totalRow = totals || {};
|
||||
const currentRow = rows.length ? rows[rows.length - 1] : {};
|
||||
const recent = recentNetworkQuality(rows, direction);
|
||||
|
||||
el.closest('.quality-summary')?.setAttribute('data-quality-state', recent.state);
|
||||
|
||||
el.innerHTML = `
|
||||
<table class="quality-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">${escapeHtml(currentTitle)}</th>
|
||||
<td><strong>${escapeHtml(formatChartNumber(currentRow[speedKey], ' MB/s'))}</strong> / <strong>${escapeHtml(formatChartNumber(currentRow[packetKey], ' pps'))}</strong></td>
|
||||
<td class="quality-value"><strong>${escapeHtml(formatChartNumber(currentRow[speedKey], ' MB/s'))}</strong></td>
|
||||
<td class="quality-value"><strong>${escapeHtml(formatChartNumber(currentRow[packetKey], ' pps'))}</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">${escapeHtml(qualityTitle)}</th>
|
||||
<td><strong>${escapeHtml(formatCount(totalRow[errorKey]))}</strong> ${escapeHtml(t('errorsLine'))} / <strong>${escapeHtml(formatCount(totalRow[dropKey]))}</strong> ${escapeHtml(t('dropsLine'))}</td>
|
||||
<td class="quality-value"><strong>${escapeHtml(formatCount(totalRow[errorKey]))}</strong> ${escapeHtml(t('errorsLine'))}</td>
|
||||
<td class="quality-value"><strong>${escapeHtml(formatCount(totalRow[dropKey]))}</strong> ${escapeHtml(t('dropsLine'))} <span class="quality-badge ${escapeHtml(recent.state)}">${escapeHtml(recent.label)}</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Reference in New Issue
Block a user