/* ============================================================================= * line_stack_pick.ts * 줄 쌓기 고르기 창(PLAN 804-3 · 요구 678-1 · 678-3) * 찾아 넣기 = M02 [항목 추가] 창 그대로(`openFindPicker` · 탭 M01 전체 · 찾기 칸 · 표) — 줄 갈래마다 그 종류만 * 인력(노임 LB) · 재료(자재 MT) · 기계(EQ → 시간당 경비 로직 + 기계='원문번호') · 다른 단가산출(M01 단가산출 로직) * M02 단가산출 · 일위대가 탭은 안 보임 — 수식 문서 연결은 M01 키만 셈 * 표 고르기 = 품셈 표(조건 칸 + 값 칸) · 값 칸 누름 = 그 줄 · 칸 · 지금 닿는 칸 강조 · * 옵션에 매인 조건 = 그 줄만 고를 수 있음(다른 줄은 막힘 + 「위 옵션에서 고름」 안내) * ========================================================================== */ import { createButton } from "@ui/ui_template_button"; import { eqText } from "@ui/ui_template_equation"; import { el } from "@ui/ui_template_elements"; import { openModal } from "@ui/ui_template_modal"; import { tableRow, tableShell, type Column } from "@ui/ui_template_table"; import { createText } from "@ui/ui_template_text"; import type { DocTable } from "../common_util/common_util_formula_doc_table"; import type { MoneyKind } from "../common_util/common_util_line_stack"; import type { Picked } from "../common_util/common_util_line_stack_pick"; import { openFindPicker, type FindKind } from "../M02_MasterTemplete/M02_MasterTemplete_Find_Pick"; import { lt } from "./line_stack_text"; const KINDS: Partial> = { 인력: "labor", 재료: "material", 기계: "machine", 단가산출: "logic", }; /** 찾아 넣기 — 고르면 `done(고른 것)` · 닫으면 아무것도 안 함 */ export function openStackPick(kind: MoneyKind, done: (p: Picked) => void): void { const want = KINDS[kind]; if (!want) return; const spec = (e: { 규격: string }) => (e.규격 ? { 규격: e.규격 } : {}); openFindPicker({ layer: "system", owner: null, title: `${lt("Find_Title")} — ${lt(`K_${kind}` as never)}`, kinds: [want], logic: (x) => done({ 키: x.키, 이름: x.이름, 단위: x.결과단위.replace(/^원\/?/, "") }), element: (e) => done({ 키: e.코드, 이름: e.이름, 단위: e.단위, ...spec(e) }), machine: (e) => e.로직 && e.원문번호 ? done({ 키: e.로직, 이름: e.이름, 입력: { 기계: `'${e.원문번호}'` }, ...spec(e) }) : undefined, }); } const isNum = (v: unknown): boolean => typeof v === "number" || (typeof v === "string" && v.trim() !== "" && Number.isFinite(Number(v))); const cellText = (v: unknown): string => Array.isArray(v) ? `${v[0] ?? ""} ~ ${v[1] ?? ""}` : isNum(v) ? eqText(Number(v)) : String(v ?? ""); export interface TablePick { table: DocTable; /** 지금 닿는 줄(-1 = 없음) · 칸 */ now: number; col: string; /** 옵션에 매인 조건 — {조건 칸: 옵션 열쇠들} */ bound: Record; done: (row: Record, col: string) => void; } /** 표 고르기 창 — 값 칸 누름 = 고름 */ export function openTablePick(o: TablePick): void { const t = o.table; const conds = Object.keys(t.조건 ?? {}); const valueCols = [ ...new Set([...Object.keys(t.값칸 ?? {}), ...t.줄.flatMap((r) => Object.keys(r))]), ].filter((k) => !conds.includes(k)); const locked = Object.keys(o.bound).length > 0; const columns: Column[] = [ ...conds.map((c) => ({ label: c })), ...valueCols.map((c) => { const unit = (t.값칸 ?? {})[c]; return { label: unit ? `${c} (${String(unit)})` : c, align: "end" as const }; }), ]; openModal({ title: [t.원문번호, (t as { 이름?: string }).이름].filter(Boolean).join(" "), closeLabel: lt("Close"), width: "960px", mount: (body, close) => { const { root, tbody } = tableShell(columns, { density: "data" }); t.줄.forEach((row, k) => { const off = locked && k !== o.now; const tr = tableRow(columns, [ ...conds.map((c) => cellText(row[c])), ...valueCols.map((c) => isNum(row[c]) // 수만 고름(글 칸 = 단위 등은 보기만 · M02 길은 수를 글로 줌) ? createButton({ label: cellText(row[c]), variant: k === o.now && c === o.col ? "filled" : "ghost", size: 24, disabled: off, onClick: () => { close(); o.done(row, c); }, }) : cellText(row[c]), ), ]); tr.dataset.row = String(k); tbody.append(tr); }); const note = locked ? [ createText( `${lt("Tbl_Bound")} — ${[...new Set(Object.values(o.bound).flat())].join(" · ")}`, ), ] : []; body.append( el("div", { className: "lstk-tpick", attrs: { "data-table-pick": t.키 ?? "" }, children: [...note, createText(lt("Tbl_Hint")), root], }), ); }, }); }