/** * 穿搭照片生成历史记录组件 */ import React, { useState, useEffect, useCallback } from 'react'; import { Clock, CheckCircle, XCircle, AlertCircle, Eye, Download, RotateCcw, Trash2, Filter, Search, Image as ImageIcon } from 'lucide-react'; import type { OutfitPhotoGeneration, GenerationHistoryQuery, GenerationHistoryResponse } from '../../types/outfitPhotoGeneration'; import { GenerationStatus } from '../../types/outfitPhotoGeneration'; import { OutfitPhotoGenerationService } from '../../services/outfitPhotoGenerationService'; import { LoadingSpinner } from '../LoadingSpinner'; import { Modal } from '../Modal'; import { DeleteConfirmDialog } from '../DeleteConfirmDialog'; interface OutfitPhotoGenerationHistoryProps { projectId?: string; modelId?: string; onRetryGeneration?: (generationId: string) => void; } const STATUS_COLORS = { [GenerationStatus.Pending]: 'text-yellow-600 bg-yellow-100', [GenerationStatus.Processing]: 'text-blue-600 bg-blue-100', [GenerationStatus.Completed]: 'text-green-600 bg-green-100', [GenerationStatus.Failed]: 'text-red-600 bg-red-100' }; const STATUS_ICONS = { [GenerationStatus.Pending]: Clock, [GenerationStatus.Processing]: AlertCircle, [GenerationStatus.Completed]: CheckCircle, [GenerationStatus.Failed]: XCircle }; const STATUS_LABELS = { [GenerationStatus.Pending]: '等待中', [GenerationStatus.Processing]: '生成中', [GenerationStatus.Completed]: '已完成', [GenerationStatus.Failed]: '失败' }; export const OutfitPhotoGenerationHistory: React.FC = ({ projectId, modelId, onRetryGeneration }) => { const [records, setRecords] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [selectedRecord, setSelectedRecord] = useState(null); const [showDetailModal, setShowDetailModal] = useState(false); const [deleteConfirm, setDeleteConfirm] = useState(null); // 查询参数 const [query, setQuery] = useState({ project_id: projectId, model_id: modelId, page: 1, page_size: 20 }); // 分页信息 const [totalCount, setTotalCount] = useState(0); const [hasMore, setHasMore] = useState(false); // 过滤器状态 const [showFilters, setShowFilters] = useState(false); const [statusFilter, setStatusFilter] = useState(''); const [searchText, setSearchText] = useState(''); // 加载历史记录 const loadHistory = useCallback(async (resetPage = false) => { try { setLoading(true); setError(null); const searchQuery: GenerationHistoryQuery = { ...query, page: resetPage ? 1 : query.page, status: statusFilter || undefined }; const response: GenerationHistoryResponse = await OutfitPhotoGenerationService.getGenerationHistory(searchQuery); if (resetPage) { setRecords(response.records); } else { setRecords(prev => [...prev, ...response.records]); } setTotalCount(response.total_count); setHasMore(response.has_more); if (resetPage) { setQuery(prev => ({ ...prev, page: 1 })); } } catch (err) { console.error('加载生成历史失败:', err); setError(err instanceof Error ? err.message : '加载失败'); } finally { setLoading(false); } }, [query, statusFilter]); // 初始加载 useEffect(() => { loadHistory(true); }, [projectId, modelId, statusFilter]); // 加载更多 const loadMore = useCallback(() => { if (!loading && hasMore) { setQuery(prev => ({ ...prev, page: prev.page! + 1 })); loadHistory(false); } }, [loading, hasMore, loadHistory]); // 重试生成 const handleRetry = useCallback(async (record: OutfitPhotoGeneration) => { try { await OutfitPhotoGenerationService.retryGeneration(record.id); onRetryGeneration?.(record.id); // 重新加载历史记录 loadHistory(true); } catch (err) { console.error('重试生成失败:', err); setError(err instanceof Error ? err.message : '重试失败'); } }, [onRetryGeneration, loadHistory]); // 删除记录 const handleDelete = useCallback(async (recordId: string) => { try { await OutfitPhotoGenerationService.deleteGeneration(recordId); setRecords(prev => prev.filter(r => r.id !== recordId)); setDeleteConfirm(null); } catch (err) { console.error('删除记录失败:', err); setError(err instanceof Error ? err.message : '删除失败'); } }, []); // 查看详情 const handleViewDetail = useCallback((record: OutfitPhotoGeneration) => { setSelectedRecord(record); setShowDetailModal(true); }, []); // 格式化时间 const formatTime = (timeStr: string) => { const date = new Date(timeStr); return date.toLocaleString('zh-CN'); }; // 格式化持续时间 const formatDuration = (ms?: number) => { if (!ms) return '-'; if (ms < 1000) return `${ms}ms`; return `${(ms / 1000).toFixed(1)}s`; }; return (
{/* 头部 */}

生成历史

{/* 过滤器 */} {showFilters && (
setSearchText(e.target.value)} placeholder="搜索提示词..." className="w-full pl-7 pr-2 py-1 text-sm border border-gray-300 rounded focus:ring-1 focus:ring-purple-500 focus:border-transparent" />
)}
{/* 错误提示 */} {error && (
{error}
)} {/* 记录列表 */}
{records.length === 0 && !loading ? (

暂无生成记录

) : ( records.map((record) => { const StatusIcon = STATUS_ICONS[record.status]; return (
{STATUS_LABELS[record.status]} {formatTime(record.created_at)} {record.generation_time_ms && ( 耗时: {formatDuration(record.generation_time_ms)} )}

{record.prompt}

{record.error_message && (

错误: {record.error_message}

)}
结果: {record.result_image_urls.length} 张图片 {record.product_image_path && ( 商品图片: {record.product_image_path.split('/').pop()} )} {record.comfyui_prompt_id && ( 任务ID: {record.comfyui_prompt_id} )}
{record.status === GenerationStatus.Failed && ( )}
); }) )}
{/* 加载更多 */} {hasMore && (
)} {/* 详情模态框 */} {showDetailModal && selectedRecord && ( setShowDetailModal(false)} title="生成详情" size="lg" >
状态: {React.createElement(STATUS_ICONS[selectedRecord.status], { className: "w-3 h-3" })} {STATUS_LABELS[selectedRecord.status]}
创建时间: {formatTime(selectedRecord.created_at)}
{selectedRecord.generation_time_ms && (
生成耗时: {formatDuration(selectedRecord.generation_time_ms)}
)} {selectedRecord.comfyui_prompt_id && (
ComfyUI 任务ID: {selectedRecord.comfyui_prompt_id}
)}
提示词:

{selectedRecord.prompt}

{selectedRecord.negative_prompt && (
负面提示词:

{selectedRecord.negative_prompt}

)} {selectedRecord.error_message && (
错误信息:

{selectedRecord.error_message}

)} {selectedRecord.result_image_urls.length > 0 && (
生成结果:
{selectedRecord.result_image_urls.map((url, index) => (
{`结果
))}
)}
)} {/* 删除确认对话框 */} {deleteConfirm && ( setDeleteConfirm(null)} onConfirm={() => handleDelete(deleteConfirm)} title="删除生成记录" message="确定要删除这条生成记录吗?此操作不可撤销。" /> )}
); };