diff --git a/internal/handler/metrics.go b/internal/handler/metrics.go index 04d97c4..ce8c757 100644 --- a/internal/handler/metrics.go +++ b/internal/handler/metrics.go @@ -644,6 +644,9 @@ var metricsTemplate = ` }) .then(response => response.json()) .then(data => { + // 反转数据顺序,使时间从左到右 + data.reverse(); + const labels = data.map(m => { const date = new Date(m.timestamp); if (hours <= 24) { @@ -655,53 +658,70 @@ var metricsTemplate = ` } }); + // 更新图表配置,添加时间轴方向设置 + const chartOptions = { + scales: { + x: { + reverse: false // 确保时间轴从左到右 + } + } + }; + // 更新或创建图表 updateChart('requestsChart', currentCharts.requests, labels, data, '请求数', - m => m.total_requests, '#007bff'); + m => m.total_requests, '#007bff', chartOptions); updateChart('errorRateChart', currentCharts.errorRate, labels, data, '错误率 (%)', - m => m.error_rate * 100, '#dc3545'); + m => m.error_rate * 100, '#dc3545', chartOptions); updateChart('bytesChart', currentCharts.bytes, labels, data, '流量 (MB)', - m => m.total_bytes / (1024 * 1024), '#28a745'); + m => m.total_bytes / (1024 * 1024), '#28a745', chartOptions); }); } - function updateChart(canvasId, chartInstance, labels, data, label, valueGetter, color) { + function updateChart(canvasId, chartInstance, labels, data, label, valueGetter, color, options = {}) { const ctx = document.getElementById(canvasId).getContext('2d'); - + const chartData = { + labels: labels, + datasets: [{ + label: label, + data: data.map(valueGetter), + borderColor: color, + backgroundColor: color + '20', + fill: true, + tension: 0.4 + }] + }; + if (chartInstance) { - chartInstance.data.labels = labels; - chartInstance.data.datasets[0].data = data.map(valueGetter); + chartInstance.data = chartData; + chartInstance.options = { + ...chartInstance.options, + ...options, + animation: false + }; chartInstance.update(); } else { chartInstance = new Chart(ctx, { type: 'line', - data: { - labels: labels, - datasets: [{ - label: label, - data: data.map(valueGetter), - borderColor: color, - tension: 0.1, - fill: false - }] - }, + data: chartData, options: { + ...options, responsive: true, maintainAspectRatio: false, + plugins: { + legend: { + display: false + } + }, scales: { + y: { + beginAtZero: true + }, x: { - ticks: { - maxRotation: 45, - minRotation: 45 - } + reverse: false } } } }); - - if (canvasId === 'requestsChart') currentCharts.requests = chartInstance; - if (canvasId === 'errorRateChart') currentCharts.errorRate = chartInstance; - if (canvasId === 'bytesChart') currentCharts.bytes = chartInstance; } } diff --git a/internal/models/metrics.go b/internal/models/metrics.go index e56dff1..d18877a 100644 --- a/internal/models/metrics.go +++ b/internal/models/metrics.go @@ -279,5 +279,19 @@ func (db *MetricsDB) GetRecentMetrics(hours int) ([]HistoricalMetrics, error) { } metrics = append(metrics, m) } + + // 如果没有数据,返回一个空的记录而不是 null + if len(metrics) == 0 { + now := time.Now() + metrics = append(metrics, HistoricalMetrics{ + Timestamp: now.Format("2006-01-02 15:04:05"), + TotalRequests: 0, + TotalErrors: 0, + TotalBytes: 0, + ErrorRate: 0, + AvgLatency: 0, + }) + } + return metrics, rows.Err() }