feat(spreadsheet): F 서버 재계산 · 산출근거 따로 저장 · M02 끼우기 · 금빛 시험

- common_util_spreadsheet_node.ts · common_util_spreadsheet.py · build:spreadsheet — [저장] 때 화면과 같은 TS 엔진을 Node 로 돌려 계산값 정본(브라우저 값 버림 · 못 풀면 503)
- M02 새 종류 basis — resources/master_template/basis/<열 id>.json(구조물집계표 열마다) · 층 복사 · 뼈대 검사 · 옛 구조물 문서 산출근거 49 벌 옮김(migrate_basis) · 새 열도 같이 만듦
- 상세 산출근거 카드 = 새 스프레드시트(import() 로 늦게 받음) · basis 읽기 · 저장
- ⚠ 임시 [스프레드시트 시험] 단추 — 빈 통합문서(시트 셋) · 저장 자리 tmp/spreadsheet_trial.json · 1단계 검증 뒤 지움
- 시험 resources/tester/spreadsheet/ — 저장 · 서버 다리 · 크기 예산 · M02 만 늦게 불러옴 · 실무 구조도 xlsx 세 벌 수식 2,699 칸 엑셀 캐시값 대조(엔진 빈 몸이면 건너뜀)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0168FQuoV7vDh5nhnSowW5cp
This commit is contained in:
2026-09-27 20:12:39 +09:00
co-authored by Claude Opus 5.5
parent 26fd4fb72e
commit cd824aca25
118 changed files with 3642 additions and 3065 deletions
@@ -22,6 +22,8 @@ import {
type StructureColumn,
type StructurePanelHandle,
} from "./M02_MasterTemplete_Structure";
// ⚠ 임시 — [스프레드시트 시험] 단추(1단계 검증 뒤 지움)
import { mountSpreadsheetTrial } from "./M02_MasterTemplete_Spreadsheet_Trial";
export interface Selection {
layer: Layer;
@@ -77,6 +79,9 @@ export function createMain(isAdmin: boolean, onSaved?: () => void): MainHandle {
const title = el("h2", { className: "m02-main__title", text: L("M02_PickTemplate") });
const reload = createButton({ label: L("M02_Reload"), variant: "ghost" });
const save = createButton({ label: L("M02_Save"), variant: "filled" });
// ⚠ 임시 — [스프레드시트 시험] 단추(사용자 지시 · 1단계 검증 뒤 지움)
const trial = createButton({ label: "스프레드시트 시험", variant: "ghost" });
trial.hidden = !isAdmin;
const slot = el("div", { className: "m02-main__slot" }); // 도면 양식의 작도 영역 칸이 들어옴
const notice = el("div", { className: "m02-main__notice", attrs: { hidden: "" } });
const host = el("div", { className: "m02-main__host" });
@@ -84,7 +89,7 @@ export function createMain(isAdmin: boolean, onSaved?: () => void): MainHandle {
const root = el("div", {
className: "m02-main",
children: [
el("div", { className: "m02-main__head", children: [title, slot, reload, save] }),
el("div", { className: "m02-main__head", children: [title, slot, reload, save, trial] }),
notice,
host,
extra,
@@ -269,6 +274,18 @@ export function createMain(isAdmin: boolean, onSaved?: () => void): MainHandle {
}
save.addEventListener("click", () => void doSave());
// ⚠ 임시 — [스프레드시트 시험] 빈 통합문서(시트 셋)를 메인 칸에 넓게 엶 · 저장은 서버 tmp 견본 자리
trial.addEventListener("click", async () => {
if (!(await confirmLeave())) return;
seq += 1;
dirty = false;
drop();
showNotice([]);
sel = null;
bar();
title.textContent = "스프레드시트 시험";
editor = mountSpreadsheetTrial(host, (d) => (dirty = d));
});
reload.addEventListener("click", async () => {
if (sel && (await confirmLeave())) void open(sel);
});