From 0eebf357fa21c268d7354001ab26c486f9afefff Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 22 Sep 2026 12:08:54 +0900 Subject: [PATCH] =?UTF-8?q?feat(M01):=20PLAN=207-1=20=E2=80=94=20=E3=80=8C?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B0=9C=EC=84=A0=20=EC=8B=9C=ED=97=98?= =?UTF-8?q?=E3=80=8D=EC=9D=84=20=E3=80=8C=EB=8B=A8=EA=B0=80=EC=82=B0?= =?UTF-8?q?=EC=B6=9C=20=EB=A1=9C=EC=A7=81=E3=80=8D=20=ED=95=98=EB=82=98?= =?UTF-8?q?=EB=A1=9C=20=ED=95=A9=EC=B9=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 소요량·계수의 쓰는 로직 · 조합 화면 로직 이름 · 패널 제목 세 자리를 모두 새 컨테이너(UI_LogicLab)로 돌림 · 옛 컨테이너(UI_Logic_Page)는 old_code/M01_MasterData/ 로 옮김(지우지 않음 · import 경로만 고침 · 통째 복사 아님) · 정본 GC·GF 를 화면에서 바로 고쳐 저장 · 정본 파일에 빈 줄 더하기 두 길은 사용자 확정으로 버림. 분석 = resources/master_data/ref/_분석_로직컨테이너_통합.md. typecheck 통과 · M01 시험 107 통과 · ORCA — 패널에 「단가산출 로직」 하나만 · 소요량 표 쓰는 로직 키(GF000002 · GF000051) 클릭 각각 그 로직이 새 컨테이너에서 열림 · 조합 화면 로직 이름도 같은 컨테이너로 이어짐. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_016WRFJmmhPi4exAzHgPZHMT --- M01_MasterData/M01_MasterData_UI_LogicLab.ts | 4 +-- .../M01_MasterData_UI_LogicLab_Detail.ts | 2 +- .../M01_MasterData_UI_LogicLab_New.ts | 2 +- .../M01_MasterData_UI_LogicLab_Text.ts | 4 +-- .../M01_MasterData_UI_Logic_Text.ts | 3 +- M01_MasterData/M01_MasterData_UI_Page.ts | 34 ++++++------------- M01_MasterData/M01_MasterData_UI_Side.ts | 20 +++-------- .../M01_MasterData_UI_Logic_Page.ts | 30 +++++++++++----- 8 files changed, 42 insertions(+), 57 deletions(-) rename {M01_MasterData => old_code/M01_MasterData}/M01_MasterData_UI_Logic_Page.ts (90%) diff --git a/M01_MasterData/M01_MasterData_UI_LogicLab.ts b/M01_MasterData/M01_MasterData_UI_LogicLab.ts index dcccdb38..231e38b4 100644 --- a/M01_MasterData/M01_MasterData_UI_LogicLab.ts +++ b/M01_MasterData/M01_MasterData_UI_LogicLab.ts @@ -262,7 +262,7 @@ export async function mountM01LogicLab( // 왼쪽 「전체」 + 구분 → 상세구분 거름 — 고르면 목록으로 돌아와 그 범위만 filterHost.replaceChildren( side.filter({ - id: "로직시험|", + id: "로직|", store: "m01.filter.로직시험", subs, total: list.total(), @@ -421,7 +421,7 @@ export async function mountM01LogicLab( ], }), ); - side.labHost.replaceChildren(filterHost); + side.logicHost.replaceChildren(filterHost); show(null); showLoadingOverlay(); const openKeyOn = async (key: string): Promise => { diff --git a/M01_MasterData/M01_MasterData_UI_LogicLab_Detail.ts b/M01_MasterData/M01_MasterData_UI_LogicLab_Detail.ts index 037450ae..03e2b0f3 100644 --- a/M01_MasterData/M01_MasterData_UI_LogicLab_Detail.ts +++ b/M01_MasterData/M01_MasterData_UI_LogicLab_Detail.ts @@ -1,6 +1,6 @@ /* ============================================================================= * M01_MasterData_UI_LogicLab_Detail.ts - * 「로직 개선 시험」 상세 화면 — 컨테이너 넷을 위에서 아래로 + * 「단가산출 로직」 상세 화면 — 컨테이너 넷을 위에서 아래로 * ① 기본정보(정본은 읽기 전용 · 비고만 고침) ② 단가산출 상세(인력·자재·경비·그 밖 묶음 + 소계) * ③ 텍스트 수식(자리 — `_LogicLab_Formula.ts`) ④ 시험 계산(입력값 + 결과값 — `Logic_Calc` 그대로) * 호표 줄을 누르면 그 줄이 쓰는 자료 모달(`_LogicLab_Modal.ts`) diff --git a/M01_MasterData/M01_MasterData_UI_LogicLab_New.ts b/M01_MasterData/M01_MasterData_UI_LogicLab_New.ts index eb828837..7cc035b2 100644 --- a/M01_MasterData/M01_MasterData_UI_LogicLab_New.ts +++ b/M01_MasterData/M01_MasterData_UI_LogicLab_New.ts @@ -1,6 +1,6 @@ /* ============================================================================= * M01_MasterData_UI_LogicLab_New.ts - * 「로직 개선 시험」 — 식으로 새 로직 만들기 (PLAN 3-3 · 계약 `_화면_계약.md` 7장) + * 「단가산출 로직」 — 식으로 새 로직 만들기 (PLAN 3-3 · 계약 `_화면_계약.md` 7장) * ① 식을 줄로 적음 ② [분석] → 변수 표에서 변수마다 무엇인지·단위·비목을 고름 * ③ 이름·결과 단위 ④ 시험 계산으로 값을 보고 저장(자체 로직 · 키 GX) * 검사에 걸린 것은 그 줄·자리를 짚어 쉬운 말로 보임 — 서버 글 그대로(`문제`) diff --git a/M01_MasterData/M01_MasterData_UI_LogicLab_Text.ts b/M01_MasterData/M01_MasterData_UI_LogicLab_Text.ts index e884f5eb..eff054cb 100644 --- a/M01_MasterData/M01_MasterData_UI_LogicLab_Text.ts +++ b/M01_MasterData/M01_MasterData_UI_LogicLab_Text.ts @@ -1,6 +1,6 @@ /* ============================================================================= * M01_MasterData_UI_LogicLab_Text.ts - * 「로직 개선 시험」 컨테이너 글자 — [한국어, 영어] + * 「단가산출 로직」 컨테이너 글자 — [한국어, 영어] * ========================================================================== */ import { currentLanguageIndex } from "@ui/ui_template_locale"; @@ -53,7 +53,7 @@ const TEXT = { Pill_Table: ["표", "Table"], Pill_Logic: ["로직", "Logic"], Pill_Go: ["마스터 화면에서 보기", "Open in master"], - Pill_Back: ["← 로직 개선 시험으로 돌아가기", "← Back to logic lab"], + Pill_Back: ["← 단가산출 로직으로 돌아가기", "← Back to unit-price logic"], Pill_NoPick: [ "고르기 조건에 맞는 마스터 줄이 없음 — 단가를 못 찾음", "No master row matches the pick conditions", diff --git a/M01_MasterData/M01_MasterData_UI_Logic_Text.ts b/M01_MasterData/M01_MasterData_UI_Logic_Text.ts index 97a7b0c1..95c7137a 100644 --- a/M01_MasterData/M01_MasterData_UI_Logic_Text.ts +++ b/M01_MasterData/M01_MasterData_UI_Logic_Text.ts @@ -17,7 +17,6 @@ const TEXT = { List_New: ["새것", "New"], List_Deleted: ["지움", "Deleted"], Bar_Back: ["← 로직 목록", "← Logics"], - Bar_New: ["로직 새로 만들기", "New logic"], Bar_Delete: ["로직 지우기", "Delete logic"], Bar_Save: ["저장", "Save"], Bar_Discard: ["고친 것 버리기", "Discard edits"], @@ -85,7 +84,7 @@ const TEXT = { Save_Failed: ["저장 못 함", "Save failed"], Save_Nothing: ["고친 것 없음", "Nothing to save"], Load_Failed: ["불러오지 못함", "Load failed"], - Lab_Title: ["로직 개선 시험", "Logic — improvement lab"], + Lab_Title: ["단가산출 로직", "Unit-price logic"], Loading: ["불러오는 중", "Loading"], Confirm_Delete: [ "로직 「{v}」 을 지울까요? [저장] 때 파일에서 빠짐", diff --git a/M01_MasterData/M01_MasterData_UI_Page.ts b/M01_MasterData/M01_MasterData_UI_Page.ts index dd12bd71..211b16ff 100644 --- a/M01_MasterData/M01_MasterData_UI_Page.ts +++ b/M01_MasterData/M01_MasterData_UI_Page.ts @@ -1,6 +1,6 @@ /* ============================================================================= * M01_MasterData_UI_Page.ts - * 마스터 요소 화면 — 좌측 도킹 패널(컨테이너: 인력·재료·기계·소요량·계수·환율·요율·단가산출 로직·일위대가 조합·로직 테스트) + * 마스터 요소 화면 — 좌측 도킹 패널(컨테이너: 인력·재료·기계·소요량·계수·환율·요율·단가산출 로직·일위대가 조합) * / 우측 요소 표 · 표 목록 · 로직 편집 * * 시스템 관리자만. 고친 것은 초안(sessionStorage)에 쌓이고 [저장] 한 번에 서버로 — @@ -37,7 +37,7 @@ import { import { loadTable } from "./M01_MasterData_UI_Logic_Note"; import { tl } from "./M01_MasterData_UI_LogicLab_Text"; import { renderTables } from "./M01_MasterData_UI_Tables"; -import type { LogicHandle } from "./M01_MasterData_UI_Logic_Page"; +import type { LogicHandle } from "./M01_MasterData_UI_LogicLab"; import type { ComboHandle } from "./M01_MasterData_UI_Combo"; import "./M01_MasterData_UI_Style.css"; @@ -59,7 +59,6 @@ function buildPage(): HTMLElement { let query = ""; let dispose = (): void => {}; let logicMounted = false; - let labMounted = false; let comboHandle: ComboHandle | null = null; /* --- 우측: 머리(제목·찾기·저장) + 알림 + 본문 --- */ @@ -76,7 +75,6 @@ function buildPage(): HTMLElement { children: [title, searchField.root, summary, drop, save], }); const logicHost = el("div", { className: "m01-master__logic", attrs: { hidden: "" } }); - const labHost = el("div", { className: "m01-master__logic", attrs: { hidden: "" } }); const comboHost = el("div", { className: "m01-master__logic", attrs: { hidden: "" } }); const elementView = el("div", { className: "m01-master__elements", @@ -100,9 +98,8 @@ function buildPage(): HTMLElement { onDraftChange(refreshBar); refreshBar(); - const showMode = (mode: "elements" | "logic" | "lab" | "combo"): void => { + const showMode = (mode: "elements" | "logic" | "combo"): void => { logicHost.hidden = mode !== "logic"; - labHost.hidden = mode !== "lab"; comboHost.hidden = mode !== "combo"; elementView.hidden = mode !== "elements"; }; @@ -190,7 +187,7 @@ function buildPage(): HTMLElement { let logicHandle: LogicHandle | null = null; - /** 로직 탭으로 전환 — `key` 가 있으면 그 로직을 바로 엶. */ + /** 「단가산출 로직」 탭으로 전환 — `key` 가 있으면 그 로직을 바로 엶. */ const openLogicTab = (key?: string): void => { if (key) setPendingLogicKey(key); dispose(); @@ -203,23 +200,12 @@ function buildPage(): HTMLElement { return; } logicMounted = true; - void import("./M01_MasterData_UI_Logic_Page").then(async (m) => { + void import("./M01_MasterData_UI_LogicLab").then(async (m) => { const pending = takePendingLogicKey(); - logicHandle = await m.mountM01Logic(logicHost, side, pending ?? undefined); + logicHandle = await m.mountM01LogicLab(logicHost, side, pending ?? undefined); }); }; - /** 「로직 개선 시험」 — 정본 로직 화면의 복사본(개선은 여기서만) */ - const openLabTab = (): void => { - dispose(); - dispose = (): void => {}; - current = null; - showMode("lab"); - if (labMounted) return; - labMounted = true; - void import("./M01_MasterData_UI_LogicLab").then((m) => m.mountM01LogicLab(labHost, side)); - }; - /** 「일위대가 조합」 — 목록을 새로 받아 그림 · 로직 줄을 누르면 단가산출 로직 탭으로 */ const openComboTab = (): void => { dispose(); @@ -236,7 +222,7 @@ function buildPage(): HTMLElement { }); }; - /** 알약 → 마스터 화면 — 찾기 글을 그 키로 두고 열고, 알림줄에 「시험으로 돌아가기」를 둠 */ + /** 알약 → 마스터 화면 — 찾기 글을 그 키로 두고 열고, 알림줄에 「단가산출 로직으로 돌아가기」를 둠 */ const jump = async (target: MasterJump): Promise => { let group = target.kind === "element" ? target.group : ""; let file: FileInfo | undefined; @@ -258,7 +244,7 @@ function buildPage(): HTMLElement { const back = createButton({ label: tl("Pill_Back"), variant: "ghost" }); back.addEventListener("click", () => { showNotice([]); - openLabTab(); + openLogicTab(); }); showNotice([back]); if (target.kind === "table") { @@ -276,7 +262,7 @@ function buildPage(): HTMLElement { setMasterJump((target) => void jump(target)); /* --- 좌측: 컨테이너 --- */ - const side = buildSide(openFile, () => openLogicTab(), openLabTab, openComboTab); + const side = buildSide(openFile, () => openLogicTab(), openComboTab); const layout = el("div", { className: "ui-workflow-layout m01-master" }); const main = el("main", { @@ -284,7 +270,7 @@ function buildPage(): HTMLElement { children: [ el("div", { className: "m01-master__panel", - children: [elementView, logicHost, labHost, comboHost], + children: [elementView, logicHost, comboHost], }), ], }); diff --git a/M01_MasterData/M01_MasterData_UI_Side.ts b/M01_MasterData/M01_MasterData_UI_Side.ts index e379f5b4..4a98abae 100644 --- a/M01_MasterData/M01_MasterData_UI_Side.ts +++ b/M01_MasterData/M01_MasterData_UI_Side.ts @@ -59,7 +59,7 @@ export function takePendingLogicKey(): string | null { } } -/** 「로직 개선 시험」 알약 → 마스터 화면 — 표(키) 또는 요소(그룹 · 키 · 파일) */ +/** 「단가산출 로직」 알약 → 마스터 화면 — 표(키) 또는 요소(그룹 · 키 · 파일) */ export type MasterJump = { kind: "table"; key: string } | { kind: "element"; group: string; ref: string; file?: string }; @@ -88,8 +88,6 @@ export interface SideHandle { logicHost: HTMLElement; /** 일위대가 조합 컨테이너 안(구분 · 상세구분 거름이 들어갈 자리) */ comboHost: HTMLElement; - /** 「로직 개선 시험」 컨테이너 안 */ - labHost: HTMLElement; /** 그룹의 파일 판본을 다시 받음(저장 뒤) — 돌려받는 것 = 새 목록 */ refresh: (group: string) => Promise; /** 그룹의 파일 목록(이미 받은 것) */ @@ -147,13 +145,11 @@ const LEAF: Group[] = ["환율", "요율"]; /** 거름이 있는 컨테이너 — 펼치면 「전체」(또는 닫기 전 거름) 이 바로 열림 */ const FILTERED: Group[] = ["인력", "기계", "소요량", "계수"]; const LOGIC_ID = "로직|"; -const LAB_ID = "로직시험|"; const COMBO_ID = "조합|"; export function buildSide( onOpen: (pick: Pick) => void, onLogic: () => void, - onLab: () => void, onCombo: () => void = () => {}, ): SideHandle { const lists = new Map(); @@ -447,7 +443,7 @@ ${first.file}` }); const logicHost = el("div", { className: "m01-side__items" }); - const logic = section(L("M01_GroupLogic"), logicHost); + const logic = section(tx("Lab_Title"), logicHost); logic.querySelector(".ui-collapsible__title")?.addEventListener("click", () => { if (!logic.classList.contains("is-collapsed")) return; // 닫을 때는 그대로 둠 setActive(buttons.has(LOGIC_ID) ? LOGIC_ID : null); @@ -462,15 +458,7 @@ ${first.file}` onCombo(); }); - const labHost = el("div", { className: "m01-side__items" }); - const lab = section(tx("Lab_Title"), labHost); - lab.querySelector(".ui-collapsible__title")?.addEventListener("click", () => { - if (!lab.classList.contains("is-collapsed")) return; - setActive(buttons.has(LAB_ID) ? LAB_ID : null); - onLab(); - }); - - const root = el("div", { className: "m01-side", children: [...groups, logic, combo, lab] }); + const root = el("div", { className: "m01-side", children: [...groups, logic, combo] }); attachCollapsible(root); void Promise.all(GROUPS.map(refresh)).catch((error) => showToast(error instanceof Error ? error.message : L("M01_LoadFailed"), "error"), @@ -479,5 +467,5 @@ ${first.file}` onPicked = fn; }; const files = (group: string): FileInfo[] => lists.get(group as Group) ?? []; - return { root, logicHost, comboHost, labHost, refresh, files, setActive, setOnPicked, filter }; + return { root, logicHost, comboHost, refresh, files, setActive, setOnPicked, filter }; } diff --git a/M01_MasterData/M01_MasterData_UI_Logic_Page.ts b/old_code/M01_MasterData/M01_MasterData_UI_Logic_Page.ts similarity index 90% rename from M01_MasterData/M01_MasterData_UI_Logic_Page.ts rename to old_code/M01_MasterData/M01_MasterData_UI_Logic_Page.ts index 21f961e0..f3df09df 100644 --- a/M01_MasterData/M01_MasterData_UI_Logic_Page.ts +++ b/old_code/M01_MasterData/M01_MasterData_UI_Logic_Page.ts @@ -1,5 +1,12 @@ /* ============================================================================= - * M01_MasterData_UI_Logic_Page.ts + * M01_MasterData_UI_Logic_Page.ts (은퇴 — PLAN 7-1 로 「단가산출 로직」 컨테이너를 + * `M01_MasterData_UI_LogicLab.ts` 하나로 합치며 old_code/ 로 옮김 · 빌드에서 빠짐 · 지우지 않고 자료로만 둠) + * + * 옛 「단가산출 로직」 컨테이너 — 정본 GC·GF 로직을 화면에서 바로 고쳐 저장 · 정본 파일에 빈 줄 더하는 + * 두 길이 여기에만 있었음(새 컨테이너는 자체 GX 로직만 고침) — 사용자 확정으로 버림. + * 경로만 옮김 · import 는 위 M01_MasterData/ 의 그대로 남은 파일을 가리키도록 고침(통째 복사 아님). + * 분석 = resources/master_data/ref/_분석_로직컨테이너_통합.md. + * * 관리자 화면 — 로직 칸. 가운데 단가산출 상세(호표) 고치기 / 오른쪽 시험 계산 * 로직 목록(원문·장 고르기 · 찾기 · 막힘 거름)은 왼쪽 패널 「단가산출 로직」 컨테이너(`listHost`) 안 * @@ -29,14 +36,19 @@ import { type LogicRow, type LogicSummary, type SaveFile, -} from "./M01_MasterData_UI_Logic_Api"; -import { buildCalc } from "./M01_MasterData_UI_Logic_Calc"; -import { buildEditor } from "./M01_MasterData_UI_Logic_Edit"; -import { buildList, logicId, type ListItem, type ListMark } from "./M01_MasterData_UI_Logic_List"; -import { openPicker } from "./M01_MasterData_UI_Logic_Pick"; -import type { SideHandle } from "./M01_MasterData_UI_Side"; -import { tx } from "./M01_MasterData_UI_Logic_Text"; -import "./M01_MasterData_UI_Logic_Style.css"; +} from "../../M01_MasterData/M01_MasterData_UI_Logic_Api"; +import { buildCalc } from "../../M01_MasterData/M01_MasterData_UI_Logic_Calc"; +import { buildEditor } from "../../M01_MasterData/M01_MasterData_UI_Logic_Edit"; +import { + buildList, + logicId, + type ListItem, + type ListMark, +} from "../../M01_MasterData/M01_MasterData_UI_Logic_List"; +import { openPicker } from "../../M01_MasterData/M01_MasterData_UI_Logic_Pick"; +import type { SideHandle } from "../../M01_MasterData/M01_MasterData_UI_Side"; +import { tx } from "../../M01_MasterData/M01_MasterData_UI_Logic_Text"; +import "../../M01_MasterData/M01_MasterData_UI_Logic_Style.css"; /** 저장 안 한 로직 하나 — origKey null = 새 로직 · row null = 지움 */ interface Draft {