Files
lislgosms/src/apps/admin/system-monitoring/AlertHistory.tsx
T

98 lines
3.7 KiB
TypeScript

import { useEffect, useState } from 'react';
import { adminApi } from '@/api/adminApi';
import { Button, DateRangeInput, Table, type TableColumn } from '@/components/ui';
import { formatDateTime } from '@/utils/dateTime';
type History = Awaited<ReturnType<typeof adminApi.getInfrastructureAlertHistory>>;
const columns: TableColumn<History['items'][number]>[] = [
{ key: 'name', title: '告警', width: '280px', render: (row) => row.name },
{
key: 'severity',
title: '级别',
width: '90px',
render: (row) => ({ critical: '严重', warning: '警告', info: '提示' })[row.severity] || row.severity,
},
{ key: 'instance', title: '服务 / 实例', width: '220px', render: (row) => row.service || row.instance || '主机资源' },
{ key: 'startedAt', title: '触发时间', width: '180px', render: (row) => formatDateTime(row.startedAt) },
{
key: 'lastObservedAt',
title: '范围内最后采样',
width: '180px',
render: (row) => formatDateTime(row.lastObservedAt),
},
];
export function AlertHistory() {
const [dates, setDates] = useState(() => {
const key = (time: number) => new Date(time + 8 * 3600_000).toISOString().slice(0, 10);
return { start: key(Date.now() - 6 * 86400_000), end: key(Date.now()) };
});
const [query, setQuery] = useState({ ...dates, page: 1, revision: 0 });
const [response, setResponse] = useState<{ query: typeof query; data: History | null; error: string }>();
const loading = response?.query !== query;
const data = loading ? null : response?.data;
const error = loading ? '' : response?.error;
useEffect(() => {
let current = true;
adminApi
.getInfrastructureAlertHistory(query.start, query.end, query.page)
.then((result) => {
if (current) setResponse({ query, data: result, error: '' });
})
.catch((reason) => {
if (current)
setResponse({ query, data: null, error: reason instanceof Error ? reason.message : '历史告警加载失败' });
});
return () => {
current = false;
};
}, [query]);
return (
<section className="surface system-monitoring-alerts" aria-label="历史告警记录">
<header>
<strong>历史告警记录</strong>
</header>
<div className="filter-bar">
<DateRangeInput
label="告警日期"
value={dates}
onChange={(value) => setDates({ start: value.start || '', end: value.end || '' })}
/>
<Button disabled={loading} onClick={() => setQuery({ ...dates, page: 1, revision: query.revision + 1 })}>
查询
</Button>
</div>
<p className="muted">
默认近7天,最多31天;读取 Prometheus
保留的真实触发周期(含等待触发),最后采样不代表准确恢复时间。保留期外或采集缺失的历史无法补齐。
</p>
{error ? (
<p role="alert" className="form-error">
{error}
</p>
) : null}
<Table
columns={columns}
data={loading ? [] : (data?.items ?? [])}
rowKey="id"
pagination={false}
emptyText={loading ? '历史告警加载中…' : error ? '历史告警不可用' : '所选日期没有保留的告警记录'}
/>
<div className="table-footer">
<span>
{data?.total ?? 0} · {data?.page ?? query.page}
</span>
<Button disabled={loading || query.page <= 1} onClick={() => setQuery({ ...query, page: query.page - 1 })}>
上一页
</Button>
<Button
disabled={loading || !data || query.page * data.pageSize >= data.total}
onClick={() => setQuery({ ...query, page: query.page + 1 })}
>
下一页
</Button>
</div>
</section>
);
}