feat(import): 엑셀의 프로젝트명 · 교량명을 불러오기 창에 자동 입력
새 입력 양식(운곡교AA.xlsx, 운곡교(완도,광주)데이터)의 '형상정보' B1 '프로젝트명:' → C1, B2 '교량명:' → C2를 읽어 불러오기 창의 프로젝트명 · 교량명 칸을 채운다. - core/project-info.ts: 모든 시트의 앞 20행 × 10열에서 라벨을 찾고, 같은 칸 ':' 뒤나 오른쪽 4칸 안의 값을 씀. 라벨이 없는 엑셀(운곡교P1입력.xlsx)은 아무것도 읽지 않음 - 칸이 비었거나 앞서 자동으로 채운 값일 때만 채움. 사용자가 입력한 값은 덮어쓰지 않음(샘플 이름은 자동 값으로 취급) - 파일 줄에 읽은 위치 표시: "프로젝트명 · 교량명: 엑셀 형상정보!C1 · 형상정보!C2" - 테스트 4개, 브라우저: AA 자동 입력 → 직접 고친 프로젝트명은 다음 파일에서도 유지 → 이름 없는 샘플은 그대로 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
bff1502ecf
commit
c9e1cc6eaa
3 files changed
+113
-2
No files matched your search
+29
-2
@@ -37,6 +37,7 @@ import {
|
||||
import { ABUT_FOOTING_REBAR_DEFAULT, abutFootingGeom, abutFootingRebar, ABUT_FOOTING_SIZES, type AbutFootingGeom, type AbutFootingRebar, type AbutFootingRebarSettings } from './core/abut/rebar/footing';
|
||||
import { lenText, skewAngle } from './core/abut/rebar/skew-layout';
|
||||
import { defaultJointCount, jointPositions } from './core/abut/joints';
|
||||
import { type ProjectInfo as WorkbookNames, readProjectInfo } from './core/project-info';
|
||||
import { ABUT_BLOCK_PAD_MM, ABUT_BLOCK_REBAR_DEFAULT, abutBlockRebar, type AbutBlockRebar, type AbutBlockSettings } from './core/abut/rebar/block';
|
||||
import { ABUT_BLOCK_COLORS, abutBlockPlanSvg as abutBlockRebarPlanSvg, abutBlockSectionSvg as abutBlockRebarSectionSvg } from './view/abut-block-rebar-svg';
|
||||
import { ABUT_SLAB_REBAR_DEFAULT, ABUT_SLAB_SIZES, abutSlabGeom, abutSlabRebar, type AbutSlabGeom, type AbutSlabRebar, type AbutSlabRebarSettings } from './core/abut/rebar/slab';
|
||||
@@ -190,6 +191,8 @@ interface Pending {
|
||||
abutments: AbutRecord[];
|
||||
abutIssues: Issue[];
|
||||
selectedAbutments: Set<string>;
|
||||
/** 프로젝트명 · 교량명 read from the workbook ('형상정보' B1 · B2 form), when present (2026-11-06). */
|
||||
projectInfo: WorkbookNames;
|
||||
}
|
||||
|
||||
const state = {
|
||||
@@ -5779,7 +5782,9 @@ function renderDialog(): void {
|
||||
const p = state.pending;
|
||||
const sheetsBox = $<HTMLUListElement>('sheets');
|
||||
sheetsBox.replaceChildren();
|
||||
$('file-name').textContent = p ? `선택된 파일: ${p.fileName}` : '';
|
||||
$('file-name').textContent = p
|
||||
? `선택된 파일: ${p.fileName}${p.projectInfo.source ? ` · 프로젝트명 · 교량명: 엑셀 ${p.projectInfo.source} (직접 입력한 칸은 그대로 둡니다)` : ''}`
|
||||
: '';
|
||||
if (!p) {
|
||||
sheetsBox.appendChild(el('li', '파일을 선택하면 시트별 인식 결과가 표시됩니다.'));
|
||||
renderPreview([]);
|
||||
@@ -5946,7 +5951,9 @@ 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, abutments: abut.abutments, abutIssues: abut.issues, selectedAbutments: new Set() };
|
||||
const projectInfo = readProjectInfo(wb);
|
||||
fillNamesFromWorkbook(projectInfo);
|
||||
const pending: Pending = { fileName, entries, sheets, abutments: abut.abutments, abutIssues: abut.issues, selectedAbutments: new Set(), projectInfo };
|
||||
for (const e of entries) e.checked = selectable(pending, e);
|
||||
for (const rec of pending.abutments) if (selectableAbut(pending, rec)) pending.selectedAbutments.add(rec.name);
|
||||
state.pending = pending;
|
||||
@@ -6129,6 +6136,8 @@ $<HTMLButtonElement>('edit-regen').addEventListener('click', () => {
|
||||
});
|
||||
|
||||
$<HTMLInputElement>('project-name').addEventListener('input', updateApply);
|
||||
// A typed name is the user's: a later workbook no longer replaces it (fillNamesFromWorkbook).
|
||||
for (const id of ['project-name', 'bridge-name']) $<HTMLInputElement>(id).addEventListener('input', (e) => { delete (e.target as HTMLInputElement).dataset.auto; (e.target as HTMLInputElement).title = ''; });
|
||||
|
||||
$<HTMLButtonElement>('pick-file').addEventListener('click', () => $<HTMLInputElement>('file').click());
|
||||
$<HTMLButtonElement>('download-template').addEventListener('click', () => {
|
||||
@@ -6144,9 +6153,27 @@ $<HTMLInputElement>('file').addEventListener('change', async (ev) => {
|
||||
/** The project's standing input and names (RAG/운곡교P1입력.xlsx → 프로젝트 운곡교P1, 교량 운곡교). */
|
||||
const SAMPLE_PROJECT = { name: '운곡교P1', bridge: '운곡교' } as const;
|
||||
|
||||
/**
|
||||
* 프로젝트명 · 교량명 from the workbook (2026-11-06): fill a field that is empty or still holds a value filled from a
|
||||
* workbook (data-auto), never one the user typed. Workbooks without the labels leave the fields as they are.
|
||||
*/
|
||||
function fillNamesFromWorkbook(info: WorkbookNames): void {
|
||||
for (const [id, value] of [['project-name', info.projectName], ['bridge-name', info.bridgeName]] as const) {
|
||||
if (!value) continue;
|
||||
const input = $<HTMLInputElement>(id);
|
||||
if (input.value.trim() && input.dataset.auto !== '1') continue;
|
||||
input.value = value;
|
||||
input.dataset.auto = '1';
|
||||
input.title = `엑셀에서 읽음 (${info.source ?? ''})`;
|
||||
}
|
||||
updateApply();
|
||||
}
|
||||
|
||||
function fillSampleNames(): void {
|
||||
$<HTMLInputElement>('project-name').value = SAMPLE_PROJECT.name;
|
||||
$<HTMLInputElement>('bridge-name').value = SAMPLE_PROJECT.bridge;
|
||||
// Filled by the app, not typed: a workbook with names may replace them (fillNamesFromWorkbook).
|
||||
for (const id of ['project-name', 'bridge-name']) $<HTMLInputElement>(id).dataset.auto = '1';
|
||||
// Setting .value does not fire 'input', so the apply button must be refreshed here.
|
||||
updateApply();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user