/* ============================================================================= * M01_MasterData_UI_Logic_Pick.ts * 요소 찾기 창 — 그룹 전체에서 이름·열쇠로 찾아 호표 줄에 넣음(`GET /elements`) * 표 고르기(소요량·계수)는 값칸 단추를 눌러 `찾기(…).칸` 으로 수량에 넣음 * ========================================================================== */ import { createButton, el, showToast } from "@ui/ui_template_elements"; import { searchElements, type ElementBrief } from "./M01_MasterData_UI_Logic_Api"; import { formatNumber, type PickDone, type PickMode } from "./M01_MasterData_UI_Logic_Edit"; import { tx } from "./M01_MasterData_UI_Logic_Text"; const GROUPS: Record = { element: ["인력", "재료", "기계", "로직"], table: ["소요량", "계수"], }; export function openPicker(mode: PickMode, group: string, done: PickDone): void { const groups = GROUPS[mode]; const select = el("select", { className: "m01-logic__input" }); for (const g of groups) select.append(el("option", { text: g, attrs: { value: g } })); select.value = groups.includes(group) ? group : groups[0]; const search = el("input", { className: "m01-logic__input", attrs: { type: "search", placeholder: tx("Pick_Search") }, }); const count = el("span", { className: "m01-logic__muted" }); const list = el("div", { className: "m01-logic__pick-list" }); const close = (): void => backdrop.remove(); const dialog = el("div", { className: "m01-logic__pick", attrs: { role: "dialog", "aria-label": tx("Pick_Title") }, children: [ el("div", { className: "m01-logic__section-head", children: [ el("h3", { text: tx("Pick_Title") }), createButton({ label: tx("Pick_Close"), variant: "ghost", onClick: close }), ], }), el("div", { className: "m01-logic__pick-bar", children: [select, search, count] }), list, ], }); const backdrop = el("div", { className: "m01-logic__backdrop", children: [dialog] }); backdrop.addEventListener("click", (ev) => ev.target === backdrop && close()); backdrop.addEventListener("keydown", (ev) => ev.key === "Escape" && close()); const choose = (item: ElementBrief, column?: string): void => { close(); done(item, column); }; let seq = 0; const load = async (): Promise => { const mine = ++seq; try { const found = await searchElements(select.value, search.value.trim()); if (mine !== seq) return; // 최신 응답만 count.textContent = tx("Pick_Total", { n: found.total }); list.replaceChildren(...found.items.map((item) => itemRow(item, mode, choose))); } catch (error) { showToast(error instanceof Error ? error.message : tx("Load_Failed"), "error"); } }; let timer = 0; search.addEventListener("input", () => { window.clearTimeout(timer); timer = window.setTimeout(load, 250); }); select.addEventListener("change", load); document.body.append(backdrop); search.focus(); void load(); } function itemRow( item: ElementBrief, mode: PickMode, choose: (item: ElementBrief, column?: string) => void, ): HTMLElement { const text = el("div", { className: "m01-logic__stack", children: [ el("strong", { text: `${item.이름 ?? ""} ${item.규격 ?? ""}`.trim() }), el("span", { className: "m01-logic__muted", text: item.ref }), ], }); if (mode === "table") { const columns = Object.keys(item.값칸 ?? {}); const chips = columns.map((column) => createButton({ label: column, variant: "pill", onClick: () => choose(item, column) }), ); return el("div", { className: "m01-logic__pick-row", children: [text, el("div", { className: "m01-logic__chips", children: chips })], }); } const unit = typeof item.단위 === "string" ? item.단위 : ""; const value = typeof item.값 === "object" && item.값 !== null ? "{…}" : formatNumber(item.값); const row = el("button", { className: "m01-logic__pick-row m01-logic__pick-row--button", attrs: { type: "button" }, children: [ text, el("span", { className: "m01-logic__money", text: `${value} ${unit}`.trim() }), ], }); row.addEventListener("click", () => choose(item)); return row; }