import { Bell, CalendarClock, Pencil, Play, Trash2 } from 'lucide-react' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { useDeleteTask, useRunTaskNow, useUpdateTask } from '@/hooks/useMonitor' import { useCurrentPlatform } from '@/hooks/usePlatform' import { formatRelative } from '@/lib/monitorFormat' import type { MonitorTask } from '@/types/monitor' interface TaskCardProps { task: MonitorTask selected: boolean onSelect: () => void onEdit: () => void } /** Maps a task's last run status onto a badge variant. */ function statusVariant(status: string) { switch (status) { case 'success': return 'success' as const case 'running': case 'pending': return 'running' as const case 'partial': return 'warning' as const case 'failed': case 'timeout': return 'destructive' as const default: return 'idle' as const } } const STATUS_LABEL: Record = { idle: '未运行', success: '成功', partial: '部分失败', failed: '失败', timeout: '超时', running: '运行中', pending: '排队中', interrupted: '已中断', } export function TaskCard({ task, selected, onSelect, onEdit }: TaskCardProps) { const updateTask = useUpdateTask() const deleteTask = useDeleteTask() const runNow = useRunTaskNow() // 按**任务自己的**平台取措辞,而不是当前平台 —— 卡片未必只出现在同平台的列表里。 // 抖音管它们叫「作品」,小红书叫「笔记」,写死一个对另一个就是错的。 const { platforms } = useCurrentPlatform() const noteNoun = platforms.find((entry) => entry.value === task.platform)?.target_hints?.note_label ?? '笔记' // A suspected cookie failure surfaces here so it is visible without opening // the event feed. const authTrouble = task.last_status === 'partial' return (
{task.name} {task.mode === 'creator' ? '博主' : noteNoun} {STATUS_LABEL[task.last_status] ?? task.last_status} {task.unread_events > 0 && ( {task.unread_events} )}
目标 {task.target_count} 个 {/* 由后端拼好,列表和编辑弹窗因此不会对同一个计划给出两种说法 */} {task.schedule_label} {task.enabled ? formatRelative(task.next_run_at) : '已暂停'} 上次 {formatRelative(task.last_run_at)}
{authTrouble && (

{task.last_error ?? '疑似登录态失效,请检查 Cookie'}

)}
) }