Drawer 宽度从固定百分比改为按视口响应式默认值(6段断点),宽屏占比更小、窄屏占比更大。 启用 TDesign sizeDraggable 原生拖拽调整能力,配置 min/max 视口安全边界,不持久化拖拽宽度。 概览统计卡片改为 TDesign Statistic 上下布局(与 SummaryCards 一致),提升窄屏视觉体验。 Drawer header 间距调大,MutationObserver polyfill 补全。
105 lines
3.5 KiB
TypeScript
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>
|
|
);
|
|
}
|