Files
Aislo/M02_MasterTemplete/M02_MasterTemplete_Labor_LogicMats.ts
T
eomsangdonandClaude Opus 5.5 f79078f9c9 feat(m02): 일위대가 자재목록 로직 자재 기본 줄 · [바꾸기] 고름 · 사용자 추가분만 삭제(103-1)
- 문서 담은로직[].고름 {호표 차례: MT키} 정리 · 검사(재료 줄 · M01 자재품목만)
- run_line 을 엔진 choosing(고름)으로 감쌈 · 로직 자재 줄(차례 · 품목 · 단가 · 금액 · 가격 · 걸림) 내보냄
- 로직 자재 금액은 합 · 알약에 안 더함 · 사용자 자재와 같은 품목은 저장 때 400
- 단가승격 · 사전조합 안 로직도 고름 따름(없으면 지금 값)
- 프로젝트 사본 고른자재 씨앗 = 문서 고름 · 단가 묶음에 고른 품목 줄
- 화면: 자재목록 표 앞에 로직 자재 줄(삭제 없음 · [바꾸기] · 바꾼 줄 [기본]) · 입력 바뀌면 걸린 고름 풂 · 로직 자재와 같은 품목 추가 막음
- 시험 test_m02_labor_logic_mats.py(서버 · Node 짝)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PSXsvyDxjNmufteN5bqmt
2026-10-08 16:18:21 +09:00

145 lines
5.7 KiB
TypeScript

/* =============================================================================
* M02_MasterTemplete_Labor_LogicMats.ts
* 자재목록 표의 로직 자재 줄(103-1) — 담은 로직 맨 위 층 재료 줄(서버 calc `줄[].재료`) · 사용자 자재 줄과 같은 칸
* (코드 · 이름 · 규격 · 수량 · 단위 · 가격 다섯 · 단가 / 금액) · 사용자 자재 앞.
* · 삭제 없음 · [바꾸기] = M01 자재품목 표에서 고름(문서 `담은로직[].고름` · 엔진 `choosing`) · 바꾼 줄만 [기본](고름 풂)
* · 금액은 로직 단가 안이라 합에 다시 안 더함(보기만) · 수량은 로직 것(누름 · 알약 없음)
* · 하위 로직 안 재료는 안 보임(엔진이 맨 위 층만 고름)
* ========================================================================== */
import { createButton, el } from "@ui/ui_template_elements";
import { formatMoney } from "../M01_MasterData/M01_MasterData_UI_Logic_Money";
import { openPickTable } from "../M01_MasterData/M01_MasterData_UI_Logic_PickTable";
import { headWord } from "../M01_MasterData/M01_MasterData_UI_LogicLab_Modal";
import type { LaborCalc, LaborRow } from "./M02_MasterTemplete_Labor_Api";
import { lineId } from "./M02_MasterTemplete_Labor_Calc";
import { moneyCell, PRICE_SLOTS } from "./M02_MasterTemplete_Labor_Rows";
import { tc } from "./M02_MasterTemplete_Labor_Text";
import type { LogicMat } from "./M02_Labor_LogicMats_Model";
export interface LogicMatHandlers {
/** [바꾸기]로 고른 품목 키 — `row` = 담은 로직 차례 · `at` = 호표 차례 */
swap: (row: number, at: number, key: string) => void;
/** [기본] — 그 줄 고름 풂 */
reset: (row: number, at: number) => void;
}
const num = (v: number | null): string =>
v === null
? "—"
: Number(v.toPrecision(12)).toLocaleString("ko-KR", { maximumFractionDigits: 6 });
/** 담은 로직 차례대로 그 줄 로직 자재 — calc 답이 없으면 빈 것(답이 오면 다시 그림) */
export function logicMatRows(
rows: LaborRow[],
calc: LaborCalc | null,
wait: boolean,
on?: LogicMatHandlers,
): HTMLElement[] {
return rows.flatMap((row, r) => {
const line = row.참조 ? undefined : calc?.줄.find((l) => lineId(l) === lineId(row));
return (line?.재료 ?? []).map((mat) => matRow(row, r, mat, wait, on));
});
}
function matRow(
row: LaborRow,
r: number,
mat: LogicMat,
wait: boolean,
on?: LogicMatHandlers,
): HTMLElement {
const item = mat.품목;
const name = item?.이름 ?? mat.이름;
const owner = `${row.별칭 ?? row.로직} · ${mat.이름}`;
const priceCell = (slot: (typeof PRICE_SLOTS)[number]): HTMLElement => {
const base = !!item?.값칸 && item.값칸 === slot;
const v = mat.가격?.[slot];
return el("td", {
className: `m02-labrow__num m02-labrow__price${base ? " is-base-price" : ""}`,
text: wait ? "…" : v === null || v === undefined ? "—" : formatMoney(v),
attrs: { "data-label": slot, "data-price-slot": slot },
});
};
const money = moneyCell(mat.단가, mat.금액, wait, tc("Labor_AppliedSum"));
money.title = tc("LogicMat_Inside");
const tools = on
? [
el("td", {
className: "m02-labrow__move",
children: [
el("div", {
className: "ui-btn-group",
children: [
createButton({
label: tc("LogicMat_Swap"),
variant: "ghost",
onClick: (e) => {
e.stopPropagation();
openPickTable({
kind: "재료",
title: `${tc("LogicMat_PickTitle")} · ${mat.이름}`,
seed: headWord(name),
alt: [headWord(mat.이름)],
isCurrent: (x) => String(x["키"]) === item?.키,
onPick: (x) => on.swap(r, mat.차례, String(x["키"])),
});
},
}),
...(mat.고름
? [
createButton({
label: tc("LogicMat_Reset"),
variant: "ghost",
onClick: (e) => {
e.stopPropagation();
on.reset(r, mat.차례);
},
}),
]
: []),
],
}),
],
}),
]
: [];
return el("tr", {
className: `m02-labrow__row m02-labrow__logic-mat${mat.고름 ? " is-picked-mat" : ""}`,
attrs: { "data-labor-logic-mat": `${row.로직}|${mat.차례}` },
children: [
el("td", { className: "m02-labrow__code", text: item?.키 ?? "—" }),
el("td", {
className: "m02-labrow__name",
children: [
el("strong", { text: name, attrs: { title: name } }),
el("small", {
className: "m02-labrow__key",
text: mat.고름 ? `${owner} · ${tc("LogicMat_Picked")}` : owner,
attrs: { title: owner },
}),
...(mat.까닭 ? [el("small", { className: "m02-labrow__empty", text: mat.까닭 })] : []),
],
}),
el("td", {
className: "m02-labrow__spec",
text: item?.규격 ?? "",
attrs: { title: item?.규격 ?? "" },
}),
el("td", {
className: "m02-labrow__qty",
text: wait ? "…" : num(mat.수량),
attrs: { "data-label": tc("Labor_QtyCol") },
}),
el("td", {
className: "m02-labrow__unit",
text: mat.단위,
attrs: { "data-label": tc("Labor_Unit") },
}),
...PRICE_SLOTS.map(priceCell),
money,
...tools,
],
});
}