Files
Aislo/M01_MasterData/M01_MasterData_UI_Logic_Pick.ts
T
eomsangdonandClaude Opus 5 6c9ac97b29 feat(master_data): 키 개편 — 테이블ID+6자리 키 · 인력·기계 한 테이블 · 장 파일 이름
- 모든 요소·표·로직 줄의 열쇠 → 키(LB000123 꼴) · 옛 열쇠·원문 번호는 원문번호 칸 · 대장 _키대장.json (키 36,840 · 다음 번호)
- 변수 적는 법 키로 — 로직 식·연결·준용·통합·후보·조달 연결 일괄 변환 · {이름} 낀 참조는 ID:원문번호
- 인력 8 파일 → 인력.json(줄마다 조사 · 머리 조사 묶음) · 기계 2 파일 → 기계.json(세부분류)
- 소요량·계수·로직 파일 이름 = 그룹_원문_NN장_장 제목 · 머리 부문·차례
- 엔진(값 찾기 · 알림에 키 옆 이름) · check_master(키 모양·겹침·대장·끊긴 키 · 기계 요소 줄도 본문 결손 대조) · M01 서버(새 줄 키는 대장 다음 번호 · 키 못 고침) · 화면 칸 이름만 맞춤
- 로직 일괄 시험 계산 1,351 줄 — 옮기기 전후 줄마다 결과·금액 같음

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JgUhN55Z3BCYhUJTjwTNfj
2026-09-20 01:56:30 +09:00

110 lines
4.2 KiB
TypeScript

/* =============================================================================
* 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<PickMode, string[]> = {
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<void> => {
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;
}