From b0a71fc73f5c4e4126113ec1ef55b2dbc2eacc1c Mon Sep 17 00:00:00 2001 From: ypshim Date: Tue, 27 Oct 2026 15:26:35 +0900 Subject: [PATCH] =?UTF-8?q?feat(import):=20=EC=97=91=EC=85=80=20=EB=B6=88?= =?UTF-8?q?=EB=9F=AC=EC=98=A4=EA=B8=B0=20=EB=AF=B8=EB=A6=AC=EB=B3=B4?= =?UTF-8?q?=EA=B8=B0=EC=97=90=20=EC=A0=84=EC=B2=B4=20=EA=B5=90=EA=B0=81?= =?UTF-8?q?=EC=9D=98=20=EC=9E=85=EB=A0=A5=EA=B0=92=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 교각 정보: 교각마다 열 하나, 행은 형식·EL·기초·말뚝·두부보·기둥·받침/IP 수·불러오기 여부 - 받침과 IP: 모든 교각을 한 표에 두고 교각 열을 추가, 표는 스크롤 - 교각 이름 클릭으로 미리볼 교각을 고르던 방식은 제거 (전체를 보여 줌) Co-Authored-By: Claude Haiku 5.5 --- index.html | 22 +++++++++------- src/main.ts | 73 +++++++++++++++++++++++++++------------------------ src/style.css | 3 +++ 3 files changed, 55 insertions(+), 43 deletions(-) diff --git a/index.html b/index.html index 211bcb6..a013dec 100644 --- a/index.html +++ b/index.html @@ -291,17 +291,21 @@

미리보기

교각 정보

-
+

받침

- - - -
번호x (m)y (m)z (m)방위각위치
+
+ + + +
교각번호x (m)y (m)z (m)방위각위치
+

IP

