问题修复

This commit is contained in:
2025-09-20 00:38:35 +08:00
parent 480d8cce46
commit af2058f752
5 changed files with 397 additions and 33 deletions

View File

@@ -630,16 +630,76 @@ export const HistoryPanel: React.FC<{
};
img.onerror = (error) => {
console.error('图像加载失败:', error);
// 即使图像加载失败,也显示预览
setHoveredImage({
url: imageUrl,
title: `生成记录 G${globalIndex + 1}`,
width: 0,
height: 0
});
// 传递鼠标位置信息给App组件
if (setPreviewPosition) {
setPreviewPosition({ x: e.clientX, y: e.clientY });
// 如果是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;
@@ -1026,7 +1086,30 @@ export const HistoryPanel: React.FC<{
? `${gen.uploadResults[index].url}?x-oss-process=image/quality,q_30`
: null;
const displayUrl = uploadedUrl || asset.url;
// 如果没有上传的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 (
<div
@@ -1042,11 +1125,30 @@ export const HistoryPanel: React.FC<{
});
}}
>
<img
src={displayUrl}
alt={`生成结果 ${index + 1}`}
className="w-full h-full object-cover"
/>
{displayUrl ? (
<img
src={displayUrl}
alt={`生成结果 ${index + 1}`}
className="w-full h-full object-cover"
onError={(e) => {
// 如果图像加载失败尝试重新创建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;
}
});
}
}}
/>
) : (
<div className="w-full h-full bg-gray-100 flex items-center justify-center">
<ImageIcon className="h-4 w-4 text-gray-400" />
</div>
)}
</div>
);
})}
@@ -1074,11 +1176,36 @@ export const HistoryPanel: React.FC<{
const fullGen = dbGenerations.find(item => item.id === gen.id) || gen;
const outputAssetsCount = fullGen.outputAssets?.length || 0;
const uploadedUrl = gen.uploadResults && gen.uploadResults[outputAssetsCount + index] && gen.uploadResults[outputAssetsCount + index].success
? `${gen.uploadResults[outputAssetsCount + index].url}?x-oss-process=image/quality,q_30`
// 确保索引在有效范围内
const uploadResultIndex = outputAssetsCount + index;
const uploadedUrl = fullGen.uploadResults && fullGen.uploadResults[uploadResultIndex] && fullGen.uploadResults[uploadResultIndex].success
? `${fullGen.uploadResults[uploadResultIndex].url}?x-oss-process=image/quality,q_30`
: null;
const displayUrl = uploadedUrl || asset.url;
// 如果没有上传的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 (
<div
@@ -1094,11 +1221,30 @@ export const HistoryPanel: React.FC<{
});
}}
>
<img
src={displayUrl}
alt={`参考图像 ${index + 1}`}
className="w-full h-full object-cover"
/>
{displayUrl ? (
<img
src={displayUrl}
alt={`参考图像 ${index + 1}`}
className="w-full h-full object-cover"
onError={(e) => {
// 如果图像加载失败尝试重新创建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;
}
});
}
}}
/>
) : (
<div className="w-full h-full bg-gray-100 flex items-center justify-center">
<ImageIcon className="h-4 w-4 text-gray-400" />
</div>
)}
</div>
);
})}
@@ -1166,6 +1312,95 @@ export const HistoryPanel: React.FC<{
</div>
)}
{/* 编辑结果图像 */}
{selectedEdit.outputAssets && selectedEdit.outputAssets.length > 0 && (
<div className="pt-2 border-t border-gray-200">
<h5 className="text-xs font-medium text-gray-500 mb-2"></h5>
<div className="text-xs text-gray-600 mb-2">
{selectedEdit.outputAssets.length}
</div>
<div className="flex flex-wrap gap-2">
{selectedEdit.outputAssets.slice(0, 4).map((asset: any, index: number) => {
// 获取上传后的远程链接(如果存在)
const uploadedUrl = selectedEdit.uploadResults && selectedEdit.uploadResults[index] && selectedEdit.uploadResults[index].success
? `${selectedEdit.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 (
<div
key={asset.id}
className="relative w-16 h-16 rounded border overflow-hidden cursor-pointer hover:ring-2 hover:ring-yellow-400"
onClick={(e) => {
e.stopPropagation();
setPreviewModal({
open: true,
imageUrl: displayUrl,
title: `编辑结果 ${index + 1}`,
description: `${asset.width} × ${asset.height}`
});
}}
>
{displayUrl ? (
<img
src={displayUrl}
alt={`编辑结果 ${index + 1}`}
className="w-full h-full object-cover"
onError={(e) => {
// 如果图像加载失败尝试重新创建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;
}
});
}
}}
/>
) : (
<div className="w-full h-full bg-gray-100 flex items-center justify-center">
<ImageIcon className="h-4 w-4 text-gray-400" />
</div>
)}
</div>
);
})}
{selectedEdit.outputAssets.length > 4 && (
<div className="w-16 h-16 rounded border flex items-center justify-center bg-gray-100 text-xs text-gray-500">
+{selectedEdit.outputAssets.length - 4}
</div>
)}
</div>
</div>
)}
{/* 原始生成参考 */}
{parentGen && (
<div className="pt-2 border-t border-gray-200">
@@ -1184,10 +1419,37 @@ export const HistoryPanel: React.FC<{
// 获取上传后的远程链接(如果存在)
// 参考图像在uploadResults中从索引outputAssets.length开始
const outputAssetsCount = parentGen.outputAssets?.length || 0;
const uploadedUrl = parentGen.uploadResults && parentGen.uploadResults[outputAssetsCount + index] && parentGen.uploadResults[outputAssetsCount + index].success
? `${parentGen.uploadResults[outputAssetsCount + index].url}?x-oss-process=image/quality,q_30`
// 确保索引在有效范围内
const uploadResultIndex = outputAssetsCount + index;
const uploadedUrl = parentGen.uploadResults && parentGen.uploadResults[uploadResultIndex] && parentGen.uploadResults[uploadResultIndex].success
? `${parentGen.uploadResults[uploadResultIndex].url}?x-oss-process=image/quality,q_30`
: null;
const displayUrl = uploadedUrl || asset.url;
// 如果没有上传的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 (
<div
@@ -1203,11 +1465,30 @@ export const HistoryPanel: React.FC<{
});
}}
>
<img
src={displayUrl}
alt={`原始参考图像 ${index + 1}`}
className="w-full h-full object-cover"
/>
{displayUrl ? (
<img
src={displayUrl}
alt={`原始参考图像 ${index + 1}`}
className="w-full h-full object-cover"
onError={(e) => {
// 如果图像加载失败尝试重新创建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;
}
});
}
}}
/>
) : (
<div className="w-full h-full bg-gray-100 flex items-center justify-center">
<ImageIcon className="h-4 w-4 text-gray-400" />
</div>
)}
</div>
);
})}

View File

@@ -119,6 +119,23 @@ export const ImageCanvas: React.FC = () => {
.then(response => {
if (!response.ok) {
console.error('Blob URL无法访问:', response.status, response.statusText);
// 尝试从AppStore重新获取Blob并创建新的URL
import('../store/useAppStore').then((module) => {
const useAppStore = module.useAppStore;
const blob = useAppStore.getState().getBlob(canvasImage);
if (blob) {
console.log('从AppStore找到Blob尝试重新创建URL...');
// 重新创建Blob URL并重试加载
const newUrl = URL.createObjectURL(blob);
console.log('创建新的Blob URL:', newUrl);
// 更新canvasImage为新的URL
useAppStore.getState().setCanvasImage(newUrl);
} else {
console.error('AppStore中未找到Blob');
}
}).catch(err => {
console.error('导入AppStore时出错:', err);
});
} else {
console.log('Blob URL可以访问');
}

View File

@@ -69,6 +69,27 @@ export const PromptComposer: React.FC = () => {
const blob = getBlob(img);
if (blob) {
referenceImageBlobs.push(blob);
} else {
// 如果在AppStore中找不到Blob尝试重新创建
try {
const response = await fetch(img);
if (response.ok) {
const blob = await response.blob();
// 重新添加到AppStore
const newUrl = useAppStore.getState().addBlob(blob);
referenceImageBlobs.push(blob);
// 更新uploadedImages中的URL
const index = uploadedImages.indexOf(img);
if (index !== -1) {
const newImages = [...uploadedImages];
newImages[index] = newUrl;
useAppStore.getState().clearUploadedImages();
newImages.forEach(imageUrl => useAppStore.getState().addUploadedImage(imageUrl));
}
}
} catch (error) {
console.warn('无法重新获取参考图像:', img, error);
}
}
} else {
// 从URL获取Blob

View File

@@ -275,6 +275,34 @@ export const useImageEditing = () => {
const blob = useAppStore.getState().getBlob(img);
if (blob) {
referenceImageBlobs.push(blob);
} else {
// 如果在AppStore中找不到Blob尝试重新获取
try {
const response = await fetch(img);
if (response.ok) {
const blob = await response.blob();
referenceImageBlobs.push(blob);
// 重新添加到AppStore
const newUrl = useAppStore.getState().addBlob(blob);
// 更新editReferenceImages中的URL
const index = editReferenceImages.indexOf(img);
if (index !== -1) {
const { removeEditReferenceImage, addEditReferenceImage } = useAppStore.getState();
removeEditReferenceImage(index);
// 重新添加所有图像以保持顺序
const currentImages = [...editReferenceImages];
currentImages[index] = newUrl;
// 清空并重新添加
for (let i = 0; i < currentImages.length; i++) {
if (i < 2) { // 最多2张参考图像
addEditReferenceImage(currentImages[i]);
}
}
}
}
} catch (error) {
console.warn('无法重新获取参考图像:', img, error);
}
}
} else if (img.includes('base64,')) {
// 从base64数据创建Blob

View File

@@ -637,8 +637,25 @@ export const useAppStore = create<AppState>()(
const isUsedInUploads = state.uploadedImages.includes(url);
const isUsedInEdits = state.editReferenceImages.includes(url);
// 检查是否是历史记录中的参考图像
const isUsedAsReference = state.currentProject && (
state.currentProject.generations.some(gen =>
gen.sourceAssets.some(asset => asset.blobUrl === url)
) ||
state.currentProject.edits.some(edit =>
(edit.maskReferenceAssetBlobUrl === url)
)
);
// 检查是否是当前编辑操作中的参考图像
const isUsedInCurrentEdit = state.editReferenceImages.includes(url);
// 检查是否是当前生成操作中的参考图像
const isUsedInCurrentGeneration = state.uploadedImages.includes(url);
// 如果Blob没有被使用则清理它
if (!isUsedInProject && !isUsedInCanvas && !isUsedInUploads && !isUsedInEdits) {
// 但保留仍在作为参考图像使用的Blob
if (!isUsedInProject && !isUsedInCanvas && !isUsedInUploads && !isUsedInEdits && !isUsedAsReference && !isUsedInCurrentEdit && !isUsedInCurrentGeneration) {
URL.revokeObjectURL(url);
const newBlobStore = new Map(state.blobStore);
newBlobStore.delete(url);