diff --git a/M01_MasterData/M01_MasterData_UI_Logic_Calc.ts b/M01_MasterData/M01_MasterData_UI_Logic_Calc.ts index 4aa40833c..6bfa49452 100644 --- a/M01_MasterData/M01_MasterData_UI_Logic_Calc.ts +++ b/M01_MasterData/M01_MasterData_UI_Logic_Calc.ts @@ -28,6 +28,7 @@ import { formatNumber } from "./M01_MasterData_UI_Logic_Edit"; import { formatMoney } from "./M01_MasterData_UI_Logic_Money"; import { safeReason, tx } from "./M01_MasterData_UI_Logic_Text"; import { createBadge } from "@ui/ui_template_badge"; +import { createDivider } from "@ui/ui_template_divider"; /** 고르기 값이 마스터 키(자재·기계·직종)면 이름으로 바꿔 보임 — 값 칸은 키 그대로 보냄 */ const KEY_RE = /^[A-Z]{2}\d{6}$/; @@ -67,6 +68,9 @@ export interface CalcContext { onText?: (answer: TextAnswer) => void; } +const grid = (children: HTMLElement[]): HTMLElement => + el("div", { className: "m01-logic__head", children }); + const SUMS = ["노무비", "재료비", "경비", "계"]; /** 로직마다 자동값을 한 번만 받음(다시 그려도 안 부름) */ @@ -122,7 +126,7 @@ export function buildCalc(host: HTMLElement, ctx: CalcContext): void { control = box; } const label = spec.단위 ? `${name} (${spec.단위})` : name; - // 긴 이름 줄만 한 칸 다 씀 — 고르기 줄은 짧으면 그대로 2열에 맞춰 나란히 + // 긴 이름 줄만 두 칸 차지 — 짧으면 4 열에 맞춰 나란히 const wide = label.length > 10; return el("label", { className: `m01-logic__field${wide ? " m01-logic__field--wide" : ""}`, @@ -196,8 +200,13 @@ export function buildCalc(host: HTMLElement, ctx: CalcContext): void { runButton.setAttribute("data-calc-run", ""); host.replaceChildren( el("h3", { text: tx("Calc_Title") }), + // 옵션 고르기 · 자재 고르기 두 격자(기본 4 열) — 사이 수평 구분선(709-1 부품) ...(fields.length || materials.length - ? [el("div", { className: "m01-logic__head", children: [...fields, ...materials] })] // 요소 표가 쓰는 auto-fill 그리드 재사용 — 2열 + ? [ + ...(fields.length ? [grid(fields)] : []), + ...(fields.length && materials.length ? [createDivider()] : []), + ...(materials.length ? [grid(materials)] : []), + ] : [el("p", { className: "ui-text ui-text--muted", text: tx("Calc_NoInputs") })]), runButton, out, diff --git a/M01_MasterData/M01_MasterData_UI_Logic_CalcPick.ts b/M01_MasterData/M01_MasterData_UI_Logic_CalcPick.ts index 227dc95df..1b608b92e 100644 --- a/M01_MasterData/M01_MasterData_UI_Logic_CalcPick.ts +++ b/M01_MasterData/M01_MasterData_UI_Logic_CalcPick.ts @@ -1,6 +1,6 @@ /* ============================================================================= * M01_MasterData_UI_Logic_CalcPick.ts - * 시험 계산의 재료 · 기계 고르기 — 재료 줄마다 「잡힌 품목 + 품목 고르기」 · 기계 입력은 단추 하나 + * 시험 계산의 재료 · 기계 고르기 — 재료 칸마다 잡힌 품목 이름(누르면 고르기) · 기계 입력은 단추 하나 * 누르면 마스터 표 모달(`PickTable`) · 고른 재료는 `고름`(호표 줄 차례 → 키)에 실어 다시 계산 · 저장 안 함 * ========================================================================== */ @@ -49,10 +49,11 @@ const isMachineInput = (spec: LogicInput): boolean => const pickButton = (label: string, onClick: () => void): HTMLButtonElement => createButton({ label, variant: "ghost", onClick }); -const line = (label: string, current: HTMLElement, button: HTMLElement): HTMLElement => +/** 자재 칸 — 이름 + 잡힌 품목(누르면 고르기 모달) · 긴 이름은 두 칸 */ +const line = (label: string, current: HTMLElement): HTMLElement => el("div", { - className: "m01-logic__field m01-logic__field--wide", - children: [el("span", { text: label }), el("div", { children: [current, button] })], + className: `m01-logic__field${label.length > 10 ? " m01-logic__field--wide" : ""}`, + children: [el("span", { text: label }), current], }); /** 재료 줄마다 한 칸 — 지금 잡힌 품목 + 품목 고르기 */ @@ -80,12 +81,16 @@ export function materialRows( const seeds = [cond?.["검색어"], cond?.이름, cond?.상세구분, cond?.구분, label] .map(headWord) .filter((w, k, all) => w && all.indexOf(w) === k); - const current = el("span", { - className: "ui-text ui-text--muted", - text: `${nowName || tx("Mat_NoPrice")} `, - attrs: { "data-mat-idx": String(i), "data-ref": brief?.ref ?? "" }, + // 잡힌 품목 이름 = 링크 단추 — 누르면 고르기 모달([품목 고르기] 단추 걷음) + const current = createButton({ + label: nowName || tx("Mat_NoPrice"), + variant: "link", + onClick: () => pick(), }); - const button = pickButton(tx("Pick_Item"), () => + current.dataset.matIdx = String(i); + current.dataset.ref = brief?.ref ?? ""; + current.title = tx("Pick_Item"); + const pick = (): void => openPickTable({ kind: "재료", title: `${tx("Pick_MatTitle")} · ${label}`, @@ -94,12 +99,11 @@ export function materialRows( isCurrent: (r) => String(r["키"]) === (mine.get(i)?.ref ?? current.dataset.ref), onPick: (r) => { mine.set(i, { ref: String(r["키"]), label: nameOf(r) }); - current.textContent = `${nameOf(r)} `; + current.textContent = nameOf(r); again(); }, - }), - ); - return line(`${label}${item.규격 ? ` ${item.규격}` : ""}`, current, button); + }); + return line(`${label}${item.규격 ? ` ${item.규격}` : ""}`, current); }); } @@ -115,7 +119,7 @@ export function showItems( const item = lines[i]?.품목; if (!item || mine.has(i)) return; span.dataset.ref = item.키; - span.textContent = `${`${item.이름 ?? ""} ${item.규격 ?? ""}`.trim() || item.키} `; + span.textContent = `${item.이름 ?? ""} ${item.규격 ?? ""}`.trim() || item.키; }); } diff --git a/M01_MasterData/M01_MasterData_UI_Logic_Style.css b/M01_MasterData/M01_MasterData_UI_Logic_Style.css index 5d5a9e7ef..287baba33 100644 --- a/M01_MasterData/M01_MasterData_UI_Logic_Style.css +++ b/M01_MasterData/M01_MasterData_UI_Logic_Style.css @@ -73,11 +73,24 @@ gap: var(--spacing-8); } -/* 시험 계산 입력만 2열 고정 — 요소 표 쪽(auto-fill)은 그대로 둠 +/* 시험 계산 입력만 4열 고정(옵션 · 자재 격자 둘) — 요소 표 쪽(auto-fill)은 그대로 둠 · 긴 이름 칸은 두 칸 실제 그릇은 LogicLab 이 씌우는 `.m01lab__calc`(`.m01-logic__calc` 는 옛 테스트 컨테이너 몫이라 안 걸림) */ .m01lab__calc .m01-logic__head, .m01-logic__calc .m01-logic__head { - grid-template-columns: repeat(2, 1fr); + grid-template-columns: repeat(4, minmax(0, 1fr)); +} + +.m01lab__calc .m01-logic__field--wide { + grid-column: span 2; +} + +/* 자재 칸 잡힌 품목 링크 — 칸 폭 안에서 왼쪽 맞춤 · 넘치면 말줄임 */ +.m01lab__calc .m01-logic__field > .ui-btn--link { + justify-content: flex-start; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .m01-logic__field {