Your Name 21a2254428
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
feat: expand canvas batch and image workflows
2026-05-08 16:24:28 +08:00

98 lines
3.3 KiB
TypeScript

"use client";
import { useParams, useRouter } from "next/navigation";
import { useCallback } from "react";
import { toast } from "sonner";
import { SceneFusionView } from "@/components/scene-fusion-view";
import { canvasService } from "@/services/canvas";
import { canvasSelectors, useCanvasStore } from "@/store/canvas";
export default function CanvasBatchProcessingPage() {
const router = useRouter();
const routeParams = useParams();
const id = String(routeParams?.id || "");
const viewport = useCanvasStore(canvasSelectors.viewport);
const selectedNodeIds = useCanvasStore(canvasSelectors.selectedNodeIds);
const nodes = useCanvasStore(canvasSelectors.nodes);
const addNode = useCanvasStore((state) => state.addNode);
const selectNodes = useCanvasStore((state) => state.selectNodes);
const getCanvasState = useCanvasStore((state) => state.getCanvasState);
const selectedImageNode =
selectedNodeIds.length === 1
? nodes.find(
(node) => node.id === selectedNodeIds[0] && node.type === "image"
)
: null;
const handleBack = useCallback(() => {
router.push(`/canvas/${id}`);
}, [id, router]);
const handleBatchAddToCanvas = useCallback(
async (imageUrls: string[]) => {
if (!imageUrls || imageUrls.length === 0) {
toast.error("没有可添加到画布的图片");
return;
}
const columns = Math.min(4, imageUrls.length);
const viewportX = viewport.x || 0;
const viewportY = viewport.y || 0;
const viewportZoom = viewport.zoom || 1;
const stageWidth = typeof window !== "undefined" ? window.innerWidth : 1440;
const stageHeight = typeof window !== "undefined" ? window.innerHeight : 900;
const startX = (stageWidth * 0.22 - viewportX) / viewportZoom;
const startY = (stageHeight * 0.18 - viewportY) / viewportZoom;
const createdNodeIds: string[] = [];
for (const [index, imageUrl] of imageUrls.entries()) {
const x = startX + (index % columns) * 320;
const y = startY + Math.floor(index / columns) * 320;
const nodeId = addNode({
type: "image",
position: { x, y },
size: { width: 300, height: 300 },
data: {
src: imageUrl,
status: "completed",
title: `批量结果-${index + 1}`,
prompt: "批量处理结果",
},
connections: [],
});
createdNodeIds.push(nodeId);
}
if (createdNodeIds.length > 0) {
selectNodes(createdNodeIds);
}
try {
await canvasService.saveCanvasState(id, getCanvasState());
} catch (error) {
console.error("[CanvasBatchProcessingPage] 保存批量处理结果失败:", error);
}
},
[addNode, getCanvasState, id, selectNodes, viewport.x, viewport.y, viewport.zoom]
);
return (
<div className="h-dvh w-full overflow-hidden bg-background">
<SceneFusionView
canvasId={id}
initialProductImage={
selectedImageNode ? String((selectedImageNode.data as any)?.src || "") : null
}
initialProductName={
selectedImageNode ? String((selectedImageNode.data as any)?.title || "") : ""
}
onBack={handleBack}
onBatchAddToCanvas={handleBatchAddToCanvas}
persistenceKey={id ? `canvas-scene-fusion:${id}` : null}
/>
</div>
);
}