feat(M02): 켜쌓기 적용율 — 골쌓기 기준 로직 세부항목 수량 × 율 · 문서 · 사본 · 서고 같은 함수 · 옵션 칸 · 줄 아래 글(85-2)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W4uKaV4ZBhsJN4GHG7yRj4
This commit is contained in:
2026-10-08 12:05:25 +09:00
co-authored by Claude Opus 5.5
parent afedef7efa
commit 875ceec7f7
12 changed files with 277 additions and 15 deletions
@@ -39,6 +39,17 @@ function footer(
export interface LaborInputResult {
입력값: LaborValues;
메모: string | null;
/** 켜쌓기 적용율 %(85-2 · 대상 로직만 · 빈 칸 · 100 = null) */
켜쌓기율: number | null;
}
/** 켜쌓기율 칸 글 → 값 — 빈 글 · 100 = null · 0 초과 200 이하 · 소수 한 자리 밖 = NaN */
export function layerRate(raw: string): number | null {
if (raw.trim() === "") return null;
const v = Number(raw);
const ok =
Number.isFinite(v) && v > 0 && v <= 200 && Math.abs(v * 10 - Math.round(v * 10)) < 1e-9;
return !ok ? NaN : v === 100 ? null : v;
}
export interface LaborInputOptions {
@@ -48,6 +59,8 @@ export interface LaborInputOptions {
logic: ItemLogic | null;
values: LaborValues;
memo: string | null;
/** 켜쌓기율(85-2) — 로직이 대상일 때만 칸 */
rate?: number | null;
readOnly: boolean;
done: (next: LaborInputResult) => void;
/** 머리 한 줄 알림(51-14 · 서고 원본 고침) */
@@ -100,9 +113,27 @@ export function openLaborInput(opt: LaborInputOptions): void {
}) as HTMLInputElement;
memo.value = opt.memo ?? "";
memo.readOnly = opt.readOnly;
const rate = opt.logic?.켜쌓기
? (el("input", {
className: "ui-input m02-inputval__control",
attrs: {
type: "number",
min: "0.1",
max: "200",
step: "0.1",
placeholder: "100",
"data-labor-layer": "",
},
}) as HTMLInputElement)
: null;
if (rate) {
rate.value = opt.rate == null ? "" : String(opt.rate);
rate.readOnly = opt.readOnly;
}
const ok = (): void => {
if (bad.size) return showToast(tc("In_Bad"), "error");
opt.done({ 입력값: { ...draft }, 메모: memo.value.trim() || null });
const layer = rate ? layerRate(rate.value) : null;
if (bad.size || Number.isNaN(layer)) return showToast(tc("In_Bad"), "error");
opt.done({ 입력값: { ...draft }, 메모: memo.value.trim() || null, 켜쌓기율: layer });
close();
};
body.append(
@@ -129,6 +160,21 @@ export function openLaborInput(opt: LaborInputOptions): void {
...(rows.length
? rows
: [el("p", { className: "m02-labin__muted", text: tc("In_None") })]),
...(rate
? [
el("div", {
className: "m02-inputval__row",
children: [
el("span", {
className: "m02-inputval__name",
text: tc("In_Layer"),
attrs: { title: tc("In_LayerHint") },
}),
rate,
],
}),
]
: []),
el("div", {
className: "m02-inputval__row",
children: [