feat(m02-df): 흐름도 검증 칸(끊긴 곳 · 재료 자리 · 조건 자리) · 출력 끝수 기본 · 합계 끝수
- 새 Verify: 끊긴 곳 목록(on.select) · 변수 예시값 · 재료 선택 자리(찾기 · 쪽 · 고르기) · 재료 조건 자리(잡힌 품목 · 0 · 여럿) · 이어지지 않은 다른 로직 값 - 새 Round · Material: 금액 단위 표준에서 끝수 기본(금액란 0.1원 · 계금 1원 미만 버림) · 재료 찾기 · 단가 - OutputPanel 끝수 고르기 · Summary 합계 끝수 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EauA2ATmqNRbeV48s9CcBr
This commit is contained in:
@@ -6,10 +6,11 @@
|
||||
* ========================================================================== */
|
||||
|
||||
import { currentLanguageIndex } from "@ui/ui_template_locale";
|
||||
import { createSelectField, el } from "@ui/ui_template_elements";
|
||||
import { createButton, createSelectField, el } from "@ui/ui_template_elements";
|
||||
import { formatMoney } from "../../M01_MasterData/M01_MasterData_UI_Logic_Money";
|
||||
import { evalLogic, type CfEvalResult, type CfValue } from "./M02_DF_Eval";
|
||||
import { portsOut, type CfBox, type CfCost, type CfLogic } from "./M02_DF_Model";
|
||||
import { portsOut, type CfBox, type CfCost, type CfLogic, type CfRound } from "./M02_DF_Model";
|
||||
import { defaultItemRound, roundText } from "./M02_DF_Round";
|
||||
import "./M02_DF_OutputPanel.css";
|
||||
|
||||
const TEXT = {
|
||||
@@ -32,6 +33,14 @@ const TEXT = {
|
||||
Table: ["표", "Table"],
|
||||
Calc: ["계산 중이 아니에요", "Not calculated"],
|
||||
Cant: ["지금은 바꿀 수 없어요", "Cannot change this now"],
|
||||
Round: ["끝수", "Rounding"],
|
||||
RoundPlaces: ["자리", "Places"],
|
||||
RoundMethod: ["방법", "Method"],
|
||||
RoundDefault: ["끝수 기본", "Default rounding"],
|
||||
RoundStd: ["일위대가표 금액란", "unit-price sheet amount column"],
|
||||
RoundNone: ["끝수 없음(값 그대로)", "No rounding (value as is)"],
|
||||
RoundReset: ["기본으로", "Back to default"],
|
||||
RoundUser: ["고른 끝수", "Chosen rounding"],
|
||||
PlainHint: [
|
||||
"원가 합계에 안 넣고 값으로만 보여요",
|
||||
"Shown as a value, not added to the cost total",
|
||||
@@ -152,7 +161,7 @@ export function renderOutputPanel(
|
||||
emit(() =>
|
||||
withBox(lg, box.id, (b) => ({
|
||||
...b,
|
||||
output: { unit: b.output?.unit ?? b.unit, cost: v as CfCost },
|
||||
output: { ...b.output, unit: b.output?.unit ?? b.unit, cost: v as CfCost },
|
||||
})),
|
||||
),
|
||||
});
|
||||
@@ -167,7 +176,7 @@ export function renderOutputPanel(
|
||||
withBox(lg, box.id, (b) => ({
|
||||
...b,
|
||||
unit: next,
|
||||
output: { cost: b.output?.cost ?? "노무비", unit: next },
|
||||
output: { ...b.output, cost: b.output?.cost ?? "노무비", unit: next },
|
||||
})),
|
||||
);
|
||||
});
|
||||
@@ -177,6 +186,76 @@ export function renderOutputPanel(
|
||||
children: [el("span", { text: label }), control],
|
||||
});
|
||||
|
||||
/* 끝수 — 기본 = 일위대가표 금액란 0.1원 미만 버림(표준 표를 읽음) · 값(비용 아님)은 정하지 않으면 그대로 */
|
||||
const round = box.output?.round;
|
||||
const stepName = (n: number): string => (n === 0 ? "1" : String(Number((10 ** -n).toFixed(n))));
|
||||
let fallback: CfRound = { places: 1, method: "버림" };
|
||||
const roundNote = el("span", { className: "m02-dfout__muted" });
|
||||
const noteOf = (r: CfRound | undefined): string =>
|
||||
r
|
||||
? `${to("RoundUser")}: ${roundText(r)}`
|
||||
: cost === "값"
|
||||
? to("RoundNone")
|
||||
: `${to("RoundDefault")}: ${to("RoundStd")} ${roundText(fallback)}`;
|
||||
roundNote.textContent = noteOf(round);
|
||||
if (cost !== "값")
|
||||
void defaultItemRound().then((r) => {
|
||||
fallback = r;
|
||||
roundNote.textContent = noteOf(round);
|
||||
});
|
||||
const setRound = (next: CfRound | undefined): void =>
|
||||
emit(() =>
|
||||
withBox(lg, box.id, (b) => {
|
||||
const output = { ...(b.output ?? { cost, unit: b.unit }) };
|
||||
if (next) output.round = next;
|
||||
else delete output.round;
|
||||
return { ...b, output };
|
||||
}),
|
||||
);
|
||||
const placesField = createSelectField({
|
||||
options: [
|
||||
{ value: "", text: cost === "값" ? to("RoundNone") : to("RoundDefault") },
|
||||
...[0, 1, 2, 3, 4].map((n) => ({ value: String(n), text: `${stepName(n)}원 단위` })),
|
||||
],
|
||||
value: round ? String(round.places) : "",
|
||||
compact: true,
|
||||
ariaLabel: to("RoundPlaces"),
|
||||
onChange: (v) =>
|
||||
setRound(v === "" ? undefined : { places: Number(v), method: round?.method ?? "버림" }),
|
||||
});
|
||||
const methodField = createSelectField({
|
||||
options: (["버림", "올림", "반올림"] as const).map((m) => ({ value: m, text: `미만 ${m}` })),
|
||||
value: round?.method ?? fallback.method,
|
||||
compact: true,
|
||||
disabled: !round,
|
||||
ariaLabel: to("RoundMethod"),
|
||||
onChange: (v) => round && setRound({ places: round.places, method: v as CfRound["method"] }),
|
||||
});
|
||||
const roundBlock = el("div", {
|
||||
className: "m02-dfout__round",
|
||||
children: [
|
||||
el("strong", { text: to("Round") }),
|
||||
el("div", {
|
||||
className: "m02-dfout__fields",
|
||||
children: [
|
||||
field(to("RoundPlaces"), placesField.root),
|
||||
field(to("RoundMethod"), methodField.root),
|
||||
...(round
|
||||
? [
|
||||
createButton({
|
||||
label: to("RoundReset"),
|
||||
size: "sm",
|
||||
variant: "ghost",
|
||||
onClick: () => setRound(undefined),
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
],
|
||||
}),
|
||||
roundNote,
|
||||
],
|
||||
});
|
||||
|
||||
host.replaceChildren(
|
||||
el("strong", { className: "m02-dfout__title", text: `${to("Title")} · ${box.name}` }),
|
||||
el("div", {
|
||||
@@ -189,6 +268,7 @@ export function renderOutputPanel(
|
||||
}),
|
||||
],
|
||||
}),
|
||||
roundBlock,
|
||||
...(cost === "값" ? [el("p", { className: "m02-dfout__muted", text: to("PlainHint") })] : []),
|
||||
msg,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user