import React, { useState, useEffect, useCallback, useMemo } from 'react'; import { useAppStore } from '../store/useAppStore'; import { Button } from './ui/Button'; import { History, Download, Image as ImageIcon, Trash2 } from 'lucide-react'; import { cn } from '../utils/cn'; import { ImagePreviewModal } from './ImagePreviewModal'; import { useIndexedDBListener } from '../hooks/useIndexedDBListener'; import { DayPicker } from 'react-day-picker'; import zhCN from 'react-day-picker/dist/locale/zh-CN'; export const HistoryPanel: React.FC<{ setHoveredImage: (image: {url: string, title: string, width?: number, height?: number} | null) => void, setPreviewPosition?: (position: {x: number, y: number} | null) => void }> = ({ setHoveredImage, setPreviewPosition }) => { const { currentProject, selectedGenerationId, selectedEditId, selectGeneration, selectEdit, showHistory, setShowHistory, setCanvasImage, removeGeneration, removeEdit } = useAppStore(); const { getBlob } = useAppStore.getState(); // 使用自定义hook获取IndexedDB记录 const { generations: dbGenerations, edits: dbEdits, loading, error, refresh } = useIndexedDBListener(); const [previewModal, setPreviewModal] = React.useState<{ open: boolean; imageUrl: string; title: string; description?: string; }>({ open: false, imageUrl: '', title: '', description: '' }); // 删除确认对话框状态 const [deleteConfirm, setDeleteConfirm] = React.useState<{ open: boolean; ids: string[]; type: 'generation' | 'edit' | 'multiple'; count: number; }>({ open: false, ids: [], type: 'generation', count: 0 }); // 存储从Blob URL解码的图像数据 const [decodedImages, setDecodedImages] = useState>({}); // 跟踪当前悬停的记录 const [hoveredRecord, setHoveredRecord] = useState<{type: 'generation' | 'edit', id: string} | null>(null); // 筛选和搜索状态 const [startDate, setStartDate] = useState(() => { // 初始化时默认显示今天的记录 const today = new Date(); today.setHours(0, 0, 0, 0); return today.toISOString().split('T')[0]; }); const [endDate, setEndDate] = useState(() => { // 初始化时默认显示今天的记录 const today = new Date(); today.setHours(0, 0, 0, 0); return today.toISOString().split('T')[0]; }); const [searchTerm, setSearchTerm] = useState(''); const [showDatePicker, setShowDatePicker] = useState(false); // 控制日期选择器的显示 const [dateRange, setDateRange] = useState<{ from: Date | undefined; to: Date | undefined }>({ from: (() => { const today = new Date(); today.setHours(0, 0, 0, 0); return today; })(), to: (() => { const today = new Date(); today.setHours(0, 0, 0, 0); return today; })() }); // 分页状态 const [currentPage, setCurrentPage] = useState(1); const itemsPerPage = 20; // 减少每页显示的项目数 // 获取当前图像尺寸 // const [imageDimensions, setImageDimensions] = React.useState<{ width: number; height: number } | null>(null); // 当currentProject为空时,使用dbGenerations和dbEdits作为备选 const displayGenerations = currentProject ? currentProject.generations : dbGenerations; const displayEdits = currentProject ? currentProject.edits : dbEdits; // 筛选记录的函数 const filterRecords = useCallback((records: Array<{timestamp: number, prompt?: string, instruction?: string}>, isGeneration: boolean) => { return records.filter(record => { // 日期筛选 - 检查记录日期是否在筛选范围内 const recordDate = new Date(record.timestamp); recordDate.setHours(0, 0, 0, 0); // 设置为当天的开始 const recordDateStr = recordDate.toISOString().split('T')[0]; // 获取日期部分 YYYY-MM-DD // 检查是否在日期范围内 if (startDate && recordDateStr < startDate) return false; if (endDate && recordDateStr > endDate) return false; // 搜索词筛选 if (searchTerm) { if (isGeneration) { // 生成记录按提示词搜索 return record.prompt?.toLowerCase().includes(searchTerm.toLowerCase()) || false; } else { // 编辑记录按指令搜索 return record.instruction?.toLowerCase().includes(searchTerm.toLowerCase()) || false; } } return true; }); }, [startDate, endDate, searchTerm]); // 筛选后的记录 const filteredGenerations = useMemo(() => filterRecords(displayGenerations, true), [displayGenerations, filterRecords]); const filteredEdits = useMemo(() => filterRecords(displayEdits, false), [displayEdits, filterRecords]); // React.useEffect(() => { // if (canvasImage) { // const img = new Image(); // img.onload = () => { // setImageDimensions({ width: img.width, height: img.height }); // }; // img.src = canvasImage; // } else { // setImageDimensions(null); // } // }, [canvasImage]); // 当项目变化时,解码Blob图像 useEffect(() => { const decodeBlobImages = async () => { const newDecodedImages: Record = {}; // 解码生成记录的输出图像 for (const gen of displayGenerations) { if (Array.isArray(gen.outputAssetsBlobUrls)) { for (const blobUrl of gen.outputAssetsBlobUrls) { if (!decodedImages[blobUrl] && blobUrl.startsWith('blob:')) { const blob = getBlob(blobUrl); if (blob) { // 使用Promise来处理FileReader的异步操作 const dataUrl = await new Promise((resolve) => { const reader = new FileReader(); reader.onload = () => resolve(reader.result as string); reader.readAsDataURL(blob); }); newDecodedImages[blobUrl] = dataUrl; } } } } } // 解码编辑记录的输出图像 for (const edit of displayEdits) { if (Array.isArray(edit.outputAssetsBlobUrls)) { for (const blobUrl of edit.outputAssetsBlobUrls) { if (!decodedImages[blobUrl] && blobUrl.startsWith('blob:')) { const blob = getBlob(blobUrl); if (blob) { // 使用Promise来处理FileReader的异步操作 const dataUrl = await new Promise((resolve) => { const reader = new FileReader(); reader.onload = () => resolve(reader.result as string); reader.readAsDataURL(blob); }); newDecodedImages[blobUrl] = dataUrl; } } } } } if (Object.keys(newDecodedImages).length > 0) { setDecodedImages(prev => ({ ...prev, ...newDecodedImages })); } }; // 将异步操作包装在立即执行的函数中 (async () => { await decodeBlobImages(); })(); }, [displayGenerations, displayEdits, getBlob, decodedImages]); // 获取上传后的图片链接 const getUploadedImageUrl = (generationOrEdit: Generation | Edit, index: number) => { if (generationOrEdit.uploadResults && generationOrEdit.uploadResults[index]) { const uploadResult = generationOrEdit.uploadResults[index]; if (uploadResult.success && uploadResult.url) { // 返回原始链接,不添加任何参数 return uploadResult.url; } } return null; }; // 加载和错误状态显示 if (loading) { return (

历史记录和变体

正在加载历史记录...

); } if (error) { return (

历史记录和变体

加载历史记录时出错: {error}

); } if (!showHistory) { return (
); } return (
{/* 头部 */}

历史记录

{/* 筛选和搜索控件 */}
{showDatePicker && (
{ if (range) { // 确保日期时间设置为当天的开始 if (range.from) { range.from.setHours(0, 0, 0, 0); } if (range.to) { range.to.setHours(0, 0, 0, 0); } setDateRange(range); // 更新字符串格式的日期用于筛选 if (range.from) { setStartDate(range.from.toISOString().split('T')[0]); } if (range.to) { setEndDate(range.to.toISOString().split('T')[0]); } } }} numberOfMonths={2} className="border-0" locale={zhCN} />
)}
setSearchTerm(e.target.value)} className="flex-1 text-xs p-1.5 border border-gray-200 rounded-l-lg bg-gray-50 focus:outline-none focus:ring-1 focus:ring-yellow-400 card" placeholder="搜索提示词..." />
{/* 变体网格 */}

变体

{filteredGenerations.length + filteredEdits.length}/100 {(filteredGenerations.length > 0 || filteredEdits.length > 0) && ( )}
{filteredGenerations.length === 0 && filteredEdits.length === 0 ? (
🖼️

暂无历史记录

) : (
{/* 显示生成记录 */} {(() => { const sortedGenerations = [...filteredGenerations].sort((a, b) => b.timestamp - a.timestamp); // 合并所有记录并排序,然后分页 const allRecords = [...sortedGenerations, ...[...filteredEdits].sort((a, b) => b.timestamp - a.timestamp)] .sort((a, b) => b.timestamp - a.timestamp); const startIndex = (currentPage - 1) * itemsPerPage; const endIndex = startIndex + itemsPerPage; const paginatedRecords = allRecords.slice(startIndex, endIndex); // 只显示当前页的生成记录 const paginatedGenerations = paginatedRecords.filter(record => sortedGenerations.some(gen => gen.id === record.id) ); return paginatedGenerations.map((generation: {id: string, sourceAssets?: Array<{url: string}>, outputAssets?: Array<{url: string}>}) => { // 计算全局索引用于显示编号 const globalIndex = allRecords.findIndex(record => record.id === generation.id); return (
{ selectGeneration(generation.id); // 设置画布图像为生成结果图像,而不是参考图像 let imageUrl = null; // 优先使用生成结果图像 if (generation.outputAssets && generation.outputAssets.length > 0) { const asset = generation.outputAssets[0]; if (asset.url) { const uploadedUrl = getUploadedImageUrl(generation, 0); imageUrl = uploadedUrl || asset.url; } } // 如果没有生成结果图像,则使用参考图像 if (!imageUrl && generation.sourceAssets && generation.sourceAssets.length > 0) { // 参考图像在uploadResults中从索引outputAssets.length开始 const outputAssetsCount = generation.outputAssets?.length || 0; const uploadResultIndex = outputAssetsCount; // 第一个参考图像 const uploadedUrl = getUploadedImageUrl(generation, uploadResultIndex); if (uploadedUrl) { imageUrl = uploadedUrl; } else if (generation.sourceAssets[0].url) { imageUrl = generation.sourceAssets[0].url; } } if (imageUrl) { // 检查是否是Blob URL并且可能已经失效 if (imageUrl.startsWith('blob:')) { // 预先检查Blob URL是否有效 fetch(imageUrl) .then(response => { if (!response.ok) { // Blob URL失效,尝试从AppStore重新获取 const { getBlob } = useAppStore.getState(); const blob = getBlob(imageUrl); if (blob) { console.log('从AppStore找到Blob,重新创建URL...'); const newUrl = URL.createObjectURL(blob); setCanvasImage(newUrl); } else { // 如果AppStore中也没有,直接设置原URL,让ImageCanvas处理 setCanvasImage(imageUrl); } } else { // Blob URL有效,直接使用 setCanvasImage(imageUrl); } }) .catch(() => { // 网络错误,尝试从AppStore重新获取 const { getBlob } = useAppStore.getState(); const blob = getBlob(imageUrl); if (blob) { console.log('从AppStore找到Blob,重新创建URL...'); const newUrl = URL.createObjectURL(blob); setCanvasImage(newUrl); } else { // 如果AppStore中也没有,直接设置原URL,让ImageCanvas处理 setCanvasImage(imageUrl); } }); } else { // 非Blob URL直接设置 setCanvasImage(imageUrl); } } }} onMouseEnter={(e) => { // 设置当前悬停的记录 setHoveredRecord({type: 'generation', id: generation.id}); // 优先显示生成结果图像,如果没有生成结果图像则显示参考图像 let imageUrl = null; // 优先使用生成结果图像 if (generation.outputAssets && generation.outputAssets.length > 0) { const asset = generation.outputAssets[0]; if (asset.url) { const uploadedUrl = getUploadedImageUrl(generation, 0); imageUrl = uploadedUrl || asset.url; } } // 如果没有生成结果图像,则使用参考图像 if (!imageUrl && generation.sourceAssets && generation.sourceAssets.length > 0) { // 参考图像在uploadResults中从索引outputAssets.length开始 const outputAssetsCount = generation.outputAssets?.length || 0; const uploadResultIndex = outputAssetsCount; // 第一个参考图像 imageUrl = getUploadedImageUrl(generation, uploadResultIndex) || (generation.sourceAssets[0].url ? generation.sourceAssets[0].url : null); } if (imageUrl) { // 创建图像对象以获取尺寸 const img = new Image(); img.onload = () => { setHoveredImage({ url: imageUrl, title: `生成记录 G${globalIndex + 1}`, width: img.width, height: img.height }); // 传递鼠标位置信息给App组件 if (setPreviewPosition) { setPreviewPosition({ x: e.clientX, y: e.clientY }); } }; img.onerror = (error) => { console.error('图像加载失败:', error); // 如果是Blob URL失效,尝试重新获取 if (imageUrl.startsWith('blob:')) { import('../store/useAppStore').then((module) => { const useAppStore = module.useAppStore; const blob = useAppStore.getState().getBlob(imageUrl); if (blob) { console.log('从AppStore找到Blob,尝试重新创建URL...'); // 重新创建Blob URL const newUrl = URL.createObjectURL(blob); // 更新显示 setHoveredImage({ url: newUrl, title: `生成记录 G${globalIndex + 1}`, width: 0, height: 0 }); // 传递鼠标位置信息给App组件 if (setPreviewPosition) { setPreviewPosition({ x: e.clientX, y: e.clientY }); } // 预加载新URL const newImg = new Image(); newImg.onload = () => { setHoveredImage({ url: newUrl, title: `生成记录 G${globalIndex + 1}`, width: newImg.width, height: newImg.height }); }; newImg.src = newUrl; } else { // 即使图像加载失败,也显示预览 setHoveredImage({ url: imageUrl, title: `生成记录 G${globalIndex + 1}`, width: 0, height: 0 }); // 传递鼠标位置信息给App组件 if (setPreviewPosition) { setPreviewPosition({ x: e.clientX, y: e.clientY }); } } }).catch(err => { console.error('导入AppStore时出错:', err); // 即使图像加载失败,也显示预览 setHoveredImage({ url: imageUrl, title: `生成记录 G${globalIndex + 1}`, width: 0, height: 0 }); // 传递鼠标位置信息给App组件 if (setPreviewPosition) { setPreviewPosition({ x: e.clientX, y: e.clientY }); } }); } else { // 即使图像加载失败,也显示预览 setHoveredImage({ url: imageUrl, title: `生成记录 G${globalIndex + 1}`, width: 0, height: 0 }); // 传递鼠标位置信息给App组件 if (setPreviewPosition) { setPreviewPosition({ x: e.clientX, y: e.clientY }); } } }; img.src = imageUrl; } }} onMouseMove={() => { // 不需要处理鼠标移动事件,因为预览现在在页面中心显示 }} onMouseLeave={() => { // 清除当前悬停的记录 setHoveredRecord(null); setHoveredImage(null); if (setPreviewPosition) { setPreviewPosition(null); } }} > {(() => { // 优先显示生成结果图像,如果没有生成结果图像则显示参考图像 let imageUrl = null; // 优先使用生成结果图像 if (generation.outputAssets && generation.outputAssets.length > 0) { const asset = generation.outputAssets[0]; if (asset.url) { const uploadedUrl = getUploadedImageUrl(generation, 0); imageUrl = uploadedUrl || asset.url; } } // 如果没有生成结果图像,则使用参考图像 if (!imageUrl && generation.sourceAssets && generation.sourceAssets.length > 0) { // 参考图像在uploadResults中从索引outputAssets.length开始 const outputAssetsCount = generation.outputAssets?.length || 0; const uploadResultIndex = outputAssetsCount; // 第一个参考图像 imageUrl = getUploadedImageUrl(generation, uploadResultIndex) || (generation.sourceAssets[0].url ? generation.sourceAssets[0].url : null); } if (imageUrl) { return 生成的变体; } else { return (
); } })()} {/* 变体编号 */}
G{globalIndex + 1}
{/* 悬停时显示的按钮 */} {hoveredRecord && hoveredRecord.type === 'generation' && hoveredRecord.id === generation.id && (
)}
); }); })()} {/* 显示编辑记录 */} {(() => { const sortedEdits = [...filteredEdits].sort((a, b) => b.timestamp - a.timestamp); // 使用之前计算的相同记录列表以确保编号一致 const allRecords = [...[...filteredGenerations].sort((a, b) => b.timestamp - a.timestamp), ...sortedEdits] .sort((a, b) => b.timestamp - a.timestamp); const startIndex = (currentPage - 1) * itemsPerPage; const endIndex = startIndex + itemsPerPage; const paginatedRecords = allRecords.slice(startIndex, endIndex); // 只显示当前页的编辑记录 const paginatedEdits = paginatedRecords.filter(record => sortedEdits.some(edit => edit.id === record.id) ); return paginatedEdits.map((edit: {id: string, sourceAssets?: Array<{url: string}>, outputAssets?: Array<{url: string}>}) => { // 计算全局索引用于显示编号 const globalIndex = allRecords.findIndex(record => record.id === edit.id); return (
{ selectEdit(edit.id); selectGeneration(null); // 设置画布图像为编辑结果图像,而不是参考图像 let imageUrl = null; // 优先使用编辑结果图像 if (edit.outputAssets && edit.outputAssets.length > 0) { const asset = edit.outputAssets[0]; if (asset.url) { const uploadedUrl = getUploadedImageUrl(edit, 0); imageUrl = uploadedUrl || asset.url; } } // 如果没有编辑结果图像,则使用参考图像 if (!imageUrl && edit.sourceAssets && edit.sourceAssets.length > 0) { // 参考图像在uploadResults中从索引outputAssets.length开始 const outputAssetsCount = edit.outputAssets?.length || 0; const uploadResultIndex = outputAssetsCount; // 第一个参考图像 const uploadedUrl = getUploadedImageUrl(edit, uploadResultIndex); if (uploadedUrl) { imageUrl = uploadedUrl; } else if (edit.sourceAssets[0].url) { imageUrl = edit.sourceAssets[0].url; } } if (imageUrl) { // 检查是否是Blob URL并且可能已经失效 if (imageUrl.startsWith('blob:')) { // 预先检查Blob URL是否有效 fetch(imageUrl) .then(response => { if (!response.ok) { // Blob URL失效,尝试从AppStore重新获取 const { getBlob } = useAppStore.getState(); const blob = getBlob(imageUrl); if (blob) { console.log('从AppStore找到Blob,重新创建URL...'); const newUrl = URL.createObjectURL(blob); setCanvasImage(newUrl); } else { // 如果AppStore中也没有,直接设置原URL,让ImageCanvas处理 setCanvasImage(imageUrl); } } else { // Blob URL有效,直接使用 setCanvasImage(imageUrl); } }) .catch(() => { // 网络错误,尝试从AppStore重新获取 const { getBlob } = useAppStore.getState(); const blob = getBlob(imageUrl); if (blob) { console.log('从AppStore找到Blob,重新创建URL...'); const newUrl = URL.createObjectURL(blob); setCanvasImage(newUrl); } else { // 如果AppStore中也没有,直接设置原URL,让ImageCanvas处理 setCanvasImage(imageUrl); } }); } else { // 非Blob URL直接设置 setCanvasImage(imageUrl); } } }} onMouseEnter={(e) => { // 设置当前悬停的记录 setHoveredRecord({type: 'edit', id: edit.id}); // 优先显示编辑结果图像,如果没有编辑结果图像则显示参考图像 let imageUrl = null; // 优先使用编辑结果图像 if (edit.outputAssets && edit.outputAssets.length > 0) { const asset = edit.outputAssets[0]; if (asset.url) { const uploadedUrl = getUploadedImageUrl(edit, 0); imageUrl = uploadedUrl || asset.url; } } // 如果没有编辑结果图像,则使用参考图像 if (!imageUrl && edit.sourceAssets && edit.sourceAssets.length > 0) { // 参考图像在uploadResults中从索引outputAssets.length开始 const outputAssetsCount = edit.outputAssets?.length || 0; const uploadResultIndex = outputAssetsCount; // 第一个参考图像 imageUrl = getUploadedImageUrl(edit, uploadResultIndex) || (edit.sourceAssets[0].url ? edit.sourceAssets[0].url : null); } if (imageUrl) { // 创建图像对象以获取尺寸 const img = new Image(); img.onload = () => { setHoveredImage({ url: imageUrl, title: `编辑记录 E${globalIndex + 1}`, width: img.width, height: img.height }); // 传递鼠标位置信息给App组件 if (setPreviewPosition) { setPreviewPosition({ x: e.clientX, y: e.clientY }); } }; img.onerror = (error) => { console.error('图像加载失败:', error); // 即使图像加载失败,也显示预览 setHoveredImage({ url: imageUrl, title: `编辑记录 E${globalIndex + 1}`, width: 0, height: 0 }); // 传递鼠标位置信息给App组件 if (setPreviewPosition) { setPreviewPosition({ x: e.clientX, y: e.clientY }); } }; img.src = imageUrl; } }} onMouseMove={() => { // 不需要处理鼠标移动事件,因为预览现在在页面中心显示 }} onMouseLeave={() => { // 清除当前悬停的记录 setHoveredRecord(null); setHoveredImage(null); if (setPreviewPosition) { setPreviewPosition(null); } }} > {(() => { // 优先显示编辑结果图像,如果没有编辑结果图像则显示参考图像 let imageUrl = null; // 优先使用编辑结果图像 if (edit.outputAssets && edit.outputAssets.length > 0) { const asset = edit.outputAssets[0]; if (asset.url) { const uploadedUrl = getUploadedImageUrl(edit, 0); imageUrl = uploadedUrl || asset.url; } } // 如果没有编辑结果图像,则使用参考图像 if (!imageUrl && edit.sourceAssets && edit.sourceAssets.length > 0) { // 参考图像在uploadResults中从索引outputAssets.length开始 const outputAssetsCount = edit.outputAssets?.length || 0; const uploadResultIndex = outputAssetsCount; // 第一个参考图像 imageUrl = getUploadedImageUrl(edit, uploadResultIndex) || (edit.sourceAssets[0].url ? edit.sourceAssets[0].url : null); } if (imageUrl) { return 编辑的变体; } else { return (
); } })()} {/* 编辑标签 */}
E{globalIndex + 1}
{/* 悬停时显示的按钮 */} {hoveredRecord && hoveredRecord.type === 'edit' && hoveredRecord.id === edit.id && (
)}
); }); })()}
)}
{/* 分页控件 */} {(() => { // 合并所有记录并排序,然后计算分页 const allRecords = [ ...[...filteredGenerations].sort((a, b) => b.timestamp - a.timestamp), ...[...filteredEdits].sort((a, b) => b.timestamp - a.timestamp) ].sort((a, b) => b.timestamp - a.timestamp); const totalItems = allRecords.length; const totalPages = Math.ceil(totalItems / itemsPerPage); // 只在有多页时显示分页控件 if (totalPages > 1) { return (
第 {currentPage} 页,共 {totalPages} 页
); } return null; })()} {/* 生成详情 */}

