1
0
Files
DiAL/src/web/constants/target-table-columns.tsx

107 lines
3.4 KiB
TypeScript

import type { PrimaryTableCellParams, PrimaryTableCol } from "tdesign-react";
import { Progress, Tag } from "tdesign-react";
import type { TargetStatus } from "../../shared/api";
import { StatusBar } from "../components/StatusBar";
import { StatusDot } from "../components/StatusDot";
import { getAvailabilityProgressColor } from "./color-threshold";
import { statusFilter } from "./target-table-filters";
import { availabilitySorter, latencySorter } from "./target-table-sorters";
export function createTargetTableColumns(checkerTypes: string[]): Array<PrimaryTableCol<TargetStatus>> {
return [
{
align: "center",
cell: ({ row }: PrimaryTableCellParams<TargetStatus>) => <StatusDot up={!!row.latestCheck?.matched} />,
colKey: "latestCheck.matched",
filter: statusFilter,
fixed: "left",
title: "#",
width: 60,
},
{
colKey: "name",
ellipsis: true,
title: "名称",
},
{
cell: ({ row }: PrimaryTableCellParams<TargetStatus>) => (
<Tag size="small" theme="primary" variant="light-outline">
{row.type}
</Tag>
),
colKey: "type",
filter: createTypeFilter(checkerTypes),
title: "类型",
width: 80,
},
{
cell: ({ row }: PrimaryTableCellParams<TargetStatus>) => {
const availability = row.stats?.availability;
if (availability === undefined || availability === null) return "-";
const color = getAvailabilityProgressColor(availability);
return (
<Progress
color={color}
label={`${availability.toFixed(1)}%`}
percentage={availability}
size="small"
theme="line"
/>
);
},
colKey: "stats.availability",
sorter: availabilitySorter,
sortType: "all",
title: "可用率(24h)",
width: 160,
},
{
cell: ({ row }: PrimaryTableCellParams<TargetStatus>) => <StatusBar samples={row.recentSamples} />,
colKey: "recentSamples",
title: "最近状态",
width: 220,
},
{
align: "center",
cell: ({ row }: PrimaryTableCellParams<TargetStatus>) => {
const streak = row.currentStreak;
if (!streak) return "-";
return (
<Tag size="small" theme={streak.up ? "success" : "danger"} variant="light">
{streak.up ? "▲" : "▼"} {streak.count}
{streak.capped ? "+" : ""}
</Tag>
);
},
colKey: "currentStreak",
title: "连续(次)",
width: 88,
},
{
align: "right",
cell: ({ row }: PrimaryTableCellParams<TargetStatus>) => {
const ms = row.latestCheck?.durationMs;
if (ms === null || ms === undefined) return <span className="text-disabled">-</span>;
const colorClass = ms <= 100 ? "latency-ok" : ms <= 500 ? "latency-warn" : "latency-error";
const latencyText = ms > 9999 ? "9999+" : `${Math.round(ms)}`;
return <span className={`${colorClass} latency-value tabular-nums`}>{latencyText}</span>;
},
colKey: "latestCheck.durationMs",
sorter: latencySorter,
sortType: "all",
title: "延迟(ms)",
width: 75,
},
];
}
function createTypeFilter(checkerTypes: string[]): PrimaryTableCol["filter"] {
return {
list: [{ label: "全部", value: "" }, ...checkerTypes.map((type) => ({ label: type, value: type }))],
type: "single",
};
}