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) | 방위각 | 위치 |
-
-
+
IP
-
+
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; }