/* ============================================================================= * M02_MyItems_View.ts * M02 「내 품목」 모아 보기(PLAN 821-3 · 요구서 796 3 장 · 읽기만) — 좌측 「내 품목」 칸을 펼치면 가운데에 뜸(개인 층). * 줄 = 그 층 단가산출 줄에 값을 바로 적은 재료(우리 자재에 안 이어진 것 · 서버 `M02_MyMachine_Look.items`) * 칸 = 이름 · 규격 · 단위 · 값 · 쓰는 단가산출 수 · 같은 이름 수(같은 이름 묶음 = 이름 차례로 붙어 보임) * 줄 누름 = 아래 쓰는 단가산출 목록 → 누르면 그 단가산출로(고치기는 거기서 · 여기선 저장 없음) * ========================================================================== */ import { createDataTable } from "@ui/ui_template_data_table"; import { createInputField, el } from "@ui/ui_template_elements"; import { createFindList } from "@ui/ui_template_find_list"; import { createText } from "@ui/ui_template_text"; import { listMyItems, type MyItem, type Use } from "./M02_MyMachine_Api"; import { mt } from "./M02_MyMachine_Text"; export interface MyItemsViewOptions { owner: string | null; /** 그 단가산출 열기(떠남 확인은 부르는 쪽) */ openSk: (use: Use) => void; } export function buildMyItemsView(opt: MyItemsViewOptions): HTMLElement { let rows: MyItem[] = []; let shown: MyItem[] = []; const search = createInputField({ type: "search", placeholder: mt("Find") }); const hint = createText(""); const fail = el("div"); const uses = createFindList({ placeholder: mt("Open_Sk") }); uses.root.hidden = true; const table = createDataTable({ caption: mt("Items_Title"), columns: [ { key: "이름", label: mt("Name"), width: 200 }, { key: "규격", label: mt("Spec"), width: 140 }, { key: "단위", label: mt("Unit"), width: 60 }, { key: "값", label: mt("Value"), kind: "number", decimals: 2, trim: true, width: 100 }, { key: "쓰는곳", label: mt("Uses_Count"), kind: "number", decimals: 0, width: 70 }, { key: "같은이름", label: mt("Same_Name"), kind: "number", decimals: 0, width: 70 }, ], rows: [], empty: mt("Items_None"), mergeSame: ["이름"], onRowClick: (i) => pick(shown[i]), }); const pick = (item: MyItem | undefined): void => { if (!item) return; uses.root.hidden = false; uses.hint.textContent = `${item.이름} ${item.규격}`.trim(); uses.setRows( item.쓰는곳.map((u) => ({ key: u.키, name: u.이름 || u.키, sub: u.키, onPick: () => opt.openSk(u), })), ); }; const draw = (): void => { const words = search.input.value.trim().toLowerCase().split(/\s+/).filter(Boolean); const count = new Map(); for (const r of rows) count.set(r.이름, (count.get(r.이름) ?? 0) + 1); shown = rows.filter((r) => words.every((w) => `${r.이름} ${r.규격}`.toLowerCase().includes(w))); hint.textContent = rows.length ? `${shown.length} / ${rows.length}` : ""; table.setRows( shown.map((r) => ({ 이름: r.이름, 규격: r.규격, 단위: r.단위, 값: typeof r.값 === "number" ? r.값 : Number(r.값) || null, 쓰는곳: r.쓰는곳.length, 같은이름: count.get(r.이름) ?? 1, })), ); }; search.input.addEventListener("input", draw); void listMyItems(opt.owner) .then((got) => (rows = got)) .catch((error) => fail.replaceChildren( createText(error instanceof Error ? error.message : mt("Personal_Only"), "error"), ), ) .finally(draw); return el("div", { className: "m02-mymach-view", attrs: { "data-my-items": "" }, children: [ el("div", { className: "ui-toolbar", children: [search.root, hint] }), createText(mt("Items_Note"), "muted"), fail, table.root, uses.root, ], }); }