1
0
Files
DiAL/src/web/components/OverviewTab.tsx
lanyuanxiaoyao 88f4119a4e feat: Drawer 响应式默认宽度与拖拽调整,统计卡片上下布局优化
Drawer 宽度从固定百分比改为按视口响应式默认值(6段断点),宽屏占比更小、窄屏占比更大。

启用 TDesign sizeDraggable 原生拖拽调整能力,配置 min/max 视口安全边界,不持久化拖拽宽度。

概览统计卡片改为 TDesign Statistic 上下布局(与 SummaryCards 一致),提升窄屏视觉体验。

Drawer header 间距调大,MutationObserver polyfill 补全。
2026-05-15 23:10:08 +08:00

105 lines
3.5 KiB
TypeScript

import type { ReactNode } from "react";
import { Col, Descriptions, Divider, Row, Skeleton, Space, Statistic } from "tdesign-react";
import type { TargetMetricsResponse, TargetStatus } from "../../shared/api";
import { formatDurationUnit } from "../utils/time";
import { TrendChart } from "./TrendChart";
interface OverviewStatItemProps {
color?: string;
suffix?: ReactNode;
title: string;
value: number;
}
interface OverviewTabProps {
metricsData: null | TargetMetricsResponse;
metricsLoading: boolean;
target: TargetStatus;
}
export function OverviewTab({ metricsData, metricsLoading, target }: OverviewTabProps) {
const stats = metricsData?.stats ?? null;
const mttr = formatDurationUnit(stats?.mttr ?? null);
const longestOutage = formatDurationUnit(stats?.longestOutage ?? null);
const currentUpStreak = stats?.currentStreak?.up ? stats.currentStreak.count : 0;
return (
<Space className="full-width" direction="vertical" size={16}>
<Divider align="left"></Divider>
<Descriptions
items={[
{ content: target.target, label: "目标地址" },
{ content: target.interval, label: "检查间隔" },
{
content: target.latestCheck ? new Date(target.latestCheck.timestamp).toLocaleString("zh-CN") : "-",
label: "最新检查时间",
},
{ content: target.latestCheck?.statusDetail ?? "-", label: "状态详情" },
]}
/>
<Divider align="left"></Divider>
{metricsLoading ? (
<Skeleton animation="gradient" />
) : stats ? (
<Row gutter={[16, 16]}>
<Col span={3}>
<OverviewStatItem color="green" suffix="%" title="可用率" value={stats.availability} />
</Col>
<Col span={3}>
<OverviewStatItem
suffix={stats.avgDurationMs === null ? "" : "ms"}
title="平均延迟"
value={stats.avgDurationMs ?? 0}
/>
</Col>
<Col span={3}>
<OverviewStatItem
suffix={stats.p95DurationMs === null ? "" : "ms"}
title="P95 延迟"
value={stats.p95DurationMs ?? 0}
/>
</Col>
<Col span={3}>
<OverviewStatItem color="blue" title="检查总数" value={stats.totalChecks} />
</Col>
<Col span={3}>
<OverviewStatItem suffix={mttr.suffix} title="MTTR" value={mttr.value} />
</Col>
<Col span={3}>
<OverviewStatItem suffix={longestOutage.suffix} title="最长故障" value={longestOutage.value} />
</Col>
<Col span={3}>
<OverviewStatItem color="red" suffix="次" title="故障次数" value={stats.incidentCount} />
</Col>
<Col span={3}>
<OverviewStatItem color="green" suffix="次" title="连续正常" value={currentUpStreak} />
</Col>
</Row>
) : (
<div className="trend-empty"></div>
)}
<Divider align="left"></Divider>
{metricsLoading ? (
<Skeleton animation="gradient" />
) : metricsData ? (
<TrendChart data={metricsData.trend} />
) : (
<div className="trend-empty"></div>
)}
</Space>
);
}
function OverviewStatItem({ color, suffix, title, value }: OverviewStatItemProps) {
return (
<div className="overview-stat-card summary-stat-col">
<Statistic color={color} suffix={suffix} title={title} value={value} />
</div>
);
}