import { createSignal, For, Show, createMemo } from 'solid-js'; import type { PageData } from './hooks/usePDFExport'; import type { CardPath } from '../../plotcutter'; import type { CardShape } from '../../plotcutter'; import { getCardShapePoints, calculateCenter, contourToSvgPath } from '../../plotcutter'; import { generateTravelPaths, travelPathsToSvg } from '../../plotcutter'; import { pts2plotter } from '../../plotcutter'; export interface PltPreviewProps { pages: PageData[]; cardWidth: number; cardHeight: number; shape: CardShape; bleed: number; cornerRadius: number; onClose: () => void; } /** * 生成卡片切割路径 */ function generateCardPaths( pages: PageData[], cardWidth: number, cardHeight: number, shape: CardShape, bleed: number, cornerRadius: number, a4Height: number ): CardPath[] { const cardPaths: CardPath[] = []; let pathIndex = 0; // 计算切割尺寸(排版尺寸减去出血) const cutWidth = cardWidth - bleed * 2; const cutHeight = cardHeight - bleed * 2; for (const page of pages) { for (const card of page.cards) { if (card.side !== 'front') continue; // 生成形状轮廓点(相对于卡片左下角) const shapePoints = getCardShapePoints(shape, cutWidth, cutHeight, cornerRadius); // 平移到页面坐标并翻转 Y 轴 const pagePoints = shapePoints.map(([x, y]) => [ card.x + bleed + x, a4Height - (card.y + bleed + y) ] as [number, number]); const center = calculateCenter(pagePoints); const pathD = contourToSvgPath(pagePoints); // 起点和终点(对于闭合路径是同一点) const startPoint = pagePoints[0]; const endPoint = pagePoints[pagePoints.length - 1]; cardPaths.push({ pageIndex: page.pageIndex, cardIndex: pathIndex++, points: pagePoints, centerX: center.x, centerY: center.y, pathD, startPoint, endPoint }); } } return cardPaths; } /** * PLT 预览组件 - 显示切割路径预览 */ export function PltPreview(props: PltPreviewProps) { const a4Width = 297; // 横向 A4 const a4Height = 210; // 使用传入的圆角值,但也允许用户修改 const [cornerRadius, setCornerRadius] = createSignal(props.cornerRadius); // 生成所有卡片路径 const cardPaths = createMemo(() => generateCardPaths( props.pages, props.cardWidth, props.cardHeight, props.shape, props.bleed, cornerRadius(), a4Height ) ); // 生成空走路径 const travelPathD = createMemo(() => { const travelPaths = generateTravelPaths(cardPaths(), a4Height); return travelPathsToSvg(travelPaths); }); // 生成 HPGL 代码用于下载 const plotterCode = createMemo(() => { const allPaths = cardPaths().map(p => p.points); return allPaths.length > 0 ? pts2plotter(allPaths, a4Width, a4Height, 1) : ''; }); const handleDownload = () => { if (!plotterCode()) { alert('没有可导出的卡片'); return; } const blob = new Blob([plotterCode()], { type: 'application/vnd.hp-HPGL' }); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = `deck-export-${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.plt`; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); }; const handleCornerRadiusChange = (e: Event) => { const target = e.target as HTMLInputElement; setCornerRadius(Number(target.value)); }; return (