feat(M01): 일위대가 로직 테스트 컨테이너 틀 + 방식 A 질문·답 마법사

- 왼쪽 패널에 「일위대가 로직 테스트」 컨테이너 추가 — 공종 10 개 고르기 + 방식 탭 A·B·C (B·C 는 준비 중)
- 방식 A: 공종 → 조건 질문(한 번에 하나) → 재료·기계 고르기 → 결과 호표 · 식 안 보임 · 저장 없음
- 대상 10 개는 복잡도로 재어 고름(scripts/로직_복잡도_재기.py) · 시험 test_m01_test_container.py

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016WRFJmmhPi4exAzHgPZHMT
This commit is contained in:
2026-09-20 21:34:39 +09:00
co-authored by Claude Sonnet 5
parent 565833bcb8
commit 292568e688
9 changed files with 686 additions and 18 deletions
+36 -16
View File
@@ -1,6 +1,6 @@
/* =============================================================================
* M01_MasterData_UI_Page.ts
* 마스터 요소 화면 — 좌측 도킹 패널(컨테이너 여덟: 인력·재료·기계·소요량·계수·환율·요율·일위대가 로직)
* 마스터 요소 화면 — 좌측 도킹 패널(컨테이너 아홉: 인력·재료·기계·소요량·계수·환율·요율·일위대가 로직·로직 테스트)
* / 우측 요소 표 · 표 목록 · 로직 편집
*
* 시스템 관리자만. 고친 것은 초안(sessionStorage)에 쌓이고 [저장] 한 번에 서버로 —
@@ -45,6 +45,7 @@ function buildPage(): HTMLElement {
let query = "";
let dispose = (): void => {};
let logicMounted = false;
let testMounted = false;
/* --- 우측: 머리(제목·찾기·저장) + 알림 + 본문 --- */
const title = el("h2", { className: "m01-master__title", text: L("M01_PickFile") });
@@ -60,6 +61,7 @@ function buildPage(): HTMLElement {
children: [title, searchField.root, summary, drop, save],
});
const logicHost = el("div", { className: "m01-master__logic", attrs: { hidden: "" } });
const testHost = el("div", { className: "m01-master__logic", attrs: { hidden: "" } });
const elementView = el("div", {
className: "m01-master__elements",
children: [head, notice, body],
@@ -77,14 +79,15 @@ function buildPage(): HTMLElement {
onDraftChange(refreshBar);
refreshBar();
const showMode = (logic: boolean): void => {
logicHost.hidden = !logic;
elementView.hidden = logic;
const showMode = (mode: "elements" | "logic" | "test"): void => {
logicHost.hidden = mode !== "logic";
testHost.hidden = mode !== "test";
elementView.hidden = mode !== "elements";
};
const openFile = (pick: Pick): void => {
dispose();
showMode(false);
showMode("elements");
if (pick.view) {
query = pick.view.q;
search.value = query;
@@ -162,21 +165,38 @@ function buildPage(): HTMLElement {
return [L("M01_Stale").replace("{value}", stale.map(fileLabel).join(", ")), again];
};
/* --- 좌측: 컨테이너 여덟 --- */
const side = buildSide(openFile, () => {
dispose();
dispose = (): void => {};
current = null;
showMode(true);
if (logicMounted) return;
logicMounted = true;
void import("./M01_MasterData_UI_Logic_Page").then((m) => m.mountM01Logic(logicHost, side));
});
/* --- 좌측: 컨테이너 아홉 --- */
const side = buildSide(
openFile,
() => {
dispose();
dispose = (): void => {};
current = null;
showMode("logic");
if (logicMounted) return;
logicMounted = true;
void import("./M01_MasterData_UI_Logic_Page").then((m) => m.mountM01Logic(logicHost, side));
},
() => {
dispose();
dispose = (): void => {};
current = null;
showMode("test");
if (testMounted) return;
testMounted = true;
void import("./M01_MasterData_UI_Test").then((m) => m.mountM01Test(testHost));
},
);
const layout = el("div", { className: "ui-workflow-layout m01-master" });
const main = el("main", {
className: "ui-workflow-layout__main",
children: [el("div", { className: "m01-master__panel", children: [elementView, logicHost] })],
children: [
el("div", {
className: "m01-master__panel",
children: [elementView, logicHost, testHost],
}),
],
});
const overlays = createWorkflowOverlays({
title: L("M01_Title"),