From 8712076fc55ff54c2f572c79dba8f1f5dd4d15b0 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Fri, 9 Oct 2026 19:05:26 +0900 Subject: [PATCH] =?UTF-8?q?feat(m02):=20=E3=80=8C=EC=86=90=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=E3=80=8D=20=E2=86=92=20=E3=80=8C=EC=88=98=EA=B8=B0=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=E3=80=8D=20=C2=B7=20[=EB=A9=B4=EC=A0=81?= =?UTF-8?q?=EC=82=B0=EC=B6=9C=EC=97=90=EC=84=9C=20=EC=9E=87=EA=B8=B0]=20?= =?UTF-8?q?=C2=B7=20goArea=20=EA=B1=B7=EC=96=B4=20=EB=83=84(147-4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01QND7Co43B24zK2P937rdxt --- .../M02_MasterTemplete_CardHelp.ts | 4 ++-- .../M02_MasterTemplete_ItemCards.ts | 1 - .../M02_MasterTemplete_Labor_Detail.ts | 5 +--- .../M02_MasterTemplete_Labor_Input.ts | 3 --- .../M02_MasterTemplete_Labor_QtyModal.ts | 24 ++++--------------- .../M02_MasterTemplete_Labor_RefEdit.ts | 1 - .../M02_MasterTemplete_Labor_Rows.ts | 8 +++---- .../M02_MasterTemplete_Labor_Text.ts | 9 ++++--- .../M02_MasterTemplete_UI_Main.ts | 7 ------ resources/tester/test_m02_labor_values.py | 4 ++-- resources/tester/test_modal_head_actions.py | 13 ++++++++++ 11 files changed, 31 insertions(+), 48 deletions(-) diff --git a/M02_MasterTemplete/M02_MasterTemplete_CardHelp.ts b/M02_MasterTemplete/M02_MasterTemplete_CardHelp.ts index 1547bfc40..9f34e5722 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_CardHelp.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_CardHelp.ts @@ -63,7 +63,7 @@ export const CARD_HELP: Record<"structure" | "labor" | "area", CardHelp> = { ["수정", "일위대가 상세를 엶 — 로직 추가 · 순서 바꾸기 · 다이어그램은 여기"], clear("일위대가"), ["로직 줄 누름", "넣을 값 창 — 그 로직의 넣을 값 고침"], - ["수량산출 칸", "손 입력 · 면적산출 칸 고르기"], + ["수량산출 칸", "수기 입력 · 면적산출 칸 고르기"], ["별칭 칸", "줄에 따로 이름 붙임"], ["줄 끝 단추", "그 줄을 뺌"], ["자재 추가", "자재를 골라 자재목록에 넣음"], @@ -72,7 +72,7 @@ export const CARD_HELP: Record<"structure" | "labor" | "area", CardHelp> = { steps: [ "왼쪽 표에서 구조물 항목을 고름", "로직 줄을 눌러 넣을 값을 고침", - "수량산출 칸에서 손 입력 또는 면적산출 칸을 고름", + "수량산출 칸에서 수기 입력 또는 면적산출 칸을 고름", "[저장] — 로직을 더하거나 순서를 바꿀 때는 [수정]", ], }, diff --git a/M02_MasterTemplete/M02_MasterTemplete_ItemCards.ts b/M02_MasterTemplete/M02_MasterTemplete_ItemCards.ts index 466cb0411..595e930a1 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_ItemCards.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_ItemCards.ts @@ -319,7 +319,6 @@ export function createItemCards(opts: ItemCardsOptions): ItemCardsHandle { } : {}), onChanged: (dirty) => laborCard.saver.mark(dirty && laborWritable()), - goArea: null, // 면적 칸 잇기는 수량 모달 안(43-1) — 카드에서 화면을 옮기지 않음 card: true, }); }; diff --git a/M02_MasterTemplete/M02_MasterTemplete_Labor_Detail.ts b/M02_MasterTemplete/M02_MasterTemplete_Labor_Detail.ts index 33ba90be7..9c6a02cb0 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Labor_Detail.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_Labor_Detail.ts @@ -54,7 +54,7 @@ import { diagramTitle, renderComboDiagram, } from "./M02_MasterTemplete_Labor_Diagram"; -import { openLaborInput, type GoArea } from "./M02_MasterTemplete_Labor_Input"; +import { openLaborInput } from "./M02_MasterTemplete_Labor_Input"; import { openQtyModal } from "./M02_MasterTemplete_Labor_QtyModal"; import { openRefEdit } from "./M02_MasterTemplete_Labor_RefEdit"; import { afterRowDrag } from "./M02_MasterTemplete_Labor_RowDrag"; @@ -79,8 +79,6 @@ export interface LaborDetailOptions { readOnly: boolean; /** 저장 안 한 고침이 생기거나 사라짐 */ onChanged: (dirty: boolean) => void; - /** 「면적산출에서 잇기」 — 그 열 면적산출 상세로(옮겨 가면 참 · 취소 = 거짓 · 없으면 단추 없음) */ - goArea: GoArea | null; /** 구조물 조합 카드 갈래(43-4) — 단가산출 로직 표 + 자재목록만 · 위로 · 아래로 · 로직 추가 · * 자재 추가 · 정보(단위 · 본뜬) · 다이어그램 없음 · 옵션 · 삭제 · 줄 · 수량 모달은 상세와 같음 */ card?: boolean; @@ -318,7 +316,6 @@ export function mountLaborDetail( unit, readOnly: !edit, sheet: { doc: area?.doc ?? null, layer: opt.layer, column: opt.column, pill }, - goArea: opt.goArea, ...(lib ? { handOnly: true } : {}), done: (r) => { if (r.kind === "keep") return; diff --git a/M02_MasterTemplete/M02_MasterTemplete_Labor_Input.ts b/M02_MasterTemplete/M02_MasterTemplete_Labor_Input.ts index cc2d42196..75f48475d 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Labor_Input.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_Labor_Input.ts @@ -16,9 +16,6 @@ import "./M02_MasterTemplete_Labor.css"; const fill = (text: string, value: string): string => text.replace("{value}", value); -/** 면적산출 상세로 감 — 옮겨 갔으면 참(물음에서 취소 = 거짓) */ -export type GoArea = () => Promise; - export interface LaborInputResult { 입력값: LaborValues; 메모: string | null; diff --git a/M02_MasterTemplete/M02_MasterTemplete_Labor_QtyModal.ts b/M02_MasterTemplete/M02_MasterTemplete_Labor_QtyModal.ts index b54f34abc..9718335f6 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Labor_QtyModal.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_Labor_QtyModal.ts @@ -1,10 +1,10 @@ /* ============================================================================= * M02_MasterTemplete_Labor_QtyModal.ts * 일위대가 수량산출 모달(43-1) — 수량산출 칸 누름(로직 줄 · 자재 줄 같음) = 모달 하나. - * · 위 = 지금 수량(손 · 칸 · —) · 손 입력 칸 · [연결 풀기] + * · 위 = 지금 수량(수기 · 칸 · —) · 수기 입력 칸 · [연결 풀기] * · 아래 = 그 열 면적산출 시트를 모달 안에 바로(읽기만 · 실제 값 · 이은 칸 색 · `mountAreaSheet`) · * 칸 누름 = 그 칸을 고름(함께 잇기 · 바꾸기 물음 그대로) - * · 머리 [확인] = 손 값이 있으면 손 · 아니면 고른 칸으로 잇기 · 풀기 · 머리 [닫기] = 그대로 + * · 머리 [확인] = 수기 값이 있으면 수기 · 아니면 고른 칸으로 잇기 · 풀기 · 머리 [닫기] = 그대로 * 잇기 · 풀기는 화면 문서만(저장은 일위대가 [저장] 때 면적 문서와 함께 · `Labor_Detail`). * ========================================================================== */ @@ -13,7 +13,6 @@ import { openModal } from "@ui/ui_template_modal"; import type { Workbook } from "../A00_Common/spreadsheet/spreadsheet"; import type { Layer } from "./M02_MasterTemplete_Api_Fetch"; import { mountAreaSheet, type AreaCellPick } from "./M02_MasterTemplete_AreaCellPick"; -import type { GoArea } from "./M02_MasterTemplete_Labor_Input"; import { tc } from "./M02_MasterTemplete_Labor_Text"; import "./M02_Labor_Values.css"; import "./M02_MasterTemplete_Labor.css"; @@ -29,20 +28,18 @@ export type QtyResult = export interface QtyModalOptions { /** 「GF000219 돌쌓기 메쌓기(인력)」 */ title: string; - /** 지금 수량 글(「손 5 ㎥」 · 「B6 = 12.5」 · 「—」) */ + /** 지금 수량 글(「수기 5 ㎥」 · 「B6 = 12.5」 · 「—」) */ now: string; /** 지금 칸에 이어져 있나 — [연결 풀기] */ linked: boolean; /** 지금 손 값(없으면 null) */ hand: number | null; - /** 손 입력 단위(분모 · 자재 단위) */ + /** 수기 입력 단위(분모 · 자재 단위) */ unit: string; readOnly: boolean; /** 그 열 면적산출 — `pill` 이 없으면(계산 전) 시트 대신 안내 */ sheet: { doc: Workbook | null; layer: Layer; column: string; pill: string | null }; - /** [면적산출 상세로] — 없으면 단추 없음 */ - goArea: GoArea | null; - /** 손 입력만(서고 사전조합 줄 · 51-6) — 면적산출 시트 없음 */ + /** 수기 입력만(서고 사전조합 줄 · 51-6) — 면적산출 시트 없음 */ handOnly?: boolean; done: (result: QtyResult) => void; } @@ -92,16 +89,6 @@ export function openQtyModal(opt: QtyModalOptions): void { }, }) : null; - const go = opt.goArea - ? createButton({ - label: tc("In_QtyGoArea"), - variant: "ghost", - onClick: () => - void opt.goArea?.().then((moved) => { - if (moved) finish(); - }), - }) - : null; const host = el("div", { className: "m02-cellpick__sheet", attrs: { "data-labor-qty-sheet": "" }, @@ -153,7 +140,6 @@ export function openQtyModal(opt: QtyModalOptions): void { ], }), ...(unlink ? [unlink] : []), - ...(go ? [go] : []), ], }), state, diff --git a/M02_MasterTemplete/M02_MasterTemplete_Labor_RefEdit.ts b/M02_MasterTemplete/M02_MasterTemplete_Labor_RefEdit.ts index ae980c9ae..109fca8ee 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Labor_RefEdit.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_Labor_RefEdit.ts @@ -66,7 +66,6 @@ export async function openRefEdit(opt: RefEditOptions): Promise { column: opt.ref.키, readOnly: opt.readOnly, onChanged: (d) => (dirty = d && !opt.readOnly), - goArea: null, mode: "precombo", owner: opt.ref.주인, }); diff --git a/M02_MasterTemplete/M02_MasterTemplete_Labor_Rows.ts b/M02_MasterTemplete/M02_MasterTemplete_Labor_Rows.ts index adb93289c..298e793f2 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Labor_Rows.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_Labor_Rows.ts @@ -77,7 +77,7 @@ const BOOK = /^(건설|산림)품셈/; const num = (v: number): string => Number(v.toPrecision(12)).toLocaleString("ko-KR", { maximumFractionDigits: 6 }); -/** 수량 글 — 「수량 손 3 개소」 · 「수량 12.5 ㎡(B6)」(칸 = 그 알약을 이은 면적산출 칸 · 44-6) · +/** 수량 글 — 「수량 수기 입력 3 개소」 · 「수량 12.5 ㎡(B6)」(칸 = 그 알약을 이은 면적산출 칸 · 44-6) · * 이은 칸이 비었으면 「수량 빈 칸(A1)」(수량 없음 · 서버와 같음) · 아니면 빈 글 */ export function qtyText( line: { 수량?: number | null; 수량출처?: string; 알약?: string | null } | undefined, @@ -103,7 +103,7 @@ export function baseQtyText( return `${num(line.배 || 1)} ${line.분모}`; } -/** 지금 수량 짧은 글 — 「손 5 ㎥」 · 「12.5(B6)」 · 「빈 칸(B6)」 · 없으면 「—」 */ +/** 지금 수량 짧은 글 — 「수기 5 ㎥」 · 「12.5(B6)」 · 「빈 칸(B6)」 · 없으면 「—」 */ export function qtyShort( line: { 수량?: number | null; 수량출처?: string; 알약?: string | null } | undefined, unit: string, @@ -117,7 +117,7 @@ export function qtyShort( return `${num(line.수량)}(${at ?? tc("In_QtyCell")})`; } -/** 수량산출 칸(40-1) — 위 결과단위 기준 수량(「10 ㎡」) · 아래 지금 수량(「손 5 ㎥」 · 「12.5(B6)」 · 「—」) · +/** 수량산출 칸(40-1) — 위 결과단위 기준 수량(「10 ㎡」) · 아래 지금 수량(「수기 5 ㎥」 · 「12.5(B6)」 · 「—」) · * `open` 이 있으면 단추(줄 누름과 따로) */ function qtyCell( line: LaborCalcLine | undefined, @@ -204,7 +204,7 @@ export interface RowHandlers { option?: (i: number) => void; /** 참조 줄 단추(51-14) — 일위조합 [수정] = 서고 원본 모달 · 없으면 단추 없음 */ ref?: (i: number) => void; - /** 수량산출 칸 누름(손 입력 · 엑셀에서 고르기) — 없으면 줄 누름과 같음 */ + /** 수량산출 칸 누름(수기 입력 · 엑셀에서 고르기) — 없으면 줄 누름과 같음 */ qty?: (i: number) => void; /** 줄 순서(85-3) — from 줄을 to 자리로(▲▼ = 옆 자리 · 줄 끌기 102-2 = 놓은 줄 자리) */ move?: (from: number, to: number) => void; diff --git a/M02_MasterTemplete/M02_MasterTemplete_Labor_Text.ts b/M02_MasterTemplete/M02_MasterTemplete_Labor_Text.ts index 90b450800..ec2e896d4 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Labor_Text.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_Labor_Text.ts @@ -70,8 +70,8 @@ const TEXT = { Labor_Qty: ["수량", "Quantity"], Labor_QtyCol: ["수량산출", "Quantity"], Labor_Item: ["항목", "Item"], - Labor_Hand: ["손", "Manual"], - Labor_QtyPick: ["누르면 손 입력 · 엑셀에서 고르기", "Manual or pick a cell"], + Labor_Hand: ["수기", "Manual"], + Labor_QtyPick: ["누르면 수기 입력 · 엑셀에서 고르기", "Manual or pick a cell"], Labor_PickWait: ["계산이 끝난 뒤 고름", "Wait for the calculation"], Labor_NoArea: ["이 열 면적산출을 못 읽음", "Area sheet not loaded"], Labor_BadCell: ["칸 주소가 틀림", "Invalid cell"], @@ -131,9 +131,8 @@ const TEXT = { Labor_Layer: ["켜쌓기 {n}%", "Layered {n}%"], In_QtyCell: ["면적산출 칸", "Area sheet cell"], In_QtyEmpty: ["빈 칸", "empty cell"], - In_QtyHand: ["손 입력", "Manual"], - In_QtyGoArea: ["면적산출에서 잇기", "Link in area sheet"], - In_QtyNeed: ["손 입력 수량을 수로 적음", "Enter a number"], + In_QtyHand: ["수기 입력", "Manual"], + In_QtyNeed: ["수기 입력 수량을 수로 적음", "Enter a number"], In_Bad: ["범위 밖 값이 있음 — 고친 뒤 확인", "Out-of-range values — fix first"], In_Ok: ["확인", "OK"], In_Close: ["닫기", "Close"], diff --git a/M02_MasterTemplete/M02_MasterTemplete_UI_Main.ts b/M02_MasterTemplete/M02_MasterTemplete_UI_Main.ts index 31b05e1f4..b39d8309b 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_UI_Main.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_UI_Main.ts @@ -423,13 +423,6 @@ export function createMain( column: at.name, readOnly, onChanged: (d) => (dirty = d && !readOnly), - goArea: mode - ? null - : async () => { - if (!(await confirmLeave())) return false; // 취소 — 입력 모달 그대로 - void open({ ...at, kind: "area" }); - return true; - }, ...(mode ? { mode, owner: at.owner ?? null } : {}), }); // [저장] = 엑셀에서 고른 칸 연결(면적 문서) 먼저 · 그다음 일위대가(서버가 새 칸 값으로 계산값) diff --git a/resources/tester/test_m02_labor_values.py b/resources/tester/test_m02_labor_values.py index e800b2d63..d9324de41 100644 --- a/resources/tester/test_m02_labor_values.py +++ b/resources/tester/test_m02_labor_values.py @@ -184,11 +184,11 @@ def test_수량_글은_이은_칸_주소를_보임() -> None: assert out.returncode == 0, out.stderr got = json.loads(out.stdout) # 수량산출 열(40-1) — 위 결과단위 기준 수량 · 아래 지금 수량 짧은 글 - assert got[:7] == ["10 ㎡", "1 ㎥", "", "손 5 ㎥", "12.5(B6)", "빈 칸(B6)", "—"] + assert got[:7] == ["10 ㎡", "1 ㎥", "", "수기 5 ㎥", "12.5(B6)", "빈 칸(B6)", "—"] assert got[7:] == [ "수량 20 ㎡(B6)", # 44-6 — 수량(칸 주소) "수량 20 ㎡(면적산출 칸)", - "수량 손 입력 3 ㎡", + "수량 수기 입력 3 ㎡", "수량 빈 칸(B6)", # 이은 칸이 비었음 = 수량 없음(39-8 ② · 서버 area_values 와 같음) "", ] diff --git a/resources/tester/test_modal_head_actions.py b/resources/tester/test_modal_head_actions.py index 8c42f863b..d08bbe82a 100644 --- a/resources/tester/test_modal_head_actions.py +++ b/resources/tester/test_modal_head_actions.py @@ -3,6 +3,7 @@ · 147-1 곁값 `actions`(머리 [닫기] 바로 왼쪽 · 넘긴 창만) · `wide`(96vw × 94vh · 몸만 스크롤) · 147-2 연결창 단추 넷 → 머리 · 큰 창 · 글 묻는 창 [확인] 머리 · [취소] 없음 · 147-3 M02 입력 · 수량산출 · 참조 창 — 아래 단추 줄 없음 · [확인] 머리 · 읽기만이면 없음 +· 147-4 「손 입력」 → 「수기 입력」 · 짧은 글 「손」 → 「수기」 · [면적산출에서 잇기] · goArea 없음 """ from __future__ import annotations @@ -80,3 +81,15 @@ def test_147_3_m02_창_셋_머리_확인(): assert "if (!opt.readOnly)" in ts and "head.append(" in ts, name assert "In_Cancel" not in _text(f"{m02}Labor_Text.ts") assert ".m02-labin__foot" not in _text(f"{m02}Labor.css") + + +def test_147_4_수기_입력_잇기_없음(): + m02 = ROOT / "M02_MasterTemplete" + text = _text("M02_MasterTemplete/M02_MasterTemplete_Labor_Text.ts") + assert 'In_QtyHand: ["수기 입력", "Manual"],' in text + assert 'Labor_Hand: ["수기", "Manual"],' in text + assert "In_QtyGoArea" not in text + assert "손 입력" not in _text("M02_MasterTemplete/M02_MasterTemplete_CardHelp.ts") + for path in m02.glob("*.ts"): + src = path.read_text(encoding="utf-8") + assert "goArea" not in src and "GoArea" not in src, path.name