import { IconAlarm, IconBell, IconRefresh, IconSearch } from '@douyinfe/semi-icons'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { FormEvent, memo, useEffect, useMemo, useState } from 'react'; import { Link, useSearchParams } from 'react-router-dom'; import { api } from '../../api/client'; import type { AlertEvent, AlertNotification, AlertQuery, AlertRule, AlertRuleInput, AlertStatus, MetricDefinition, Page } from '../../api/types'; import { actionLabels, alertValue, canAct, formatAlertTime, operatorLabels, ruleCondition, severityLabels, statusLabels, thresholdText } from '../domain/alert'; import { InlineError } from '../shared/AsyncState'; import { usePlatformSession } from '../auth/AuthGate'; import { canAdminister, canOperate } from '../auth/session'; import { QUERY_MEMORY, queryScopeKey, retainPreviousPageWithinScope } from '../queryPolicy'; type Tab = 'events' | 'rules' | 'notifications'; type Filters = { keyword: string; severity: string; status: string; ruleId: string; protocol: string; dateFrom: string; dateTo: string }; const EMPTY_FILTERS: Filters = { keyword: '', severity: '', status: '', ruleId: '', protocol: '', dateFrom: '', dateTo: '' }; const PROTOCOLS = ['GB32960', 'JT808', 'YUTONG_MQTT']; const NUMERIC_OPERATORS = ['gt', 'gte', 'lt', 'lte', 'eq', 'neq', 'between', 'outside']; const BOOLEAN_OPERATORS = ['eq', 'neq', 'changed']; function SeverityTag({ severity }: Pick) { return {severityLabels[severity]}; } function StatusTag({ status }: Pick) { return {statusLabels[status]}; } const AlertRows = memo(function AlertRows({ rows, selectedID, onSelect }: { rows: AlertEvent[]; selectedID: string; onSelect: (id: string) => void }) { return <>{rows.map((event) => onSelect(event.id)}> onSelect(event.id)} aria-label={`选择 ${event.ruleName}`} /> {event.plate || '—'}{event.vin}{event.ruleName}{event.protocol || '—'} {formatAlertTime(event.triggeredAt)}{formatAlertTime(event.recoveredAt)}{alertValue(event)}{thresholdText(event)}{event.location || '—'}{event.handler || '—'} )}; }); function EventInspector({ event, note, acting, actionError, editable, onNote, onAction }: { event?: AlertEvent; note: string; acting: boolean; actionError?: string; editable: boolean; onNote: (value: string) => void; onAction: (action: 'acknowledge' | 'close' | 'ignore') => void }) { if (!event) return ; return