Files
Aislo/M01_MasterData/M01_MasterData_UI_Procure.ts
T
eomsangdonandClaude Sonnet 5 f80046e4ae feat(M01): B01 마스터 데이터 단추 하나로 · 시중물가 「조달 찾기」 모달 · 찾기 API
- B01 옛 「마스터 데이터」(Z01) 단추 제거 · 「마스터 요소」 이름을 「마스터 데이터」 로
- 재료 › 시중물가 줄마다 「조달 찾기」 — 나라장터자재 + 시중물가 조달 줄을 이름·규격으로 찾아 「나라장터:<열쇠>」 연결 · 노랑 표시 · 연결 끊기
- GET /api/m01/procurement 추가 · 값 묶음(조달{…}) 확정 전이라 연결은 조달›연결 칸에 임시로 담음

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016WRFJmmhPi4exAzHgPZHMT
2026-09-19 23:29:17 +09:00

87 lines
3.2 KiB
TypeScript

/* =============================================================================
* M01_MasterData_UI_Procure.ts
* 재료 › 시중물가 「조달 찾기」 모달 — 조달 자료를 이름·규격으로 찾아 고르면 ref 를 돌려줌
* ========================================================================== */
import { el, showToast } from "@ui/ui_template_elements";
import { t as L } from "@ui/ui_template_locale";
import { fetchProcurement, type ProcureItem } from "./M01_MasterData_Api_Fetch";
import { show } from "./M01_MasterData_UI_Cells";
const button = (text: string): HTMLButtonElement =>
el("button", { className: "m01-master__row-btn", text, attrs: { type: "button" } });
/** 고르면 `onPick(ref)` · 연결 끊기 = `onPick(null)`. */
export function openProcureModal(current: string, onPick: (ref: string | null) => void): void {
const close = (): void => back.remove();
const input = el("input", {
className: "m01-master__search",
attrs: { type: "search", placeholder: L("M01_ProcureSearch") },
});
const list = el("div", { className: "m01-procure__list" });
const cut = button(L("M01_ProcureCut"));
cut.disabled = !current;
cut.addEventListener("click", () => {
onPick(null);
close();
});
const shut = button(L("M01_ProcureClose"));
shut.addEventListener("click", close);
const box = el("div", {
className: "m01-procure__box",
children: [
el("h3", { text: L("M01_ProcureTitle") }),
el("p", { className: "m01-master__muted", text: current }),
input,
list,
el("div", { className: "m01-procure__foot", children: [cut, shut] }),
],
});
const back = el("div", { className: "m01-procure", children: [box] });
back.addEventListener("click", (e) => {
if (e.target === back) close();
});
document.body.append(back);
const paint = (items: ProcureItem[], total: number): void => {
list.replaceChildren(
...(items.length
? items.map((it) => {
const b = el("button", {
className: "m01-procure__item",
attrs: { type: "button" },
children: [
el("strong", { text: it.이름 }),
el("span", { text: `${it.규격} · ${it.단위} · ${show(it.)}` }),
el("span", { className: "m01-master__muted", text: it.ref }),
],
});
b.addEventListener("click", () => {
onPick(it.ref);
close();
});
return b;
})
: [el("p", { className: "m01-master__empty", text: L("M01_NoRows") })]),
...(total > items.length
? [el("p", { className: "m01-master__muted", text: `${items.length} / ${total}` })]
: []),
);
};
let timer: number | undefined;
const run = async (): Promise<void> => {
try {
const r = await fetchProcurement(input.value.trim());
paint(r.items, r.total);
} catch (error) {
showToast(error instanceof Error ? error.message : L("M01_LoadFailed"), "error");
}
};
input.addEventListener("input", () => {
window.clearTimeout(timer);
timer = window.setTimeout(() => void run(), 300);
});
void run();
input.focus();
}