107 lines
3.4 KiB
TypeScript
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",
|
|
};
|
|
}
|