네트워크 품질 표 가독성 보강

This commit is contained in:
seo
2026-07-26 02:12:32 +09:00
parent d90bf4db8a
commit e489f50fe4
2 changed files with 44 additions and 3 deletions
+43 -2
View File
@@ -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>