优化ui
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
import { formatLocalDateTime } from "@/lib/datetime";
|
||||
import { formatBytes, getDashboardMetrics } from "@/lib/store";
|
||||
|
||||
import { DashboardCharts } from "./dashboard-charts";
|
||||
|
||||
function getNodePill(node: {
|
||||
enabled: number;
|
||||
last_error_message: string | null;
|
||||
@@ -19,17 +22,13 @@ export default async function DashboardPage() {
|
||||
const data = await getDashboardMetrics();
|
||||
|
||||
return (
|
||||
<main className="page-stack">
|
||||
<main className="page-stack dashboard-page">
|
||||
<section className="hero-panel">
|
||||
<div className="hero-copy">
|
||||
<span className="eyebrow">OVERVIEW</span>
|
||||
<span className="eyebrow">概览</span>
|
||||
<h2>仪表盘</h2>
|
||||
<p className="page-lede">
|
||||
汇总多节点在线、鉴权失败、同步错误和用户用量,作为当前运行态的统一入口。
|
||||
</p>
|
||||
<div className="badge-row">
|
||||
<span className="status-pill status-pill--ok">HTTP 鉴权在线</span>
|
||||
<span className="status-pill status-pill--neutral">轮询聚合已启用</span>
|
||||
<span className="status-pill status-pill--ok">在线 {data.totals.total_online_connections}</span>
|
||||
<span className="status-pill status-pill--warm">节点 {data.totals.enabled_nodes}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -59,15 +58,25 @@ export default async function DashboardPage() {
|
||||
<article className="metric-card metric-card--sage">
|
||||
<span>启用节点</span>
|
||||
<strong>{data.totals.enabled_nodes}</strong>
|
||||
<small>轮询与 kick 生效范围</small>
|
||||
<small>当前可用</small>
|
||||
</article>
|
||||
<article className="metric-card metric-card--paper">
|
||||
<span>累计流量</span>
|
||||
<strong>{formatBytes(data.totals.total_traffic)}</strong>
|
||||
<small>已聚合到 SQLite</small>
|
||||
<small>全量累计</small>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<DashboardCharts
|
||||
nodeHealth={data.nodeHealth}
|
||||
trafficTrend={data.trafficTrend}
|
||||
trafficBuckets={data.trafficBuckets}
|
||||
trafficUserOptions={data.trafficUserOptions}
|
||||
loadTrend={data.loadTrend}
|
||||
failureTrend={data.failureTrend}
|
||||
topConsumerRows={data.topConsumerRows}
|
||||
/>
|
||||
|
||||
<section className="panel-grid">
|
||||
<article className="panel-card">
|
||||
<div className="section-title">
|
||||
@@ -90,7 +99,7 @@ export default async function DashboardPage() {
|
||||
在线 {node.last_online_users} / 流 {node.last_stream_count}
|
||||
</p>
|
||||
<p className="muted">
|
||||
最近成功 {node.last_sync_ok_at ?? "无"}
|
||||
最近成功 {formatLocalDateTime(node.last_sync_ok_at)}
|
||||
</p>
|
||||
{node.last_error_message ? (
|
||||
<p className="error-text">{node.last_error_message}</p>
|
||||
@@ -138,7 +147,7 @@ export default async function DashboardPage() {
|
||||
</div>
|
||||
<div className="align-right">
|
||||
<p className="muted mono">{item.addr ?? "-"}</p>
|
||||
<p className="muted">{item.created_at}</p>
|
||||
<p className="muted">{formatLocalDateTime(item.created_at)}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
@@ -160,7 +169,7 @@ export default async function DashboardPage() {
|
||||
<p>
|
||||
+{formatBytes(item.tx_bytes + item.rx_bytes)}
|
||||
</p>
|
||||
<p className="muted">{item.created_at}</p>
|
||||
<p className="muted">{formatLocalDateTime(item.created_at)}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
@@ -181,7 +190,7 @@ export default async function DashboardPage() {
|
||||
<strong>{item.node_name}</strong>
|
||||
<p className="error-text">{item.error_message ?? "unknown error"}</p>
|
||||
</div>
|
||||
<p className="muted">{item.created_at}</p>
|
||||
<p className="muted">{formatLocalDateTime(item.created_at)}</p>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user