feat(b08): 자재총괄 할증률 「이내」 칸 — 표값 상한 안에서만 고름 · 비우면 표값(초안 연결은 Page 한 줄 대기)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
This commit is contained in:
@@ -28,6 +28,8 @@ export interface MaterialRow {
|
|||||||
unit: string;
|
unit: string;
|
||||||
net_amount: number;
|
net_amount: number;
|
||||||
surcharge_pct: number | null;
|
surcharge_pct: number | null;
|
||||||
|
/** 할증률표 값 = 고를 수 있는 천장(품셈 1-3-1 「표의 값 이내」). `null` 이면 칸이 안 섬. */
|
||||||
|
surcharge_cap?: number | null;
|
||||||
total_amount: number;
|
total_amount: number;
|
||||||
supply: string;
|
supply: string;
|
||||||
supply_label: string;
|
supply_label: string;
|
||||||
@@ -241,9 +243,49 @@ export interface SupplyChoice {
|
|||||||
export interface MaterialGridOptions {
|
export interface MaterialGridOptions {
|
||||||
/** 저장 전 변경분 — 고른 값은 여기 쌓이고 [저장]에서만 정본으로 간다. */
|
/** 저장 전 변경분 — 고른 값은 여기 쌓이고 [저장]에서만 정본으로 간다. */
|
||||||
choices: Record<string, SupplyChoice>;
|
choices: Record<string, SupplyChoice>;
|
||||||
|
/** 할증률 고른 값 `{이름 규격: % | null}` — 산출 조건 `material_surcharge`. 안 주면 칸 없이 글자만.
|
||||||
|
* `null` = 표값으로 되돌림. 0 ~ 표값만 받음(서버도 한 번 더 거름). */
|
||||||
|
surcharge?: Record<string, number | null>;
|
||||||
onChange: () => void;
|
onChange: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 할증률 칸 — 표값(상한) 안에서만. 범위를 넘으면 칸이 빨갛게 되고 값을 안 받음. */
|
||||||
|
function surchargeCell(
|
||||||
|
row: MaterialRow,
|
||||||
|
key: string,
|
||||||
|
picks: Record<string, number | null>,
|
||||||
|
onChange: () => void,
|
||||||
|
): HTMLTableCellElement {
|
||||||
|
const cap = row.surcharge_cap as number;
|
||||||
|
const td = document.createElement("td");
|
||||||
|
const input = document.createElement("input");
|
||||||
|
input.type = "number";
|
||||||
|
input.min = "0";
|
||||||
|
input.max = String(cap);
|
||||||
|
input.step = "0.1";
|
||||||
|
input.className = "b08-grid__select";
|
||||||
|
input.style.width = "4.5em";
|
||||||
|
const picked = picks[key];
|
||||||
|
input.value = String(picked ?? row.surcharge_pct ?? cap);
|
||||||
|
input.title = `표값 ${cap}% 이내(품셈 1-3-1) · 비우면 표값`;
|
||||||
|
input.addEventListener("change", () => {
|
||||||
|
const text = input.value.trim();
|
||||||
|
const value = Number(text);
|
||||||
|
if (text !== "" && !(Number.isFinite(value) && value >= 0 && value <= cap)) {
|
||||||
|
input.setCustomValidity(`0 ~ ${cap}% 만 받음`);
|
||||||
|
input.reportValidity();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
input.setCustomValidity("");
|
||||||
|
picks[key] = text === "" ? null : value;
|
||||||
|
if (text === "") input.value = String(cap);
|
||||||
|
td.classList.add("is-changed");
|
||||||
|
onChange();
|
||||||
|
});
|
||||||
|
td.append(input);
|
||||||
|
return td;
|
||||||
|
}
|
||||||
|
|
||||||
/** 표 안의 고르는 칸. 바꾼 줄은 **표시가 남는다** — 무엇을 만졌는지 보여야 한다. */
|
/** 표 안의 고르는 칸. 바꾼 줄은 **표시가 남는다** — 무엇을 만졌는지 보여야 한다. */
|
||||||
function choiceCell(
|
function choiceCell(
|
||||||
value: string,
|
value: string,
|
||||||
@@ -337,7 +379,12 @@ export function renderMaterialGrid(
|
|||||||
tr.append(textCell(row.unit, "b08-grid__unit"));
|
tr.append(textCell(row.unit, "b08-grid__unit"));
|
||||||
tr.append(textCell(num(row.net_amount, 2)));
|
tr.append(textCell(num(row.net_amount, 2)));
|
||||||
// 미확보는 빈칸이 아니라 「-」 — 빈칸이면 0 % 로 오해된다.
|
// 미확보는 빈칸이 아니라 「-」 — 빈칸이면 0 % 로 오해된다.
|
||||||
tr.append(textCell(row.surcharge_pct === null ? "-" : num(row.surcharge_pct, 0)));
|
// 표값이 있는 줄은 「이내」로 고를 칸(초안 `surcharge` 가 이어졌을 때만).
|
||||||
|
tr.append(
|
||||||
|
options?.surcharge && typeof row.surcharge_cap === "number"
|
||||||
|
? surchargeCell(row, key, options.surcharge, options.onChange)
|
||||||
|
: textCell(row.surcharge_pct === null ? "-" : num(row.surcharge_pct, 0)),
|
||||||
|
);
|
||||||
tr.append(textCell(num(row.total_amount, 2)));
|
tr.append(textCell(num(row.total_amount, 2)));
|
||||||
if (options) {
|
if (options) {
|
||||||
// 관급/사급은 **자재마다 갈리는 발주 결정**이라 줄에서 고른다(2026-09-07 확정).
|
// 관급/사급은 **자재마다 갈리는 발주 결정**이라 줄에서 고른다(2026-09-07 확정).
|
||||||
|
|||||||
Reference in New Issue
Block a user