- - - -
점x (m)y (m)꺾임각
+
+ + + +
교각점x (m)y (m)꺾임각
+
diff --git a/src/main.ts b/src/main.ts index 8e39d95..00edc1f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -108,7 +108,6 @@ interface Pending { fileName: string; entries: Pier[]; sheets: SheetReport[]; - preview: string | null; } const state = { @@ -2842,7 +2841,7 @@ function renderDialog(): void { $('file-name').textContent = p ? `선택된 파일: ${p.fileName}` : ''; if (!p) { sheetsBox.appendChild(el('li', '파일을 선택하면 시트별 인식 결과가 표시됩니다.')); - renderPreview(null); + renderPreview([]); updateApply(); return; } @@ -2873,38 +2872,36 @@ function renderDialog(): void { entry.checked = check.checked; updateApply(); }); - const name = el('button', `${entry.input.name} · ${entry.input.type}`, 'pier-name'); - name.type = 'button'; - name.setAttribute('aria-pressed', String(p.preview === entry.input.name)); - name.addEventListener('click', () => { - p.preview = entry.input.name; - renderDialog(); - }); + const name = el('span', `${entry.input.name} · ${entry.input.type}`, 'pier-name'); row.append(check, name); li.appendChild(row); } sheetsBox.appendChild(li); } - const preview = p.entries.find((e) => e.input.name === p.preview) ?? p.entries.find((e) => selectable(p, e)) ?? null; - renderPreview(preview ? preview.input : null); + renderPreview(p ? p.entries.map((e) => ({ input: e.input, checked: e.checked })) : []); updateApply(); } -function renderPreview(input: PierInput | null): void { +/** Preview of every pier in the file: one column per pier for the 교각 정보, all 받침·IP rows with a 교각 column. */ +function renderPreview(items: { input: PierInput; checked: boolean }[]): void { const title = $('preview-title'); - const pierTable = $('pv-pier').tBodies[0]; + const pierTable = $('pv-pier'); const bearingBody = $('pv-bearings').tBodies[0]; const ipBody = $('pv-ips').tBodies[0]; pierTable.replaceChildren(); bearingBody.replaceChildren(); ipBody.replaceChildren(); - if (!input) { + if (items.length === 0) { title.textContent = '미리볼 교각이 없습니다.'; return; } - title.textContent = `${input.name} · 시트 ${input.sheet}`; - const pairs: Pair[] = [ - ['교각명', input.name], + const sheets = [...new Set(items.map((i) => i.input.sheet))].join(', '); + title.textContent = `${items.length}기 · 시트 ${sheets}`; + + const head = pierTable.createTHead().insertRow(); + head.appendChild(el('th', '항목')); + for (const { input } of items) head.appendChild(el('th', input.name)); + const rowsOf = (input: PierInput): Pair[] => [ ['교각형식', input.type], ['두부보 EL (코핑 상면)', f3(input.copingTopEl)], ['기초 하단 EL', f3(input.footingBottomEl)], @@ -2913,22 +2910,31 @@ function renderPreview(input: PierInput | null): void { ['말뚝길이 (mm)', String(input.pileLengthMm)], ['두부보 폭 × 길이 (mm)', `${input.copingWidthMm} × ${input.copingLengthMm}`], ['기둥갯수', String(input.columnCount)], + ['받침 · IP', `${input.bearings.length} · ${input.ips.length}`], ]; - for (const [k, v] of pairs) { - const tr = el('tr'); - tr.append(el('th', k), el('td', v)); - pierTable.appendChild(tr); - } - for (const b of input.bearings) { - const tr = el('tr'); - const azimuth = Number.isNaN(b.azimuthDeg) ? '오류' : `${b.azimuthDeg.toFixed(4)}°`; - for (const v of [String(b.no), b.x.toFixed(3), b.y.toFixed(3), f3(b.z), azimuth, b.row]) tr.appendChild(el('td', v)); - bearingBody.appendChild(tr); - } - for (const ip of input.ips) { - const tr = el('tr'); - for (const v of [ip.name, ip.x.toFixed(3), ip.y.toFixed(3), `${ip.angleDeg}°`]) tr.appendChild(el('td', v)); - ipBody.appendChild(tr); + const labels = rowsOf(items[0].input).map(([k]) => k); + const body = pierTable.createTBody(); + labels.forEach((label, r) => { + const tr = body.insertRow(); + tr.appendChild(el('th', label)); + for (const { input } of items) tr.appendChild(el('td', rowsOf(input)[r][1])); + }); + const included = body.insertRow(); + included.appendChild(el('th', '불러오기')); + for (const { checked } of items) included.appendChild(el('td', checked ? '예' : '아니오')); + + for (const { input } of items) { + for (const b of input.bearings) { + const tr = el('tr'); + const azimuth = Number.isNaN(b.azimuthDeg) ? '오류' : `${b.azimuthDeg.toFixed(4)}°`; + for (const v of [input.name, String(b.no), b.x.toFixed(3), b.y.toFixed(3), f3(b.z), azimuth, b.row]) tr.appendChild(el('td', v)); + bearingBody.appendChild(tr); + } + for (const ip of input.ips) { + const tr = el('tr'); + for (const v of [input.name, ip.name, ip.x.toFixed(3), ip.y.toFixed(3), `${ip.angleDeg}°`]) tr.appendChild(el('td', v)); + ipBody.appendChild(tr); + } } } @@ -2952,9 +2958,8 @@ function loadBytes(bytes: Uint8Array, fileName: string): void { for (const e of own) sheet.issues.push(...e.issues.filter((i) => i.level === 'E')); sheet.ok = sheet.ok && own.every((e) => e.model !== null); } - const pending: Pending = { fileName, entries, sheets, preview: null }; + const pending: Pending = { fileName, entries, sheets }; for (const e of entries) e.checked = selectable(pending, e); - pending.preview = entries.find((e) => selectable(pending, e))?.input.name ?? entries[0]?.input.name ?? null; state.pending = pending; renderDialog(); } diff --git a/src/style.css b/src/style.css index aa56b18..0b8e1f8 100644 --- a/src/style.css +++ b/src/style.css @@ -810,3 +810,6 @@ body { background: #eef1f4; font-family: 'Noto Sans KR', system-ui, sans-serif; @media (max-width: 800px) { .footing-grid { grid-template-columns: 1fr; } } + +/* Import preview: all piers' 받침·IP rows scroll inside the dialog. */ +.pv-scroll { max-height: 240px; overflow: auto; }