wip(est-test): 개발 중 저장 3 — 깃 싱크(11-08)

This commit is contained in:
2026-11-08 17:44:13 +09:00
parent d39eece45e
commit db71cdbf7c
28 changed files with 1027 additions and 202 deletions
+94 -95
View File
@@ -84,27 +84,29 @@ const EstExtra = (() => {
);
} else if (view === "change") {
const changes = EstBusiness.changes(project);
const page = EstBlockActions.changePage(state, changes);
html = box(
"설계변경",
button("capture-baseline", "현재 내역을 당초로 확정") +
button("load-contract", "당초·계약 내역 불러오기") +
button("recalculate-original", "당초 단가 재계산") +
button("bid-rates", "낙찰률 적용") +
button("restore-bid", "당초단가(100%) 복원"),
button("restore-bid", "당초단가(100%) 복원") +
button("change-prev", "이전", state.changePage === 0 ? "disabled" : "") +
`<span>${state.changePage + 1} / ${page.pages}쪽 · ${page.total}행</span>` +
button("change-next", "다음", state.changePage + 1 >= page.pages ? "disabled" : ""),
table(
["구분", "코드", "품명", "당초 수량", "변경 수량", "당초 금액", "변경 금액", "증감"],
changes
.filter((row) => row.Code || row.Name)
.map((row) => [
esc({ new: "신규", deleted: "삭제", changed: "변경", unchanged: "동일" }[row.status]),
esc(row.Code),
esc(row.Name),
number(row.originalGN),
number(row.GN),
number(row.originalTC),
number(row.TC),
number(row.difference),
]),
page.rows.map(({ row }) => [
esc({ new: "신규", deleted: "삭제", changed: "변경", unchanged: "동일" }[row.status]),
esc(row.Code),
esc(row.Name),
number(row.originalGN),
number(row.GN),
number(row.originalTC),
number(row.TC),
number(row.difference),
]),
) +
table(
["원가 구분", "비목", "당초 금액", "변경 금액", "증감"],
@@ -150,6 +152,11 @@ const EstExtra = (() => {
output = { rows: [], errors: [e.message] };
}
state.business = output;
const page = EstBlockActions.progressPage(state, output.rows);
tools +=
button("progress-prev", "이전", state.progressPage === 0 ? "disabled" : "") +
`<span>${state.progressPage + 1} / ${page.pages}쪽 · ${page.total}행</span>` +
button("progress-next", "다음", state.progressPage + 1 >= page.pages ? "disabled" : "");
body =
table(
[
@@ -166,58 +173,49 @@ const EstExtra = (() => {
"누계수량",
"누계금액",
],
output.rows
.map((row, index) => ({ row, index }))
.filter(
({ row }) =>
!EstMath.num(row.Level) &&
(row.Code ||
row.Name ||
[54, 55, 57, 58, 62, 67].includes(Number(row.LinkIndex))),
)
.map(({ row, index }) => {
const editable = ![54, 55, 58, 59, 62, 67].includes(Number(row.LinkIndex));
const key = EstBusiness.rowKey(row, index),
input = round.inputs?.[key] || {};
const edit = (prefix) =>
`<input data-progress="${prefix}" data-key="${esc(key)}" type="number" step="any" value="${input[prefix] ?? row[prefix + "GN"] ?? 0}" ${round.locked || !editable || input[prefix + "Mode"] === "components" ? "disabled" : ""}>` +
(input[prefix + "Mode"] === "components"
? EstMath.components
.map(
(field, i) =>
`<label>${["노무", "재료", "경비", "실적"][i]}<input data-progress="${prefix + field}" data-key="${esc(key)}" type="number" step="any" value="${input[prefix + field] ?? 0}" ${round.locked ? "disabled" : ""}></label>`,
)
.join("")
: "");
const method = (prefix) =>
!editable
? "자동계산"
: `<select data-progress="${prefix}Mode" data-key="${esc(key)}" ${round.locked ? "disabled" : ""}>${[
["quantity", "수량"],
["amount", "금액"],
["ratio", "비율 %"],
["components", "비목 금액"],
]
.map(
([v, label]) =>
`<option value="${v}" ${v === (input[`${prefix}Mode`] || "quantity") ? "selected" : ""}>${label}</option>`,
)
.join("")}</select>`;
return [
esc(row.Code),
esc(row.Name),
number(row.GN),
number(row.JunGN),
edit("Gum"),
method("Gum"),
edit("Sa"),
method("Sa"),
number(row.GumTC),
number(row.SaTC),
number(row.TotalGN),
number(row.TotalTC),
];
}),
page.rows.map(({ row, index }) => {
const editable = ![54, 55, 58, 59, 62, 67].includes(Number(row.LinkIndex));
const key = EstBusiness.rowKey(row, index),
input = round.inputs?.[key] || {};
const edit = (prefix) =>
`<input data-progress="${prefix}" data-key="${esc(key)}" type="number" step="any" value="${input[prefix] ?? row[prefix + "GN"] ?? 0}" ${round.locked || !editable || input[prefix + "Mode"] === "components" ? "disabled" : ""}>` +
(input[prefix + "Mode"] === "components"
? EstMath.components
.map(
(field, i) =>
`<label>${["노무", "재료", "경비", "실적"][i]}<input data-progress="${prefix + field}" data-key="${esc(key)}" type="number" step="any" value="${input[prefix + field] ?? 0}" ${round.locked ? "disabled" : ""}></label>`,
)
.join("")
: "");
const method = (prefix) =>
!editable
? "자동계산"
: `<select data-progress="${prefix}Mode" data-key="${esc(key)}" ${round.locked ? "disabled" : ""}>${[
["quantity", "수량"],
["amount", "금액"],
["ratio", "비율 %"],
["components", "비목 금액"],
]
.map(
([v, label]) =>
`<option value="${v}" ${v === (input[`${prefix}Mode`] || "quantity") ? "selected" : ""}>${label}</option>`,
)
.join("")}</select>`;
return [
esc(row.Code),
esc(row.Name),
number(row.GN),
number(row.JunGN),
edit("Gum"),
method("Gum"),
edit("Sa"),
method("Sa"),
number(row.GumTC),
number(row.SaTC),
number(row.TotalGN),
number(row.TotalTC),
];
}),
) +
`<p class="business-note">${esc((output.errors || []).join(" / "))} 금회 도급액 ${number(output.total)} · 기성비율 ${number(output.ratio)}%</p>`;
body += table(
@@ -248,36 +246,30 @@ const EstExtra = (() => {
`<option value="${key}" ${key === comp ? "selected" : ""}>${["노무", "재료", "경비", "실적"][i]}</option>`,
)
.join("");
const rows = project.tables.EstMainDat.map((row, index) => ({ row, index }))
.filter(
({ row }) =>
(row.Code || row.Name) &&
!EstMath.num(row.Level) &&
![54, 55, 58, 59].includes(Number(row.LinkIndex)),
)
.map(({ row, index }) => {
const result = output.rows[index];
return [
esc(row.Code),
esc(row.Name),
EstViews.cell("EstMainDat", index, `A${comp}`, row[`A${comp}`]),
number(result[`Contract${comp}`]),
EstViews.cell("EstMainDat", index, comp, row[comp]),
number(result[`D${comp}`]),
number(result[`E${comp}`]),
number(result[`F${comp}`]),
EstViews.cell("EstMainDat", index, "EscPlanned", row.EscPlanned || 0),
EstViews.cell("EstMainDat", index, "EscActual", row.EscActual || 0),
EstViews.cell("EstMainDat", index, "EscProgress", row.EscProgress || 0),
number(result.EscExcluded),
number(result.EscApplied),
`<input type="checkbox" data-esc-auto="${index}" ${row.EscAuto !== false ? "checked" : ""} aria-label="적용제외 자동계산">`,
EstViews.cell("EstMainDat", index, "EscManualQuantity", row.EscManualQuantity ?? 0),
EstViews.cell("EstMainDat", index, "EscConstruction", row.EscConstruction ?? 0),
EstViews.cell("EstMainDat", index, "EscPS", row.EscPS ?? 0),
EstViews.cell("EstMainDat", index, "EscBefore", row.EscBefore ?? 0),
];
});
const page = EstBlockActions.escalationPage(state, project.tables.EstMainDat);
const rows = page.rows.map(({ row, index }) => {
const result = output.rows[index];
return [
esc(row.Code),
esc(row.Name),
EstViews.cell("EstMainDat", index, `A${comp}`, row[`A${comp}`]),
number(result[`Contract${comp}`]),
EstViews.cell("EstMainDat", index, comp, row[comp]),
number(result[`D${comp}`]),
number(result[`E${comp}`]),
number(result[`F${comp}`]),
EstViews.cell("EstMainDat", index, "EscPlanned", row.EscPlanned || 0),
EstViews.cell("EstMainDat", index, "EscActual", row.EscActual || 0),
EstViews.cell("EstMainDat", index, "EscProgress", row.EscProgress || 0),
number(result.EscExcluded),
number(result.EscApplied),
`<input type="checkbox" data-esc-auto="${index}" ${row.EscAuto !== false ? "checked" : ""} aria-label="적용제외 자동계산">`,
EstViews.cell("EstMainDat", index, "EscManualQuantity", row.EscManualQuantity ?? 0),
EstViews.cell("EstMainDat", index, "EscConstruction", row.EscConstruction ?? 0),
EstViews.cell("EstMainDat", index, "EscPS", row.EscPS ?? 0),
EstViews.cell("EstMainDat", index, "EscBefore", row.EscBefore ?? 0),
];
});
html = box(
"물가변동 품목조정",
`<select id="escalation-component">${choices}</select>` +
@@ -287,6 +279,13 @@ const EstExtra = (() => {
button("load-progress-exclusion", "기성 누계수량 불러오기") +
button("reset-escalation", "물가변동 입력 초기화") +
button("capture-baseline", "계약 내역 확정") +
button("escalation-prev", "이전", state.escalationPage === 0 ? "disabled" : "") +
`<span>${state.escalationPage + 1} / ${page.pages}쪽 · ${page.total}행</span>` +
button(
"escalation-next",
"다음",
state.escalationPage + 1 >= page.pages ? "disabled" : "",
) +
`<label>조사 도급액(0=단가로 계산) <input type="number" step="any" data-option="EscDesignTotal" value="${project.options.EscDesignTotal ?? 0}"></label>`,
table(
[