// Copyright 2026 Arctel.net // SPDX-License-Identifier: Apache-2.0 'use client'; import * as React from 'react'; import { useQuery } from '@tanstack/react-query'; import { ChevronLeft, ChevronRight, History, RefreshCw, Search, } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Badge } from '@/components/ui/badge'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { ErrorInline } from '@/components/layout/error'; import { LoadingStateWithBorder } from '@/components/layout/loading'; import { cn } from '@/lib/utils'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import type { PushHistory } from '@/lib/services/push'; import { PushService } from '@/lib/services/push'; function getLevelBadgeVariant( level: string, ): 'outline' | 'secondary' | 'destructive' | 'default' { switch (level) { case 'CRITICAL': return 'destructive'; case 'IMPORTANT': return 'default'; default: return 'outline'; } } export function HistoriesTab() { const [historyPage, setHistoryPage] = React.useState(1); const [historySearch, setHistorySearch] = React.useState(''); const [historyStatus, setHistoryStatus] = React.useState('all'); const [detailOpen, setDetailOpen] = React.useState(false); const [selectedHistory, setSelectedHistory] = React.useState(null); const handleRowClick = (hist: PushHistory) => { setSelectedHistory(hist); setDetailOpen(true); }; const historiesQuery = useQuery({ queryKey: [ 'admin', 'push-histories', historyPage, historySearch, historyStatus, ], queryFn: () => PushService.listHistories({ page: historyPage, page_size: 10, event_key: historySearch || undefined, status: historyStatus === 'all' ? undefined : historyStatus, }), }); return (
{ setHistorySearch(e.target.value); setHistoryPage(1); }} />
事件 渠道 目标 标题 等级 状态 时间 {historiesQuery.isLoading ? ( ) : historiesQuery.isError ? ( historiesQuery.refetch()} className='justify-center' /> ) : (historiesQuery.data?.results ?? []).length === 0 ? ( 无推送历史数据 ) : ( (historiesQuery.data?.results ?? []).map((hist) => ( handleRowClick(hist)} > {hist.event_key} {hist.channel === 'email' ? '邮件' : hist.channel} {hist.target} {hist.title} {hist.level} {hist.status === 'success' ? '成功' : '失败'} {hist.status !== 'success' && hist.error_msg && (
{hist.error_msg}
)}
{new Date(hist.created_at).toLocaleString()}
)) )}
{historiesQuery.data && historiesQuery.data.total > 0 && (
共 {historiesQuery.data.total} 条历史记录
{historyPage}
)} {/* ==================== 对话框:推送详情 ==================== */} 推送通知详情 查看该条通知发送的详细审计信息与内容 {selectedHistory && (
事件标识
{selectedHistory.event_key}
发送渠道
{selectedHistory.channel === 'email' ? '邮件推送' : selectedHistory.channel}
推送目标
{selectedHistory.target}
发送时间
{new Date(selectedHistory.created_at).toLocaleString()}
通知等级
{selectedHistory.level}
发送状态
{selectedHistory.status === 'success' ? '成功' : '失败'}
{selectedHistory.status === 'failed' && selectedHistory.error_msg && (
失败原因
{selectedHistory.error_msg}
)}
通知标题
{selectedHistory.title}
通知内容
{selectedHistory.content}
)}
); }