import type { AdminRecord } from '../types'; import { ReferenceList } from './ReferenceList'; const STATUS_MAP: Record = { completed: { label: '已完成', color: '#00b894', bg: 'rgba(0,184,148,0.15)' }, failed: { label: '失败', color: '#e74c3c', bg: 'rgba(231,76,60,0.15)' }, processing: { label: '生成中', color: '#00b8e6', bg: 'rgba(0,184,230,0.15)' }, queued: { label: '排队中', color: '#00b8e6', bg: 'rgba(0,184,230,0.15)' }, }; const MODE_MAP: Record = { universal: '全能参考', keyframe: '首尾帧' }; interface Props { record: AdminRecord; onClose: () => void; showTeam?: boolean; showCost?: boolean; } export function RecordDetailModal({ record: r, onClose, showTeam, showCost }: Props) { const st = STATUS_MAP[r.status] || STATUS_MAP.processing; const elapsed = (() => { if (!r.completed_at) return '-'; const ms = new Date(r.completed_at).getTime() - new Date(r.created_at).getTime(); if (ms < 0) return '-'; const sec = Math.round(ms / 1000); if (sec < 60) return `${sec}秒`; const min = Math.floor(sec / 60); const s = sec % 60; return `${min}分${s > 0 ? s + '秒' : ''}`; })(); const refs = r.reference_urls || []; return ( <>
e.stopPropagation()}> {/* Header */}
任务详情
{/* Status */}
{st.label}
{/* Error */} {r.status === 'failed' && r.error_message && (
失败原因
{r.error_message}
{r.raw_error && r.raw_error !== r.error_message && (
原始错误:{r.raw_error}
)}
)} {/* Info Grid */}
基本信息
{r.ark_task_id && } {r.username && } {showTeam && r.team_name && } {showCost && } {r.seed != null && r.seed !== -1 && }
{/* Prompt */}
提示词
{r.prompt || '(无提示词)'}
{/* References */} {refs.length > 0 && ( <>
参考素材({refs.length})
)}
); } function InfoItem({ label, value }: { label: string; value: string }) { return (
{label}
{value}
); } // Styles const overlay: React.CSSProperties = { position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.6)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 10000, }; const modal: React.CSSProperties = { background: '#111118', border: '1px solid #2a2a38', borderRadius: 12, width: 560, maxHeight: '80vh', display: 'flex', flexDirection: 'column', }; const header: React.CSSProperties = { display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '16px 20px', borderBottom: '1px solid #2a2a38', }; const closeBtn: React.CSSProperties = { background: 'none', border: 'none', color: '#888', fontSize: 16, cursor: 'pointer', padding: '4px 8px', borderRadius: 4, }; const body: React.CSSProperties = { padding: 20, overflowY: 'auto', flex: 1, }; const statusBadge: React.CSSProperties = { padding: '4px 12px', borderRadius: 6, fontSize: 13, fontWeight: 500, }; const errorBox: React.CSSProperties = { background: 'rgba(231,76,60,0.08)', border: '1px solid rgba(231,76,60,0.2)', borderRadius: 8, padding: 12, marginBottom: 16, fontSize: 13, color: '#e74c3c', }; const sectionTitle: React.CSSProperties = { fontSize: 12, color: '#888', fontWeight: 500, marginBottom: 8, marginTop: 16, textTransform: 'uppercase', letterSpacing: 1, }; const infoGrid: React.CSSProperties = { display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '12px 16px', }; const promptBox: React.CSSProperties = { background: '#0a0a0f', borderRadius: 8, padding: 12, fontSize: 13, color: '#ccc', lineHeight: 1.6, whiteSpace: 'pre-wrap', wordBreak: 'break-all', maxHeight: 150, overflowY: 'auto', };