feat(M01): 테스트 컨테이너 고르기 부품 공용화 — 구분 → 상세구분 → 후보 거름 · B·C 에도 재료 바꿔 보기

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016WRFJmmhPi4exAzHgPZHMT
This commit is contained in:
2026-09-20 22:14:22 +09:00
co-authored by Claude Sonnet 5
parent 35588d9aa5
commit 03e6b6511e
8 changed files with 216 additions and 84 deletions
+5 -80
View File
@@ -7,23 +7,19 @@
import { createButton, createSelectField, el, showToast } from "@ui/ui_template_elements";
import {
fetchLogic,
fetchMaterials,
runCalc,
searchElements,
type CalcAnswer,
type ElementBrief,
type HoLine,
type LogicInput,
type LogicOne,
} from "./M01_MasterData_UI_Logic_Api";
import { formatNumber } from "./M01_MasterData_UI_Logic_Edit";
import { hasPickable, pickPanel, swappedRow } from "./M01_MasterData_UI_Test_Pick";
import { tt } from "./M01_MasterData_UI_Test_Text";
type Step =
{ kind: "job" } | { kind: "ask"; spec: LogicInput } | { kind: "pick" } | { kind: "result" };
const PICKABLE = ["재료", "기계"];
export function render(host: HTMLElement, logicKey: string): void {
host.replaceChildren(el("p", { className: "m01-test__muted", text: tt("Loading") }));
fetchLogic(logicKey)
@@ -35,15 +31,13 @@ function wizard(host: HTMLElement, one: LogicOne): void {
const { logic } = one;
const values: Record<string, string> = {};
const swaps = new Map<number, ElementBrief>();
const lines = (logic. ?? [])
.map((line, i) => ({ line, i }))
.filter((x) => PICKABLE.includes(x.line.));
const steps: Step[] = [
{ kind: "job" },
...(logic. ?? []).map((spec): Step => ({ kind: "ask", spec })),
...(lines.length ? [{ kind: "pick" } as Step] : []),
...(hasPickable(logic) ? [{ kind: "pick" } as Step] : []),
{ kind: "result" },
];
const picker = pickPanel(one, swaps, () => undefined);
let at = 0;
const go = (next: number): void => {
@@ -127,67 +121,7 @@ function wizard(host: HTMLElement, one: LogicOne): void {
};
const drawPick = (): void => {
const rows = lines.map(({ line, i }) => pickRow(line, i));
frame(
tt("Mat_Title"),
tt("Mat_Note"),
rows.length ? rows : [el("p", { text: tt("Mat_None") })],
true,
);
};
const pickRow = (line: HoLine, i: number): HTMLElement => {
const price = one.prices[line.]?.;
const found = new Map<string, ElementBrief>();
const select = createSelectField({
options: [{ value: "", text: tt("Mat_Default") }],
value: "",
onChange: (ref) => {
const item = found.get(ref);
if (item) swaps.set(i, item);
else swaps.delete(i);
},
});
// 재료 고르기 조건({구분, 상세구분, 규격}) 이면 새 API 로 조건 안 후보 · 아니면 이름 찾기
const cond = line. as unknown;
const found_ =
cond && typeof cond === "object"
? fetchMaterials({
sub: String((cond as Record<string, unknown>)["구분"] ?? ""),
detail: String((cond as Record<string, unknown>)["상세구분"] ?? ""),
spec: String((cond as Record<string, unknown>)["규격"] ?? ""),
region: "울진",
})
: searchElements(line., line. ?? "");
void found_
.then((r) => {
r.items.forEach((it) => found.set(it.ref, it));
select.setOptions(
[
{ value: "", text: tt("Mat_Default") },
...r.items.map((it) => ({
value: it.ref,
text: [`${it. ?? ""} ${it. ?? ""}`.trim(), formatNumber(it.)]
.filter(Boolean)
.join(" · "),
})),
],
swaps.get(i)?.ref ?? "",
);
})
.catch(() => undefined);
const spec = line. ? ` ${line.}` : "";
const unit = line. ?? "";
const cost =
price !== undefined && price !== null ? ` · ${tt("Mat_Price")} ${formatNumber(price)}` : "";
return el("div", {
className: "m01-test__pick",
children: [
el("strong", { text: `${line.} · ${line. ?? line.}${spec}` }),
el("span", { className: "m01-test__muted", text: `${unit}${cost}` }),
select.root,
],
});
frame(tt("Mat_Title"), tt("Mat_Note"), [picker], true);
};
const drawResult = async (): Promise<void> => {
@@ -199,16 +133,7 @@ function wizard(host: HTMLElement, one: LogicOne): void {
inputs[spec.] =
option !== undefined ? option : Number.isNaN(Number(raw)) ? raw : Number(raw);
}
// 바꿔 본 재료·기계가 있으면 복사본으로만 셈 — 정본 로직은 그대로
const row = swaps.size
? {
...logic,
: (logic. ?? []).map((l, i) => {
const s = swaps.get(i);
return s ? { ...l, 요소: s.ref, 이름: s.이름 ?? l., 규격: s.규격 ?? l. } : l;
}),
}
: undefined;
const row = swappedRow(logic, swaps); // 바꿔 본 것이 있으면 복사본으로만 셈
let answer: CalcAnswer;
try {
answer = await runCalc({ key: logic.키, inputs, ...(row ? { row, file: one.file } : {}) });