diff --git a/Wavelet/frontend/app/(main)/nodes/components/disk-io-trend-chart.tsx b/Wavelet/frontend/app/(main)/nodes/components/disk-io-trend-chart.tsx
index 285a4aa1..d417eda0 100644
--- a/Wavelet/frontend/app/(main)/nodes/components/disk-io-trend-chart.tsx
+++ b/Wavelet/frontend/app/(main)/nodes/components/disk-io-trend-chart.tsx
@@ -1,31 +1,16 @@
'use client';
-import {Area, AreaChart, CartesianGrid, Line, XAxis, YAxis} from 'recharts';
-
-import {Card, CardContent, CardDescription, CardHeader, CardTitle} from '@/components/ui/card';
+import {TrendChart} from '@/components/data/trend-chart';
import {
- ChartConfig,
- ChartContainer,
- ChartLegend,
- ChartLegendContent,
- ChartTooltip,
- ChartTooltipContent,
-} from '@/components/ui/chart';
+ Card,
+ CardContent,
+ CardDescription,
+ CardHeader,
+ CardTitle,
+} from '@/components/ui/card';
import type {DiskIOTrendPoint} from '@/lib/services/openflare';
-import {formatTrendHour} from '../../components/dashboard/dashboard-utils';
-import {formatBytes} from './node-utils';
-
-const chartConfig = {
- diskRead: {
- label: '磁盘读',
- color: 'hsl(var(--chart-3))',
- },
- diskWrite: {
- label: '磁盘写',
- color: 'hsl(var(--chart-5))',
- },
-} satisfies ChartConfig;
+import {formatBytes, formatTrendHour} from '../../components/dashboard/dashboard-utils';
export function DiskIOTrendChart({
points,
@@ -36,91 +21,33 @@ export function DiskIOTrendChart({
title?: string;
description?: string;
}) {
- const data = points.map((point) => ({
- hour: formatTrendHour(point.bucket_started_at),
- diskRead: point.disk_read_bytes,
- diskWrite: point.disk_write_bytes,
- }));
-
- if (data.length === 0) {
- return (
-
-
- {title}
- {description}
-
-
-
- 暂无趋势数据
-
-
-
- );
- }
-
return (
{title}
{description}
-
-
-
-
-
-
-
-
-
-
-
-
- formatBytes(Number(value))}
- />
- (
-
- {formatBytes(Number(value))}
-
- {name === 'diskRead' ? '读' : '写'}
-
-
- )}
- />
- }
- />
-
-
- } />
-
-
-
+
+ formatTrendHour(point.bucket_started_at))}
+ yAxisValueFormatter={formatBytes}
+ series={[
+ {
+ label: '磁盘读',
+ color: '#a78bfa',
+ fillColor: 'rgba(167, 139, 250, 0.14)',
+ variant: 'area',
+ values: points.map((point) => point.disk_read_bytes),
+ valueFormatter: formatBytes,
+ },
+ {
+ label: '磁盘写',
+ color: '#fb7185',
+ values: points.map((point) => point.disk_write_bytes),
+ valueFormatter: formatBytes,
+ },
+ ]}
+ />
);
diff --git a/Wavelet/frontend/app/(main)/nodes/components/network-trend-chart.tsx b/Wavelet/frontend/app/(main)/nodes/components/network-trend-chart.tsx
index ac7b23b9..8a768ebc 100644
--- a/Wavelet/frontend/app/(main)/nodes/components/network-trend-chart.tsx
+++ b/Wavelet/frontend/app/(main)/nodes/components/network-trend-chart.tsx
@@ -1,31 +1,19 @@
'use client';
-import {Area, AreaChart, CartesianGrid, Line, XAxis, YAxis} from 'recharts';
-
-import {Card, CardContent, CardDescription, CardHeader, CardTitle} from '@/components/ui/card';
+import {TrendChart} from '@/components/data/trend-chart';
import {
- ChartConfig,
- ChartContainer,
- ChartLegend,
- ChartLegendContent,
- ChartTooltip,
- ChartTooltipContent,
-} from '@/components/ui/chart';
+ Card,
+ CardContent,
+ CardDescription,
+ CardHeader,
+ CardTitle,
+} from '@/components/ui/card';
import type {NetworkTrendPoint} from '@/lib/services/openflare';
-import {formatTrendHour} from '../../components/dashboard/dashboard-utils';
-import {formatBytesPerSecond} from './node-utils';
-
-const chartConfig = {
- openrestyRx: {
- label: 'OpenResty 入站',
- color: 'hsl(var(--chart-2))',
- },
- openrestyTx: {
- label: 'OpenResty 出站',
- color: 'hsl(var(--chart-4))',
- },
-} satisfies ChartConfig;
+import {
+ formatBytesPerSecond,
+ formatTrendHour,
+} from '../../components/dashboard/dashboard-utils';
export function NetworkTrendChart({
points,
@@ -36,91 +24,33 @@ export function NetworkTrendChart({
title?: string;
description?: string;
}) {
- const data = points.map((point) => ({
- hour: formatTrendHour(point.bucket_started_at),
- openrestyRx: point.openresty_rx_bytes,
- openrestyTx: point.openresty_tx_bytes,
- }));
-
- if (data.length === 0) {
- return (
-
-
- {title}
- {description}
-
-
-
- 暂无趋势数据
-
-
-
- );
- }
-
return (
{title}
{description}
-
-
-
-
-
-
-
-
-
-
-
-
- formatBytesPerSecond(Number(value), 3600)}
- />
- (
-
- {formatBytesPerSecond(Number(value), 3600)}
-
- {name === 'openrestyRx' ? '入站' : '出站'}
-
-
- )}
- />
- }
- />
-
-
- } />
-
-
-
+
+ formatTrendHour(point.bucket_started_at))}
+ yAxisValueFormatter={(value) => formatBytesPerSecond(value, 3600)}
+ series={[
+ {
+ label: 'OpenResty 入站',
+ color: '#22c55e',
+ fillColor: 'rgba(34, 197, 94, 0.14)',
+ variant: 'area',
+ values: points.map((point) => point.openresty_rx_bytes),
+ valueFormatter: (value) => formatBytesPerSecond(value, 3600),
+ },
+ {
+ label: 'OpenResty 出站',
+ color: '#38bdf8',
+ values: points.map((point) => point.openresty_tx_bytes),
+ valueFormatter: (value) => formatBytesPerSecond(value, 3600),
+ },
+ ]}
+ />
);
diff --git a/docs/changelog/index.md b/docs/changelog/index.md
index bb8d6427..e6a59ca6 100644
--- a/docs/changelog/index.md
+++ b/docs/changelog/index.md
@@ -53,6 +53,7 @@ sidebar: false
- 修复开发模式下 `/api/*` 尾斜杠引发 Next.js 308 与 Gin 301 循环重定向:前端 Service 与 `api-client` 请求拦截器规范化路径、强制浏览器同源代理、Next `skipTrailingSlashRedirect`、后端 `RegisterCollection` 双路径注册;Access Token 管理员权限校验对齐 `token_admin`。
- 补全 Wavelet 边缘节点详情数据看板:迁移运行诊断摘要、系统信息、实时资源、网络流量、24 小时请求/容量/网络/磁盘趋势、请求结构分布与健康事件时间线。
- 节点详情页改为 Tabs 布局(概览 / 数据看板 / 配置与部署),统一 Edge/Relay/Tunnel 详情壳层并支持 `tab` URL 参数深链。
+- 节点详情 24 小时网络/磁盘 IO 趋势图对齐原版 ECharts 样式,恢复系列摘要卡与平滑面积折线图。
- OpenFlare 前端路由去除 `/openflare` 前缀,业务页面直接挂载于 `/`(如 `/nodes`、`/websites`);侧栏移除「首页」「我的文件」;旧路径 `/openflare/*`、`/home` 永久重定向至新路径。
## [v2.3.4] - 2026-06-17