fix: switch canvas zip download to native form submission
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-02-19 22:10:31 +08:00
parent e344a6db73
commit 056514f167
2 changed files with 36 additions and 53 deletions

View File

@ -103,7 +103,21 @@ export async function POST(request: NextRequest) {
return NextResponse.json({ success: false, error: "未登录" }, { status: 401 }); return NextResponse.json({ success: false, error: "未登录" }, { status: 401 });
} }
const body = await request.json().catch(() => ({})); let body: Record<string, unknown> = {};
const contentType = request.headers.get("content-type") || "";
if (contentType.includes("application/json")) {
body = (await request.json().catch(() => ({}))) as Record<string, unknown>;
} else {
const formData = await request.formData().catch(() => null);
const payload = formData?.get("payload");
if (typeof payload === "string" && payload.trim()) {
try {
body = (JSON.parse(payload) as Record<string, unknown>) || {};
} catch (_error) {
body = {};
}
}
}
const requestOrigin = getRequestOrigin(request); const requestOrigin = getRequestOrigin(request);
const files = toDownloadItems((body as any)?.files, requestOrigin); const files = toDownloadItems((body as any)?.files, requestOrigin);
const folderName = sanitizeFolderName(String((body as any)?.folderName || "")); const folderName = sanitizeFolderName(String((body as any)?.folderName || ""));

View File

@ -36,18 +36,6 @@ function isNodeInViewport(
); );
} }
function downloadBlob(blob: Blob, filename: string): void {
const link = document.createElement("a");
const objectUrl = URL.createObjectURL(blob);
link.href = objectUrl;
link.download = filename;
link.rel = "noopener noreferrer";
document.body.appendChild(link);
link.click();
link.remove();
window.setTimeout(() => URL.revokeObjectURL(objectUrl), 1500);
}
export function CanvasWorkspace() { export function CanvasWorkspace() {
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
const [isPanning, setIsPanning] = useState(false); const [isPanning, setIsPanning] = useState(false);
@ -563,51 +551,32 @@ export function CanvasWorkspace() {
} }
setIsDownloadSubmitting(true); setIsDownloadSubmitting(true);
let timeoutId: number | null = null;
try { try {
const controller = new AbortController(); const form = document.createElement("form");
timeoutId = window.setTimeout(() => controller.abort(), 120000); form.method = "POST";
const response = await fetch("/api/canvas/download-zip", { form.action = "/api/canvas/download-zip";
method: "POST", form.style.display = "none";
headers: {
"Content-Type": "application/json", const payloadInput = document.createElement("input");
}, payloadInput.type = "hidden";
signal: controller.signal, payloadInput.name = "payload";
body: JSON.stringify({ payloadInput.value = JSON.stringify({
folderName, folderName,
files, files,
}),
}); });
form.appendChild(payloadInput);
if (!response.ok) { document.body.appendChild(form);
const data = await response.json().catch(() => ({})); form.submit();
toast.error(data?.error || "打包失败,请稍后重试"); form.remove();
return;
}
const zipBlob = await response.blob(); toast.success("已开始打包下载,请留意浏览器下载栏");
downloadBlob(zipBlob, `${folderName}.zip`); } catch (_error) {
toast.error("下载失败,请稍后重试");
const successCount = Number(response.headers.get("X-Download-Success-Count") || "0");
const failedCount = Number(response.headers.get("X-Download-Failed-Count") || "0");
const totalCount = files.length;
if (failedCount > 0) {
toast.warning(`已打包 ${successCount} 张,失败 ${failedCount} 张`);
} else {
toast.success(`已下载压缩包,包含 ${successCount || totalCount} 张图片`);
}
} catch (error) {
if (error instanceof DOMException && error.name === "AbortError") {
toast.error("打包超时,请减少图片数量后重试");
} else {
toast.error("下载失败,请稍后重试");
}
} finally { } finally {
if (timeoutId) { window.setTimeout(() => {
window.clearTimeout(timeoutId); setIsDownloadSubmitting(false);
} }, 800);
setIsDownloadSubmitting(false);
} }
}, [isDownloadSubmitting, selectedImageNodes]); }, [isDownloadSubmitting, selectedImageNodes]);