import { type Worksheet } from "exceljs"; /** * Converts an Excel column label to a 1-based number. * Example: A -> 1, Z -> 26, AA -> 27 */ function columnToNumber(label: string): number { let n = 0; for (let i = 0; i < label.length; i++) { n = n * 26 + label.charCodeAt(i) - 64; } return n; } /** * Generates merge ranges like: * C8:G10, I8:M10, ... * then C14:G16, I14:M16, ... */ type MergeRangePattern = { startColumns: readonly string[]; firstStartRow: number; mergeWidthInColumns: number; mergeHeightInRows: number; mergeBlockCount: number; rowStepBetweenBlocks: number; }; export function applyMergePattern(sheet: Worksheet, config: MergeRangePattern) { const { startColumns, firstStartRow, mergeWidthInColumns, mergeHeightInRows, mergeBlockCount, rowStepBetweenBlocks } = config; for (let block = 0; block < mergeBlockCount; block++) { const rowStart = firstStartRow + block * rowStepBetweenBlocks; const rowEnd = rowStart + mergeHeightInRows - 1; for (const column of startColumns) { const colStart = columnToNumber(column); const colEnd = colStart + mergeWidthInColumns - 1; sheet.mergeCells(rowStart, colStart, rowEnd, colEnd); } } }