154 lines
5.3 KiB
TypeScript
154 lines
5.3 KiB
TypeScript
import { Card } from '@/components/ui/card';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
|
import {
|
|
Send,
|
|
Clock,
|
|
Users,
|
|
Eye,
|
|
Trash2,
|
|
CheckCircle2,
|
|
XCircle,
|
|
Timer
|
|
} from 'lucide-react';
|
|
import { format } from 'date-fns';
|
|
import { zhCN } from 'date-fns/locale';
|
|
import { MessageSendRecord } from '@/types/message';
|
|
|
|
interface MessageSendTableProps {
|
|
sendRecords: MessageSendRecord[];
|
|
onPreview: (record: MessageSendRecord) => void;
|
|
onCancel: (id: string) => void;
|
|
onDelete: (id: string) => void;
|
|
getTypeIcon: (type: string) => JSX.Element;
|
|
getTypeLabel: (type: string) => string;
|
|
getTypeBadge: (type: string) => string;
|
|
getStatusBadge: (status: string) => JSX.Element;
|
|
}
|
|
|
|
export function MessageSendTable({
|
|
sendRecords,
|
|
onPreview,
|
|
onCancel,
|
|
onDelete,
|
|
getTypeIcon,
|
|
getTypeLabel,
|
|
getTypeBadge,
|
|
getStatusBadge
|
|
}: MessageSendTableProps) {
|
|
return (
|
|
<Card>
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>消息模版</TableHead>
|
|
<TableHead>类型</TableHead>
|
|
<TableHead>接收人数</TableHead>
|
|
<TableHead>发送方式</TableHead>
|
|
<TableHead>状态</TableHead>
|
|
<TableHead>创建时间</TableHead>
|
|
<TableHead>操作</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{sendRecords.length === 0 ? (
|
|
<TableRow>
|
|
<TableCell colSpan={7} className="text-center text-muted-foreground py-8">
|
|
暂无发送记录
|
|
</TableCell>
|
|
</TableRow>
|
|
) : (
|
|
sendRecords.map((record) => (
|
|
<TableRow key={record.id}>
|
|
<TableCell>
|
|
<div>{record.templateName}</div>
|
|
{record.subject && (
|
|
<p className="text-xs text-muted-foreground">{record.subject}</p>
|
|
)}
|
|
</TableCell>
|
|
<TableCell>
|
|
<Badge className={getTypeBadge(record.type)}>
|
|
<span className="flex items-center gap-1">
|
|
{getTypeIcon(record.type)}
|
|
{getTypeLabel(record.type)}
|
|
</span>
|
|
</Badge>
|
|
</TableCell>
|
|
<TableCell>
|
|
<div className="flex items-center gap-1">
|
|
<Users className="w-4 h-4 text-muted-foreground" />
|
|
<span>{record.recipientCount}</span>
|
|
</div>
|
|
</TableCell>
|
|
<TableCell>
|
|
{record.sendType === 'immediate' ? (
|
|
<Badge variant="outline">
|
|
<Send className="w-3 h-3 mr-1" />
|
|
实时发送
|
|
</Badge>
|
|
) : (
|
|
<div>
|
|
<Badge variant="outline">
|
|
<Clock className="w-3 h-3 mr-1" />
|
|
定时发送
|
|
</Badge>
|
|
{record.scheduledTime && (
|
|
<p className="text-xs text-muted-foreground mt-1">
|
|
{format(new Date(record.scheduledTime), 'MM-dd HH:mm', { locale: zhCN })}
|
|
</p>
|
|
)}
|
|
</div>
|
|
)}
|
|
</TableCell>
|
|
<TableCell>
|
|
{getStatusBadge(record.status)}
|
|
{record.status === 'sent' && (
|
|
<p className="text-xs text-muted-foreground mt-1">
|
|
成功 {record.sentCount}/{record.recipientCount}
|
|
</p>
|
|
)}
|
|
</TableCell>
|
|
<TableCell className="text-sm text-muted-foreground">
|
|
{format(new Date(record.createdAt), 'MM-dd HH:mm', { locale: zhCN })}
|
|
</TableCell>
|
|
<TableCell>
|
|
<div className="flex gap-1">
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
onClick={() => onPreview(record)}
|
|
title="查看详情"
|
|
>
|
|
<Eye className="w-4 h-4" />
|
|
</Button>
|
|
{record.status === 'pending' && (
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
onClick={() => onCancel(record.id)}
|
|
title="取消发送"
|
|
>
|
|
<XCircle className="w-4 h-4 text-orange-600" />
|
|
</Button>
|
|
)}
|
|
{(record.status === 'sent' || record.status === 'cancelled') && (
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
onClick={() => onDelete(record.id)}
|
|
title="删除记录"
|
|
>
|
|
<Trash2 className="w-4 h-4 text-destructive" />
|
|
</Button>
|
|
)}
|
|
</div>
|
|
</TableCell>
|
|
</TableRow>
|
|
))
|
|
)}
|
|
</TableBody>
|
|
</Table>
|
|
</Card>
|
|
);
|
|
} |