fix: improve image editor upload fallback
This commit is contained in:
parent
82162f8936
commit
593a00cebc
@ -190,18 +190,92 @@ export function ImageAnnotator({
|
||||
}
|
||||
};
|
||||
|
||||
const readUploadErrorMessage = useCallback(async (response: Response) => {
|
||||
try {
|
||||
const payload = await response.clone().json();
|
||||
return String(payload?.details || payload?.error || "").trim() || "上传失败,请重试";
|
||||
} catch {
|
||||
return `上传失败(${response.status})`;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const resetEditorStateForNewImage = useCallback(() => {
|
||||
setProcessedImageUrl(null);
|
||||
setProcessedImageBase64(null);
|
||||
setProcessType(null);
|
||||
setActions([]);
|
||||
setCurrentAction(null);
|
||||
setTextInput("");
|
||||
setTextPosition(null);
|
||||
setIsResizeMode(false);
|
||||
}, []);
|
||||
|
||||
const loadImageFromFile = useCallback(
|
||||
async (file: File) => {
|
||||
revokeObjectUrl();
|
||||
const objectUrl = URL.createObjectURL(file);
|
||||
objectUrlRef.current = objectUrl;
|
||||
return await createImageElement(objectUrl, false);
|
||||
},
|
||||
[createImageElement, revokeObjectUrl]
|
||||
);
|
||||
|
||||
// 上传图片到服务器获取 URL 的辅助函数
|
||||
const uploadImageFile = async (file: File): Promise<string> => {
|
||||
const uploadImageFile = async (file: File): Promise<{ url: string; assetId?: string | null }> => {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
const response = await fetchUploadWithRetry(formData);
|
||||
if (!response.ok) {
|
||||
throw new Error("上传失败");
|
||||
throw new Error(await readUploadErrorMessage(response));
|
||||
}
|
||||
const result = await response.json();
|
||||
return result.url;
|
||||
if (!result?.url) {
|
||||
throw new Error("上传成功,但未返回可用图片地址");
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
const applyUploadedFile = useCallback(
|
||||
async (file: File) => {
|
||||
if (!file.type.startsWith("image/")) {
|
||||
throw new Error("请上传图片文件");
|
||||
}
|
||||
if (file.size > 50 * 1024 * 1024) {
|
||||
throw new Error("图片大小不能超过 50MB");
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
toast.info("正在上传图片...");
|
||||
|
||||
try {
|
||||
const localPreviewPromise = loadImageFromFile(file);
|
||||
const uploadResult = await uploadImageFile(file);
|
||||
|
||||
resetEditorStateForNewImage();
|
||||
setOriginalImageUrl(uploadResult.url);
|
||||
|
||||
try {
|
||||
const localImage = await localPreviewPromise;
|
||||
setImage(localImage);
|
||||
} catch (previewError) {
|
||||
console.warn("[ImageAnnotator] Local preview failed, fallback to uploaded url:", previewError);
|
||||
const uploadedImage = await loadImageFromSource(uploadResult.url);
|
||||
setImage(uploadedImage);
|
||||
}
|
||||
|
||||
toast.success("图片上传成功");
|
||||
} catch (error) {
|
||||
console.error("[ImageAnnotator] 上传图片失败:", error);
|
||||
const message = error instanceof Error ? error.message : "上传失败,请重试";
|
||||
toast.error(message);
|
||||
throw error;
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
},
|
||||
[loadImageFromFile, loadImageFromSource, resetEditorStateForNewImage]
|
||||
);
|
||||
|
||||
// 处理拖拽上传 - 先上传到服务器获取URL
|
||||
const handleDrop = useCallback(async (e: React.DragEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
@ -209,39 +283,11 @@ export function ImageAnnotator({
|
||||
|
||||
const files = e.dataTransfer.files;
|
||||
if (files.length > 0) {
|
||||
const file = files[0];
|
||||
if (!file.type.startsWith('image/')) {
|
||||
toast.error("请上传图片文件");
|
||||
return;
|
||||
}
|
||||
if (file.size > 50 * 1024 * 1024) {
|
||||
toast.error("图片大小不能超过 50MB");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
toast.info("正在上传图片...");
|
||||
const imageUrl = await uploadImageFile(file);
|
||||
|
||||
setOriginalImageUrl(imageUrl);
|
||||
setProcessedImageUrl(null);
|
||||
setProcessedImageBase64(null);
|
||||
setProcessType(null);
|
||||
setActions([]);
|
||||
setCurrentAction(null);
|
||||
|
||||
const img = await loadImageFromSource(imageUrl);
|
||||
setImage(img);
|
||||
setIsLoading(false);
|
||||
toast.success("图片上传成功");
|
||||
} catch (error) {
|
||||
console.error("上传图片失败:", error);
|
||||
toast.error("上传失败,请重试");
|
||||
setIsLoading(false);
|
||||
}
|
||||
await applyUploadedFile(files[0]);
|
||||
} catch {}
|
||||
}
|
||||
}, [loadImageFromSource]);
|
||||
}, [applyUploadedFile]);
|
||||
|
||||
const handleDragOver = useCallback((e: React.DragEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
@ -260,33 +306,9 @@ export function ImageAnnotator({
|
||||
if (item.type.startsWith('image/')) {
|
||||
const file = item.getAsFile();
|
||||
if (!file) continue;
|
||||
|
||||
if (file.size > 50 * 1024 * 1024) {
|
||||
toast.error("图片大小不能超过 50MB");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
toast.info("正在上传图片...");
|
||||
const imageUrl = await uploadImageFile(file);
|
||||
|
||||
setOriginalImageUrl(imageUrl);
|
||||
setProcessedImageUrl(null);
|
||||
setProcessedImageBase64(null);
|
||||
setProcessType(null);
|
||||
setActions([]);
|
||||
setCurrentAction(null);
|
||||
|
||||
const img = await loadImageFromSource(imageUrl);
|
||||
setImage(img);
|
||||
setIsLoading(false);
|
||||
toast.success("图片上传成功");
|
||||
} catch (error) {
|
||||
console.error("上传图片失败:", error);
|
||||
toast.error("上传失败,请重试");
|
||||
setIsLoading(false);
|
||||
}
|
||||
await applyUploadedFile(file);
|
||||
} catch {}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -294,7 +316,7 @@ export function ImageAnnotator({
|
||||
|
||||
document.addEventListener('paste', handlePaste);
|
||||
return () => document.removeEventListener('paste', handlePaste);
|
||||
}, [loadImageFromSource, mounted, originalImageUrl]);
|
||||
}, [applyUploadedFile, mounted, originalImageUrl]);
|
||||
|
||||
// 尺寸调整相关状态
|
||||
const [isResizeMode, setIsResizeMode] = useState(initialResizeMode);
|
||||
@ -398,34 +420,9 @@ export function ImageAnnotator({
|
||||
const handleImageUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (file) {
|
||||
if (file.size > 50 * 1024 * 1024) {
|
||||
toast.error("图片大小不能超过 50MB");
|
||||
e.target.value = "";
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
toast.info("正在上传图片...");
|
||||
const imageUrl = await uploadImageFile(file);
|
||||
|
||||
setOriginalImageUrl(imageUrl);
|
||||
// 重置状态
|
||||
setProcessedImageUrl(null);
|
||||
setProcessedImageBase64(null);
|
||||
setProcessType(null);
|
||||
setActions([]);
|
||||
setCurrentAction(null);
|
||||
|
||||
const img = await loadImageFromSource(imageUrl);
|
||||
setImage(img);
|
||||
setIsLoading(false);
|
||||
toast.success("图片上传成功");
|
||||
} catch (error) {
|
||||
console.error("上传图片失败:", error);
|
||||
toast.error("上传失败,请重试");
|
||||
setIsLoading(false);
|
||||
}
|
||||
await applyUploadedFile(file);
|
||||
} catch {}
|
||||
}
|
||||
// 重置 input
|
||||
e.target.value = "";
|
||||
@ -1369,10 +1366,13 @@ export function ImageAnnotator({
|
||||
const uploadResponse = await fetchUploadWithRetry(formData);
|
||||
|
||||
if (!uploadResponse.ok) {
|
||||
throw new Error("上传失败");
|
||||
throw new Error(await readUploadErrorMessage(uploadResponse));
|
||||
}
|
||||
|
||||
const uploadResult = await uploadResponse.json();
|
||||
if (!uploadResult?.url) {
|
||||
throw new Error("上传成功,但未返回可用图片地址");
|
||||
}
|
||||
return uploadResult.url;
|
||||
} catch (error) {
|
||||
console.error("上传图片失败:", error);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user