详情

{(() => { const gen = filteredGenerations.find(g => g.id === selectedGenerationId) || dbGenerations.find(g => g.id === selectedGenerationId); const selectedEdit = filteredEdits.find(e => e.id === selectedEditId) || dbEdits.find(e => e.id === selectedEditId); if (gen) { return (
提示:

{gen.prompt}

模型: {gen.modelVersion}
{gen.parameters.seed && (
种子: {gen.parameters.seed}
)}
时间: {new Date(gen.timestamp).toLocaleString()}
{/* 上传结果 */} {gen.uploadResults && gen.uploadResults.length > 0 && (
上传结果
{gen.uploadResults.map((result, index) => (
图像 {index + 1}: {result.success ? '成功' : '失败'}
{result.success && result.url && (
{result.url.split('/').pop()}
)} {result.error && (
{result.error}
)}
))}
)} {/* 生成结果图像 */} {gen.outputAssets && gen.outputAssets.length > 0 && (
生成结果
{gen.outputAssets.length} 个生成结果
{gen.outputAssets.slice(0, 4).map((asset: {id: string, url?: string, blobUrl?: string, width: number, height: number}, index: number) => { // 获取上传后的远程链接(如果存在) const uploadedUrl = gen.uploadResults && gen.uploadResults[index] && gen.uploadResults[index].success ? `${gen.uploadResults[index].url}?x-oss-process=image/quality,q_30` : null; // 如果没有上传的URL,则使用asset中的URL const displayUrl = uploadedUrl || asset.url || asset.blobUrl; // 如果URL是blob:开头但已失效,尝试重新创建 if (displayUrl && displayUrl.startsWith('blob:')) { // 检查blob是否仍然有效 const img = new Image(); img.onerror = () => { // Blob URL可能已失效,尝试重新创建 import('../store/useAppStore').then((module) => { const useAppStore = module.useAppStore; const blob = useAppStore.getState().getBlob(displayUrl); if (blob) { const newUrl = URL.createObjectURL(blob); // 更新显示 const imgElement = document.querySelector(`img[src="${displayUrl}"]`); if (imgElement) { imgElement.src = newUrl; } } }); }; img.src = displayUrl; } return (
{ e.stopPropagation(); setPreviewModal({ open: true, imageUrl: displayUrl, title: `生成结果 ${index + 1}`, description: `${asset.width} × ${asset.height}` }); }} > {displayUrl ? ( {`生成结果 { // 如果图像加载失败,尝试重新创建Blob URL if (displayUrl.startsWith('blob:')) { import('../store/useAppStore').then((module) => { const useAppStore = module.useAppStore; const blob = useAppStore.getState().getBlob(displayUrl); if (blob) { const newUrl = URL.createObjectURL(blob); (e.target as HTMLImageElement).src = newUrl; } }); } }} /> ) : (
)}
); })} {gen.outputAssets.length > 4 && (
+{gen.outputAssets.length - 4}
)}
)} {/* 参考图像信息 */} {gen.sourceAssets && gen.sourceAssets.length > 0 && (
参考图像
{gen.sourceAssets.length} 个参考图像
{gen.sourceAssets.slice(0, 4).map((asset: {id: string, url?: string, blobUrl?: string, width: number, height: number}, index: number) => { // 优先使用上传后的远程链接,如果没有则使用asset中的URL // 参考图像在uploadResults中从索引1开始(图像2字段) const uploadResultIndex = 1 + index; const uploadedUrl = gen.uploadResults && gen.uploadResults[uploadResultIndex] && gen.uploadResults[uploadResultIndex].success ? gen.uploadResults[uploadResultIndex].url : null; const displayUrl = uploadedUrl || asset.url || asset.blobUrl; // 如果URL是blob:开头但已失效,尝试重新创建 if (displayUrl && displayUrl.startsWith('blob:')) { // 检查blob是否仍然有效 const img = new Image(); img.onerror = () => { // Blob URL可能已失效,尝试重新创建 import('../store/useAppStore').then((module) => { const useAppStore = module.useAppStore; const blob = useAppStore.getState().getBlob(displayUrl); if (blob) { const newUrl = URL.createObjectURL(blob); // 更新显示 const imgElement = document.querySelector(`img[src="${displayUrl}"]`); if (imgElement) { imgElement.src = newUrl; } } }); }; img.src = displayUrl; } return (
{ e.stopPropagation(); setPreviewModal({ open: true, imageUrl: displayUrl, title: `参考图像 ${index + 1}`, description: `${asset.width} × ${asset.height}` }); }} > {displayUrl ? ( {`参考图像 { // 如果图像加载失败,尝试重新创建Blob URL if (displayUrl.startsWith('blob:')) { import('../store/useAppStore').then((module) => { const useAppStore = module.useAppStore; const blob = useAppStore.getState().getBlob(displayUrl); if (blob) { const newUrl = URL.createObjectURL(blob); (e.target as HTMLImageElement).src = newUrl; } }); } }} /> ) : (
)}
); })} {gen.sourceAssets.length > 4 && (
+{gen.sourceAssets.length - 4}
)}
)}
); } else if (selectedEdit) { const parentGen = filteredGenerations.find(item => item.id === selectedEdit.parentGenerationId) || dbGenerations.find(item => item.id === selectedEdit.parentGenerationId); return (
编辑指令:

{selectedEdit.instruction}

类型: 图像编辑
创建时间: {new Date(selectedEdit.timestamp).toLocaleString()}
{selectedEdit.maskAssetId && (
遮罩: 已应用
)}
{/* 上传结果 */} {selectedEdit.uploadResults && selectedEdit.uploadResults.length > 0 && (
上传结果
{selectedEdit.uploadResults.map((result, index) => (
图像 {index + 1}: {result.success ? '成功' : '失败'}
{result.success && result.url && (
{result.url.split('/').pop()}
)} {result.error && (
{result.error}
)}
))}
)} {/* 编辑结果图像 */} {selectedEdit.outputAssets && selectedEdit.outputAssets.length > 0 && (
编辑结果
{selectedEdit.outputAssets.length} 个编辑结果
{selectedEdit.outputAssets.slice(0, 4).map((asset: {id: string, url?: string, blobUrl?: string, width: number, height: number}, index: number) => { // 获取上传后的远程链接(如果存在) const uploadedUrl = selectedEdit.uploadResults && selectedEdit.uploadResults[index] && selectedEdit.uploadResults[index].success ? selectedEdit.uploadResults[index].url : null; // 如果没有上传的URL,则使用asset中的URL const displayUrl = uploadedUrl || asset.url || asset.blobUrl; // 如果URL是blob:开头但已失效,尝试重新创建 if (displayUrl && displayUrl.startsWith('blob:')) { // 检查blob是否仍然有效 const img = new Image(); img.onerror = () => { // Blob URL可能已失效,尝试重新创建 import('../store/useAppStore').then((module) => { const useAppStore = module.useAppStore; const blob = useAppStore.getState().getBlob(displayUrl); if (blob) { const newUrl = URL.createObjectURL(blob); // 更新显示 const imgElement = document.querySelector(`img[src="${displayUrl}"]`); if (imgElement) { imgElement.src = newUrl; } } }); }; img.src = displayUrl; } return (
{ e.stopPropagation(); setPreviewModal({ open: true, imageUrl: displayUrl, title: `编辑结果 ${index + 1}`, description: `${asset.width} × ${asset.height}` }); }} > {displayUrl ? ( {`编辑结果 { // 如果图像加载失败,尝试重新创建Blob URL if (displayUrl.startsWith('blob:')) { import('../store/useAppStore').then((module) => { const useAppStore = module.useAppStore; const blob = useAppStore.getState().getBlob(displayUrl); if (blob) { const newUrl = URL.createObjectURL(blob); (e.target as HTMLImageElement).src = newUrl; } }); } }} /> ) : (
)}
); })} {selectedEdit.outputAssets.length > 4 && (
+{selectedEdit.outputAssets.length - 4}
)}
)} {/* 编辑参考图像 */} {selectedEdit.sourceAssets && selectedEdit.sourceAssets.length > 0 && (
编辑参考图像
{selectedEdit.sourceAssets.length} 个参考图像
{selectedEdit.sourceAssets.slice(0, 4).map((asset: {id: string, url?: string, blobUrl?: string, width: number, height: number}, index: number) => { // 优先使用上传后的远程链接,如果没有则使用asset中的URL // 参考图像在uploadResults中从索引1开始(图像2字段) const uploadResultIndex = 1 + index; const uploadedUrl = selectedEdit.uploadResults && selectedEdit.uploadResults[uploadResultIndex] && selectedEdit.uploadResults[uploadResultIndex].success ? selectedEdit.uploadResults[uploadResultIndex].url : null; const displayUrl = uploadedUrl || asset.url || asset.blobUrl; // 如果URL是blob:开头但已失效,尝试重新创建 if (displayUrl && displayUrl.startsWith('blob:')) { // 检查blob是否仍然有效 const img = new Image(); img.onerror = () => { // Blob URL可能已失效,尝试重新创建 import('../store/useAppStore').then((module) => { const useAppStore = module.useAppStore; const blob = useAppStore.getState().getBlob(displayUrl); if (blob) { const newUrl = URL.createObjectURL(blob); // 更新显示 const imgElement = document.querySelector(`img[src="${displayUrl}"]`); if (imgElement) { imgElement.src = newUrl; } } }); }; img.src = displayUrl; } return (
{ e.stopPropagation(); setPreviewModal({ open: true, imageUrl: displayUrl, title: `编辑参考图像 ${index + 1}`, description: `${asset.width} × ${asset.height}` }); }} > {displayUrl ? ( {`编辑参考图像 { // 如果图像加载失败,尝试重新创建Blob URL if (displayUrl.startsWith('blob:')) { import('../store/useAppStore').then((module) => { const useAppStore = module.useAppStore; const blob = useAppStore.getState().getBlob(displayUrl); if (blob) { const newUrl = URL.createObjectURL(blob); (e.target as HTMLImageElement).src = newUrl; } }); } }} /> ) : (
)}
); })} {selectedEdit.sourceAssets.length > 4 && (
+{selectedEdit.sourceAssets.length - 4}
)}
)} {/* 原始生成参考 */} {parentGen && (
原始生成
基于: G{dbGenerations.findIndex(item => item.id === parentGen.id) + 1}
{/* 显示原始生成的参考图像 */} {parentGen.sourceAssets && parentGen.sourceAssets.length > 0 && (
原始参考图像:
{parentGen.sourceAssets.slice(0, 4).map((asset: {id: string, url?: string, blobUrl?: string, width: number, height: number}, index: number) => { // 优先使用上传后的远程链接,如果没有则使用asset中的URL // 参考图像在uploadResults中从索引1开始(图像2字段) const uploadResultIndex = 1 + index; const uploadedUrl = parentGen.uploadResults && parentGen.uploadResults[uploadResultIndex] && parentGen.uploadResults[uploadResultIndex].success ? parentGen.uploadResults[uploadResultIndex].url : null; const displayUrl = uploadedUrl || asset.url || asset.blobUrl; // 如果URL是blob:开头但已失效,尝试重新创建 if (displayUrl && displayUrl.startsWith('blob:')) { // 检查blob是否仍然有效 const img = new Image(); img.onerror = () => { // Blob URL可能已失效,尝试重新创建 import('../store/useAppStore').then((module) => { const useAppStore = module.useAppStore; const blob = useAppStore.getState().getBlob(displayUrl); if (blob) { const newUrl = URL.createObjectURL(blob); // 更新显示 const imgElement = document.querySelector(`img[src="${displayUrl}"]`); if (imgElement) { imgElement.src = newUrl; } } }); }; img.src = displayUrl; } return (
{ e.stopPropagation(); setPreviewModal({ open: true, imageUrl: displayUrl, title: `原始参考图像 ${index + 1}`, description: `${asset.width} × ${asset.height}` }); }} > {displayUrl ? ( {`原始参考图像 { // 如果图像加载失败,尝试重新创建Blob URL if (displayUrl.startsWith('blob:')) { import('../store/useAppStore').then((module) => { const useAppStore = module.useAppStore; const blob = useAppStore.getState().getBlob(displayUrl); if (blob) { const newUrl = URL.createObjectURL(blob); (e.target as HTMLImageElement).src = newUrl; } }); } }} /> ) : (
)}
); })} {parentGen.sourceAssets.length > 4 && (
+{parentGen.sourceAssets.length - 4}
)}
)}
)}
); } else { return (

选择一个记录以查看详细信息

); } })()}
{/* 图像预览模态框 */} setPreviewModal(prev => ({ ...prev, open }))} imageUrl={previewModal.imageUrl} title={previewModal.title} description={previewModal.description} /> {/* 删除确认对话框 */} {deleteConfirm.open && (

确认删除

{deleteConfirm.count > 1 ? `确定要删除这 ${deleteConfirm.count} 条历史记录吗?此操作无法撤销。` : '确定要删除这条历史记录吗?此操作无法撤销。'}

)}
); };