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:
@@ -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 } : {}) });
|
||||
|
||||
Reference in New Issue
Block a user