From 984b8aa1c84a00a28469f01709bd382c0a214d46 Mon Sep 17 00:00:00 2001 From: hypercross Date: Fri, 13 Mar 2026 17:42:51 +0800 Subject: [PATCH] fix: double side printing --- src/components/md-deck/hooks/usePageLayout.ts | 92 ++++++++++--------- 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/src/components/md-deck/hooks/usePageLayout.ts b/src/components/md-deck/hooks/usePageLayout.ts index 940ffd4..eabcf41 100644 --- a/src/components/md-deck/hooks/usePageLayout.ts +++ b/src/components/md-deck/hooks/usePageLayout.ts @@ -53,16 +53,16 @@ export function usePageLayout(store: DeckStore): UsePageLayoutReturn { const baseOffsetY = (a4Height - maxGridHeight) / 2; const result: PageData[] = []; - + if (doubleSided()) { - // 双面打印模式:每张卡牌需要 2 页(正面 + 背面) - // 背面卡牌顺序在长边方向上逆转 + // 双面打印模式:每页多张卡牌,正面和背面分别在相邻的两页 const totalCards = cards.length; - - for (let i = 0; i < totalCards; i++) { - const frontPageIndex = i * 2; - const backPageIndex = i * 2 + 1; - + const totalPages = Math.ceil(totalCards / cardsPerPage); + + for (let pageIndex = 0; pageIndex < totalPages; pageIndex++) { + const frontPageIndex = pageIndex * 2; + const backPageIndex = pageIndex * 2 + 1; + // 确保页面数组有足够长度 while (result.length <= backPageIndex) { result.push({ @@ -72,41 +72,51 @@ export function usePageLayout(store: DeckStore): UsePageLayoutReturn { frameBounds: { minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity } }); } - + const frontPage = result[frontPageIndex]; const backPage = result[backPageIndex]; - - // 正面:正常顺序排列 - const frontRow = Math.floor(i / cardsPerRow); - const frontCol = i % cardsPerRow; - const frontX = baseOffsetX + frontCol * cardWidth + frontOddPageOffsetX(); - const frontY = baseOffsetY + frontRow * cardHeight + frontOddPageOffsetY(); - - frontPage.cards.push({ data: cards[i], x: frontX, y: frontY, side: 'front' as const }); - frontPage.bounds.minX = Math.min(frontPage.bounds.minX, frontX); - frontPage.bounds.minY = Math.min(frontPage.bounds.minY, frontY); - frontPage.bounds.maxX = Math.max(frontPage.bounds.maxX, frontX + cardWidth); - frontPage.bounds.maxY = Math.max(frontPage.bounds.maxY, frontY + cardHeight); - - // 背面:逆转顺序排列(长边方向) - // 对于竖向打印,长边是垂直方向,所以逆转行 - // 对于横向打印,长边是水平方向,所以逆转列 - const backIndex = totalCards - 1 - i; - const backRow = orientation() === 'portrait' - ? Math.floor(backIndex / cardsPerRow) - : Math.floor(i / cardsPerRow); - const backCol = orientation() === 'portrait' - ? backIndex % cardsPerRow - : (cardsPerRow - 1 - (i % cardsPerRow)); - - const backX = baseOffsetX + backCol * cardWidth; - const backY = baseOffsetY + backRow * cardHeight; - - backPage.cards.push({ data: cards[i], x: backX, y: backY, side: 'back' as const }); - backPage.bounds.minX = Math.min(backPage.bounds.minX, backX); - backPage.bounds.minY = Math.min(backPage.bounds.minY, backY); - backPage.bounds.maxX = Math.max(backPage.bounds.maxX, backX + cardWidth); - backPage.bounds.maxY = Math.max(backPage.bounds.maxY, backY + cardHeight); + + // 计算当前正面页的卡牌范围 + const startCardIndex = pageIndex * cardsPerPage; + const endCardIndex = Math.min(startCardIndex + cardsPerPage, totalCards); + + for (let i = startCardIndex; i < endCardIndex; i++) { + // 正面:正常顺序排列 + const indexInPage = i - startCardIndex; + const row = Math.floor(indexInPage / cardsPerRow); + const col = indexInPage % cardsPerRow; + // 双面打印时,所有正面页都在奇数物理页上,所以都应用偏移 + const pageOffsetX = frontOddPageOffsetX(); + const pageOffsetY = frontOddPageOffsetY(); + + const frontX = baseOffsetX + col * cardWidth + pageOffsetX; + const frontY = baseOffsetY + row * cardHeight + pageOffsetY; + + frontPage.cards.push({ data: cards[i], x: frontX, y: frontY, side: 'front' as const }); + frontPage.bounds.minX = Math.min(frontPage.bounds.minX, frontX); + frontPage.bounds.minY = Math.min(frontPage.bounds.minY, frontY); + frontPage.bounds.maxX = Math.max(frontPage.bounds.maxX, frontX + cardWidth); + frontPage.bounds.maxY = Math.max(frontPage.bounds.maxY, frontY + cardHeight); + + // 背面:逆转顺序排列(长边方向) + // 对于竖向打印,长边是垂直方向,所以逆转行 + // 对于横向打印,长边是水平方向,所以逆转列 + const backRow = orientation() === 'portrait' + ? (rowsPerPage - 1 - row) + : row; + const backCol = orientation() === 'portrait' + ? col + : (cardsPerRow - 1 - col); + + const backX = baseOffsetX + backCol * cardWidth; + const backY = baseOffsetY + backRow * cardHeight; + + backPage.cards.push({ data: cards[i], x: backX, y: backY, side: 'back' as const }); + backPage.bounds.minX = Math.min(backPage.bounds.minX, backX); + backPage.bounds.minY = Math.min(backPage.bounds.minY, backY); + backPage.bounds.maxX = Math.max(backPage.bounds.maxX, backX + cardWidth); + backPage.bounds.maxY = Math.max(backPage.bounds.maxY, backY + cardHeight); + } } } else { // 单面打印模式:原有逻辑