merge(707): sub_laptop_8(sub5 707-1 내역 줄 불러오기) 합침 — 불러오기 길 · 화면 한 파일 · file_key 하나 (PLAN 707-1 · 707-2 · 707-3)

- Router_Import = import/bill · bill/apply(sub5) + import/rates · import/prices · 올린 파일 = 프로젝트 import/{표지} 한 자리
- UI_Import = [엑셀 내역 불러오기] + [엑셀에서 요율 · 단가표 불러오기] · 마지막 표지 함께 씀
- test_145_3 · test_166_2 TS 거울 = 글 stdin(Calc_Base · Calc_Bill 길어져 node -e 32 K 넘김)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-31 16:30:43 +09:00
co-authored by Claude Opus 5.5
16 changed files with 1208 additions and 96 deletions
+14 -2
View File
@@ -42,7 +42,7 @@ import { createCheckPanel } from "./B09_Estimation_UI_Check";
import { createLiveCalc, markWaiting, waitingKeys, withoutWaiting } from "./B09_Estimation_UI_Live";
import { tableOptionsOf, tabTableOf } from "./B09_Estimation_UI_Builders";
import { createDock, linkMode } from "./B09_Estimation_UI_Dock";
import { importTools } from "./B09_Estimation_UI_Import";
import { createBillImport, importTools } from "./B09_Estimation_UI_Import";
import { closePopups, openRowPopup } from "./B09_Estimation_UI_Popup";
import {
DRAFT,
@@ -287,7 +287,7 @@ export function renderB09Estimation(root: HTMLElement): void {
);
if (range) unpickOnRelease(table.root);
const level = bill ? levelBar(table.root, bill, (i) => table.edit(i)) : null;
if (level) bars.setTools(level.tools);
if (level) bars.setTools(importer ? [...level.tools, importer] : level.tools);
// 203 안내 글 영역 하나 — 설계내역서 레벨 안내 + 탭 안내 이어 붙임
if (level && hint) hint.textContent = `${level.guide.textContent} · ${hint.textContent}`;
const foot = hint ?? level?.guide;
@@ -303,6 +303,18 @@ export function renderB09Estimation(root: HTMLElement): void {
if (at >= 0) requestAnimationFrame(() => table.focusRow(at, false)); // 스크롤만(표시 = 빨강)
};
// 707-1 [엑셀 내역 불러오기] = 설계내역서 도구 줄 끝 · 받은 캐시 → 원가 자료와 함께 다시 셈(저장 안 함)
const importer = projectId
? createBillImport(
projectId,
() => user,
(next, made) => {
writeState("b09-estimation", made, projectId);
apply(next, false);
},
)
: null;
const apply = (next: Row, fromServer: boolean): void => {
payload = next;
const draft = projectId && !fromServer ? readState<Row>("b09-estimation", projectId) : null;