feat(import): input template download with three sheets (spec 2.3 step 4)
- buildTemplateWorkbook: 교각 · IP · 받침 sheets with the headers the parser reads; value cells left empty so no blank-name rows raise E05 - dialog button 입력 템플릿 다운로드 (.xlsx) - tests: sheet order, parser recognition, write-and-read round trip Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0b7ae1ef3f
commit
6319cccb8e
4 files changed
+67
No files matched your search
@@ -0,0 +1,32 @@
|
||||
import * as XLSX from 'xlsx';
|
||||
|
||||
/**
|
||||
* Blank input template with the three sheets (교각 · IP · 받침) and the headers the parser looks for.
|
||||
* Value cells are left empty on purpose: pre-filled names would become rows with no 교각명 and raise E05.
|
||||
* Row 1–2 are notes; the parser finds the headers anywhere on the sheet.
|
||||
*/
|
||||
export function buildTemplateWorkbook(): XLSX.WorkBook {
|
||||
const wb = XLSX.utils.book_new();
|
||||
const note = (text: string) => [text];
|
||||
|
||||
const pier = [
|
||||
note('교각 정보 1행당 교각 1기. 교각명·교각형식(T형/2주형/3주형)·기초 형식(말뚝기초/직접기초/현장타설말뚝)을 적습니다.'),
|
||||
note('방위각은 75°56\'55.9" 형식으로 적습니다. 머리글 행은 바꾸지 마세요.'),
|
||||
['교각명', '교각형식', '두부보 EL_m', '기초 하단 EL_m', '지반고 EL_m', '기초 형식', '말뚝길이_mm', '두부보 폭_mm', '두부보 길이_mm', '기둥갯수'],
|
||||
];
|
||||
const ip = [
|
||||
note('IP1–IP4의 좌표(국토좌표계, m)와 코핑 꺾임각(°)을 적습니다. 교각명은 교각 정보와 같아야 합니다.'),
|
||||
note('IP2는 참고용입니다. 프로그램이 IP1–IP3의 1:9 내분점으로 다시 계산해 비교합니다.'),
|
||||
['교각명', 'IP점', 'x_m', 'y_m', '코핑 꺾임각'],
|
||||
];
|
||||
const bearing = [
|
||||
note('받침 1행당 받침 1개. 전열·후열 수는 같아야 합니다. 위치는 전열 또는 후열.'),
|
||||
note('z_m은 받침 EL(m), 방위각은 거더 방향입니다.'),
|
||||
['교각명', '받침번호', 'x_m', 'y_m', 'z_m', '방위각', '위치'],
|
||||
];
|
||||
|
||||
XLSX.utils.book_append_sheet(wb, XLSX.utils.aoa_to_sheet(pier), '교각');
|
||||
XLSX.utils.book_append_sheet(wb, XLSX.utils.aoa_to_sheet(ip), 'IP');
|
||||
XLSX.utils.book_append_sheet(wb, XLSX.utils.aoa_to_sheet(bearing), '받침');
|
||||
return wb;
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import * as XLSX from 'xlsx';
|
||||
import { parseWorkbook, type SheetReport } from './core/parseWorkbook';
|
||||
import { buildPier, type PierModel } from './core/geometry';
|
||||
import { NOT_IMPLEMENTED_RULES, validateInput, validatePier } from './core/validate';
|
||||
import { buildTemplateWorkbook } from './core/template';
|
||||
import type { Issue, PierInput, PierType } from './core/types';
|
||||
import { buildPierScene, viewPosition, type PartName, type PierScene, type ViewKind } from './view/scene';
|
||||
|
||||
@@ -520,6 +521,9 @@ $<HTMLButtonElement>('regen').addEventListener('click', regenerateChecked);
|
||||
$<HTMLInputElement>('project-name').addEventListener('input', updateApply);
|
||||
|
||||
$<HTMLButtonElement>('pick-file').addEventListener('click', () => $<HTMLInputElement>('file').click());
|
||||
$<HTMLButtonElement>('download-template').addEventListener('click', () => {
|
||||
XLSX.writeFile(buildTemplateWorkbook(), '교각입력템플릿.xlsx');
|
||||
});
|
||||
$<HTMLInputElement>('file').addEventListener('change', async (ev) => {
|
||||
const file = (ev.target as HTMLInputElement).files?.[0];
|
||||
if (!file) return;
|
||||
|
||||
Reference in new issue
Block a user