diff --git a/apps/dao/dashboard.go b/apps/dao/dashboard.go index 114d29c..15380ab 100644 --- a/apps/dao/dashboard.go +++ b/apps/dao/dashboard.go @@ -83,8 +83,8 @@ func DashboardTrafficSummary() (vo.DashboardTrafficVo, error) { result.SinceResetDownloadBytes = r.Download result.SinceResetUploadBytes = r.Upload - now := time.Now().UnixMilli() - dayStart := now - (now % int64(24*time.Hour/time.Millisecond)) + nowTime := time.Now() + dayStart := time.Date(nowTime.Year(), nowTime.Month(), nowTime.Day(), 0, 0, 0, 0, nowTime.Location()).UnixMilli() var today row if tx := sqliteDB.Raw(`SELECT COALESCE(SUM(rx_bytes),0) AS download, @@ -135,9 +135,6 @@ func DashboardTrafficTimeseries(fromMs int64, toMs int64, bucketMs int64, source case "hourly": sourceTable = "traffic_aggregate_hourly" fromColumn = "hour_start" - case "daily": - sourceTable = "traffic_aggregate_daily" - fromColumn = "day_start" default: sourceTable = "traffic_sample" fromColumn = "sampled_at" @@ -171,18 +168,26 @@ func DashboardTrafficTimeseries(fromMs int64, toMs int64, bucketMs int64, source return filled, nil } -func DashboardSystemTimeseries(fromMs int64, toMs int64) ([]vo.DashboardSeriesPointVo, error) { +func DashboardSystemTimeseries(fromMs int64, toMs int64, bucketMs int64) ([]vo.DashboardSeriesPointVo, error) { rows := make([]vo.DashboardSeriesPointVo, 0) if !tableExists("metric_sample") { return rows, nil } + if toMs < fromMs { + return rows, nil + } + if bucketMs <= 0 { + bucketMs = int64(time.Minute / time.Millisecond) + } + alignedFrom := fromMs - (fromMs % bucketMs) if tx := sqliteDB.Raw(`SELECT - sampled_at AS ts, - cpu_percent AS cpu, - mem_percent AS mem + (? + CAST((sampled_at - ?) / ? AS INTEGER) * ?) AS ts, + AVG(cpu_percent) AS cpu, + AVG(mem_percent) AS mem FROM metric_sample WHERE sampled_at BETWEEN ? AND ? - ORDER BY sampled_at ASC`, fromMs, toMs).Scan(&rows); tx.Error != nil { + GROUP BY ts + ORDER BY ts ASC`, alignedFrom, alignedFrom, bucketMs, bucketMs, fromMs, toMs).Scan(&rows); tx.Error != nil { logrus.Errorf("%v", tx.Error) return rows, errors.New(constant.SysError) } diff --git a/apps/frontend/src/lang/package/en.ts b/apps/frontend/src/lang/package/en.ts index 2ba0fa9..96d0d45 100644 --- a/apps/frontend/src/lang/package/en.ts +++ b/apps/frontend/src/lang/package/en.ts @@ -27,6 +27,7 @@ export default { dashboard: { stale: "Dashboard data is stale. Retrying automatically...", topPeers24h: "Top peers (24h)", + topPeersRange: "Top peers ({range})", refreshFailed: "Failed to refresh dashboard data", cpu: "CPU", ram: "RAM", diff --git a/apps/frontend/src/lang/package/ru.ts b/apps/frontend/src/lang/package/ru.ts index 22abf77..9564735 100644 --- a/apps/frontend/src/lang/package/ru.ts +++ b/apps/frontend/src/lang/package/ru.ts @@ -25,6 +25,7 @@ export default { dashboard: { stale: "Данные дашборда устарели. Выполняется автоматическая повторная попытка...", topPeers24h: "Топ пиров (24ч)", + topPeersRange: "Топ пиров ({range})", refreshFailed: "Не удалось обновить данные дашборда", cpu: "CPU", ram: "RAM", diff --git a/apps/frontend/src/views/dashboard/index.vue b/apps/frontend/src/views/dashboard/index.vue index 0f15098..85e97ea 100644 --- a/apps/frontend/src/views/dashboard/index.vue +++ b/apps/frontend/src/views/dashboard/index.vue @@ -52,7 +52,7 @@
@@ -62,7 +62,7 @@ - + @@ -96,7 +96,6 @@ import VChart from "vue-echarts"; import { dashboardSecurityApi, dashboardSummaryApi, dashboardTimeseriesApi, dashboardTopPeersApi } from "@/api/dashboard"; import { DashboardSummaryVo, DashboardTimeseriesVo, DashboardTopPeerVo, SecurityRiskVo } from "@/api/dashboard/types"; import { formatBytes } from "@/utils/byte"; -import { timestampToDateTime } from "@/utils/time"; use([CanvasRenderer, LineChart, GridComponent, TooltipComponent, LegendComponent, DataZoomComponent, TitleComponent]); @@ -164,14 +163,6 @@ const loadDashboard = async () => { } }; -const systemXAxisLabels = computed(() => { - const allTs = new Set(); - for (const item of timeseries.value.system || []) { - allTs.add(item.ts); - } - return Array.from(allTs).sort((a, b) => a - b); -}); - const trafficDownloadData = computed(() => (timeseries.value.traffic || []).map((item) => [item.ts, item.download || 0]) ); @@ -180,15 +171,19 @@ const trafficUploadData = computed(() => (timeseries.value.traffic || []).map((item) => [item.ts, item.upload || 0]) ); +const hasTrafficData = computed(() => + (timeseries.value.traffic || []).some((item) => (item.download || 0) > 0 || (item.upload || 0) > 0) +); + const hasSingleTrafficPoint = computed(() => (timeseries.value.traffic || []).length === 1); -const systemMap = computed(() => { - const m = new Map(); - for (const item of timeseries.value.system || []) { - m.set(item.ts, { cpu: item.cpu || 0, mem: item.mem || 0 }); - } - return m; -}); +const systemCpuData = computed(() => + (timeseries.value.system || []).map((item) => [item.ts, item.cpu || 0]) +); + +const systemMemData = computed(() => + (timeseries.value.system || []).map((item) => [item.ts, item.mem || 0]) +); const trafficChartOption = computed(() => ({ title: { text: t("dashboard.trafficSeriesChart"), left: "left", textStyle: { fontSize: 14, fontWeight: 600 } }, @@ -237,9 +232,8 @@ const systemChartOption = computed(() => ({ grid: { left: 30, right: 20, top: 50, bottom: 50, containLabel: true }, dataZoom: [{ type: "inside" }, { type: "slider", height: 16, bottom: 10 }], xAxis: { - type: "category", + type: "time", boundaryGap: false, - data: systemXAxisLabels.value.map((ts) => timestampToDateTime(ts)), }, yAxis: { type: "value", @@ -253,14 +247,14 @@ const systemChartOption = computed(() => ({ type: "line", smooth: true, showSymbol: false, - data: systemXAxisLabels.value.map((ts) => systemMap.value.get(ts)?.cpu || 0), + data: systemCpuData.value, }, { name: t("dashboard.ram"), type: "line", smooth: true, showSymbol: false, - data: systemXAxisLabels.value.map((ts) => systemMap.value.get(ts)?.mem || 0), + data: systemMemData.value, }, ], })); diff --git a/apps/middleware/cron.go b/apps/middleware/cron.go index 71dfc80..7c8a8ec 100644 --- a/apps/middleware/cron.go +++ b/apps/middleware/cron.go @@ -38,6 +38,7 @@ func InitCron() error { logrus.Errorf("cron add func CronResetTraffic err: %v", err) } } + go service.CleanupStatsRetention() c.Start() return nil } diff --git a/apps/service/dashboard.go b/apps/service/dashboard.go index 2b52e7b..e61682f 100644 --- a/apps/service/dashboard.go +++ b/apps/service/dashboard.go @@ -75,7 +75,7 @@ func DashboardTimeseries(rangeKey string) (vo.DashboardTimeseriesVo, error) { if err != nil { return vo.DashboardTimeseriesVo{}, err } - systemRows, err := dao.DashboardSystemTimeseries(fromMs, nowMs) + systemRows, err := dao.DashboardSystemTimeseries(fromMs, nowMs, bucketMs) if err != nil { return vo.DashboardTimeseriesVo{}, err }