/** * 도면 불러오기 (승인 2026-10-23): reads the bearing drawing values from a sheet (xlsx or csv rows). Pure: the caller * passes the rows (arrays of cells). The header row names: No, EL.X (m), h1 (mm), h2 (mm). 열 and other columns are ignored. */ import type { DrawingBearing } from './bearing-ref'; export interface DrawingImportResult { rows: DrawingBearing[]; errors: string[]; } // Header names ignore case, spaces, dots and a unit in parentheses: 'EL. X (m)' → 'elx'. const norm = (v: unknown) => String(v ?? '').replace(/\(.*?\)/g, '').toLowerCase().replace(/[\s.]/g, ''); /** Column of each header name, or -1 when missing. */ function headerIndex(header: unknown[]): { no: number; elx: number; h1: number; h2: number } { const find = (...names: string[]) => header.findIndex((c) => names.includes(norm(c))); return { no: find('no'), elx: find('elx', 'el'), h1: find('h1', '블럭높이h1'), h2: find('h2', '몰탈h2', '모르타르h2') }; } export function parseDrawingRows(rows: unknown[][]): DrawingImportResult { const errors: string[] = []; const headerAt = rows.findIndex((r) => { const idx = headerIndex(r); return idx.no >= 0 && idx.elx >= 0 && idx.h1 >= 0 && idx.h2 >= 0; }); if (headerAt < 0) { return { rows: [], errors: ['머리글을 찾지 못했습니다. No, EL.X, h1, h2 열이 있어야 합니다.'] }; } const idx = headerIndex(rows[headerAt]); const out: DrawingBearing[] = []; const seen = new Set(); rows.slice(headerAt + 1).forEach((r, i) => { const rowNo = headerAt + 2 + i; if (r.every((c) => String(c ?? '').trim() === '')) return; const no = Number(r[idx.no]); const elx = Number(r[idx.elx]); const h1 = Number(r[idx.h1]); const h2 = Number(r[idx.h2]); if (!Number.isInteger(no) || no < 1) { errors.push(`${rowNo}행: No가 올바르지 않습니다.`); return; } if (seen.has(no)) { errors.push(`${rowNo}행: No ${no}가 중복됩니다.`); return; } if (!Number.isFinite(elx) || elx < 30 || elx > 100) { errors.push(`${rowNo}행: EL.X는 m 단위로 적어 주세요 (예: 43.625). 값: ${String(r[idx.elx])}`); return; } if (!Number.isFinite(h1) || h1 <= 0 || h1 > 1000 || !Number.isFinite(h2) || h2 <= 0 || h2 > 1000) { errors.push(`${rowNo}행: h1·h2는 mm 단위 양수로 적어 주세요.`); return; } seen.add(no); out.push({ no, elx, h1, h2 }); }); if (out.length === 0) errors.push('불러온 행이 없습니다.'); return { rows: out.sort((a, b) => a.no - b.no), errors }; }