import React, { useState, useRef } from 'react'; import { Play, RotateCcw, ArrowUpToLine, Trash2, MoreVertical, Clock } from 'lucide-react'; import { formatTimeAgo, thumbUrl, h3FileUrl, getH3Base, getJobKind } from '../utils'; export default function JobCard({ job, isSelected, onSelect, onRerun, onPrioritize, onDelete }) { const [isHovered, setIsHovered] = useState(false); const [showMenu, setShowMenu] = useState(false); const videoRef = useRef(null); const req = job.req || {}; const kind = getJobKind(req); const isDone = job.status === 'done'; const isRunning = job.status === 'running'; const isQueued = job.status === 'queued'; const isFailed = job.status === 'failed'; const isCancelled = job.status === 'cancelled'; // 进度计算 const curStep = job.step || 0; const totalSteps = job.total_steps || req.steps || 20; const progressPct = totalSteps > 0 ? Math.min(100, Math.max(curStep > 0 ? 5 : 2, Math.round((curStep / totalSteps) * 100))) : 0; // 悬停时自动微播放 const handleMouseEnter = () => { setIsHovered(true); if (isDone && videoRef.current) { videoRef.current.currentTime = 0; videoRef.current.play().catch(() => {}); } }; const handleMouseLeave = () => { setIsHovered(false); setShowMenu(false); if (isDone && videoRef.current) { videoRef.current.pause(); } }; // 缩略图地址 const videoFileUrl = isDone ? h3FileUrl(`${getH3Base()}/v1/videos/${job.id}/file`) : null; const coverImg = req.first_frame_url || (req.reference_image_urls || [])[0]; return (
onSelect(job.id)} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} className={`group relative p-3 rounded-2xl border transition-all duration-200 cursor-pointer flex flex-col gap-2 ${ isSelected ? 'bg-emerald-50/80 border-emerald-500 ring-1 ring-emerald-500/40 shadow-xs' : 'bg-white border-slate-200/90 hover:bg-slate-50/80 hover:border-slate-300 shadow-xs' }`} >
{/* 缩略图容器 (自适应比例) */}
{isDone && videoFileUrl ? (
{/* 右侧核心信息 */}
{/* 顶栏:短 ID 与状态胶囊 */}
#{job.id.substring(0, 8)} {/* 状态 Pill */}
{isDone && ( 已完成 )} {isRunning && ( 采样 {curStep}/{totalSteps}步 )} {isQueued && ( 排队中 )} {isFailed && ( 失败 )} {isCancelled && ( 已取消 )}
{/* Prompt 摘要 */}

{req.prompt || '(无 prompt 描述)'}

{/* 底栏:规格、时间与快捷菜单 */}
{kind.label} · {req.width ? `${req.width}p` : ''} {formatTimeAgo(job.created_at)}
{/* 三点操作菜单 */}
e.stopPropagation()}> {showMenu && (
{isQueued && ( )}
)}
{/* 处于运行中时,卡片底部直接展现清晰的横向进度条 */} {isRunning && (
)}
); }