/* ============================================================================= * line_stack_pick.ts * 줄 쌓기 고르기 창(PLAN 804-3 · 804-4 · 요구 678-1 · 678-3 · 680-1 · 681) * 찾아 넣기 = M02 [항목 추가] 창 그대로(`openFindPicker` · 탭 M01 전체 · 찾기 칸 · 표) — 줄 갈래마다 그 종류만 * 인력(노임 LB) · 재료(자재 MT) · 기계(EQ → 시간당 경비 로직 + 기계='원문번호') · 다른 단가산출(M01 단가산출 로직) * M01 단가산출 기초 줄 쌓기 = 「M01 전체」 탭만 — M01 은 원천 기준값이라 M02 단가산출 · 일위대가를 부르지 않음(요구 680-1) * M02 단가산출 줄 쌓기(`take` 있음) · 다른 단가산출 = 탭 [M01 전체 | M02 단가산출 | 일위대가](위 층 · 자기 SK 뺌) — * 고름 = 복사해 펼침(`take(src)` · src = M01 키 | `참조|층|주인|키`) · 참조 줄 없음(요구 681) * 표 고르기 = 품셈 표(조건 칸 + 값 칸) · 값 칸 누름 = 그 줄 · 칸 · 지금 닿는 칸 강조 · * 옵션에 매인 조건 = 그 줄만 고를 수 있음(다른 줄은 막힘 + 「위 옵션에서 고름」 안내) * ========================================================================== */ 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 { showToast } from "@ui/ui_template_elements"; import type { Layer } from "../M02_MasterTemplete/M02_MasterTemplete_Api_Fetch"; import { openFindPicker, type FindKind } from "../M02_MasterTemplete/M02_MasterTemplete_Find_Pick"; import { lt } from "./line_stack_text"; const KINDS: Partial> = { 인력: "labor", 재료: "material", 기계: "machine", 단가산출: "logic", }; /** M02 단가산출 복사 길(804-4) — 그 SK 층 · 키 · 복사해 넣기 */ export interface StackTake { layer: Layer; owner: string | null; me: string; take: (src: string) => void; } /** 찾아 넣기 — 고르면 `done(고른 것)` · 닫으면 아무것도 안 함 · `m02` 있고 다른 단가산출 = 복사해 펼침 · * `query` = 찾기 칸에 넣고 연 결과(이름 단추 · 요구 687-9) */ export function openStackPick( kind: MoneyKind, done: (p: Picked) => void, m02?: StackTake, query = "", ): void { const want = KINDS[kind]; if (!want) return; const spec = (e: { 규격: string }) => (e.규격 ? { 규격: e.규격 } : {}); const copy = kind === "단가산출" && m02 ? m02 : null; openFindPicker({ layer: copy?.layer ?? "system", owner: copy?.owner ?? null, title: `${lt("Find_Title")} — ${lt(copy ? "K_복사" : (`K_${kind}` as never))}`, kinds: copy ? ["logic", "sk", "pre"] : [want], // M01 = M01 전체만(680-1) query: query.trim() || undefined, ref: copy ? (r) => r.키 === copy.me && r.층 === copy.layer && (!copy.owner || r.주인 === copy.owner) ? showToast(lt("Self_Take"), "warning") : copy.take(`참조|${r.층}|${r.주인 ?? ""}|${r.키}`) : undefined, logic: (x) => copy ? copy.take(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], }), ); }, }); }