fix(stmate-test): resolve 5 UI/calculation issues found during browser control verification

This commit is contained in:
2026-11-05 06:11:43 +09:00
parent 267b5a693f
commit 91d5f478cc
4 changed files with 83 additions and 11 deletions
+39 -1
View File
@@ -188,8 +188,39 @@
renderWorkspace();
});
onClick("modal-apply-expnd", () => {
const code = ($("expnd-code") || {}).value;
const ilwi =
(ctx.state.ilwiItems || []).find((x) => x.code === code) || ctx.state.ilwiItems[0];
if (ilwi && ilwi.lines && ilwi.lines.length) {
ilwi.lines.forEach((ln, idx) => {
const r = ctx.state.resources.find((x) => x.id === ln.refId || x.code === ln.refId);
const recno = (Date.now() % 90000) + idx + 1;
ctx.state.boqItems.push({
id: "BOQ_" + recno,
code: r ? r.code : ln.refId,
name: `[전개] ${r ? r.name : ln.refId}`,
refId: ln.refId,
rowType: "normal",
qty: ln.qty || 1,
changedQty: ln.qty || 1,
_recno: recno,
});
if (ctx.dbfData && ctx.dbfData.boq_rows) {
ctx.dbfData.boq_rows.splice(5 + idx, 0, {
_recno: recno,
ITNUM: "",
BDCODE1: r ? r.code : ln.refId,
NAME1: `[전개] ${r ? r.name : ln.refId}`,
SIZE1: r ? r.spec : "",
UNIT1: r ? r.unit : "식",
QTY1: String(ln.qty || 1),
ENDCODE: "0.0000",
});
}
});
}
closeModal();
alert("선택 공종의 일위대가/산근 구성행이 전개되었습니다.");
renderWorkspace();
});
bindEach(".btn-apply-qty-expr", "onclick", (btn) => {
const id = btn.getAttribute("data-id");
@@ -455,6 +486,13 @@
const code = $("ilwi-btn-apply-f9").getAttribute("data-code");
const txt = ($("smt-formula-textarea") || {}).value || "";
ctx.uiState.editedSmtMap[code] = txt;
if (ctx.dbfData && ctx.dbfData.costn_memos) {
const prev = ctx.dbfData.costn_memos[code] || { code, blockNo: 1 };
ctx.dbfData.costn_memos[code] = Object.assign({}, prev, {
text: txt,
byteLen: txt.length,
});
}
const evalRes = ViewDanIlwi.evaluateSmtFormulaText(txt, ctx);
if (evalRes.sumT > 0)
ViewPrjBoq.syncCostnUnitPrice(ctx, code, evalRes.sumM, evalRes.sumL, evalRes.sumS);
+18 -3
View File
@@ -327,7 +327,10 @@ const StmateCalc = (() => {
});
const directT = directM + directL + directS,
govCombinedRaw = govRawTotal + govFeeTotal;
const totals = { directM, directL, directS, directT, govRawTotal, govFeeTotal, govCombinedRaw };
const totals = Object.assign(
{ directM, directL, directS, directT },
{ govRawTotal, govMatTotal: govRawTotal, govFeeTotal, govCombinedRaw },
);
return Object.assign({ rows, directTotal: directT, totals }, totals);
}
@@ -348,7 +351,7 @@ const StmateCalc = (() => {
const truncAmt = truncInd(rawCalcAmt);
const base = Object.assign(
{ key: code, code, label, formula: baseDesc },
{ baseDesc, baseAmt, rate: ratePct, ratePct },
{ baseDesc, baseAmt, base: baseAmt, rate: ratePct, ratePct },
);
if (!origKanjubRes) return Object.assign(base, { amount: truncAmt, modeUsed: "원설계" });
const origRow = origKanjubRes.itemMap[code],
@@ -507,6 +510,7 @@ const StmateCalc = (() => {
["label", label],
["formula", formula],
["baseAmt", baseAmt],
["base", baseAmt],
["rate", rate],
["amount", amount],
]);
@@ -658,8 +662,19 @@ const StmateCalc = (() => {
kanjubOrig = calcKanjub(data, boqOrig, null);
const boqRev = calcBoq(data, resources.map, machines.map, sanCal.map, ilwi.map, true),
kanjubRev = calcKanjub(data, boqRev, kanjubOrig);
const revMap = Object.fromEntries((boqRev.rows || []).map((r) => [r.id, r]));
(boqOrig.rows || []).forEach((r) => {
const rv = revMap[r.id];
r.changedTAmt = rv ? rv.tAmt : r.tAmt;
r.diffTAmt = r.changedTAmt - r.tAmt;
});
const base = { resources, machines, sanCal, ilwi, boqOrig, kanjubOrig };
Object.assign(base, { boqRev, kanjubRev, resList: resources.list });
Object.assign(base, {
boqRev,
kanjubRev,
resList: resources.list,
revComputed: { revBoq: boqRev, revKj: kanjubRev },
});
return Object.assign(base, { boqComputed: boqOrig, kanjubComputed: kanjubOrig });
}
+21 -4
View File
@@ -82,13 +82,14 @@
const vExpr = m[2].trim();
const val = evalMathWithVars(vExpr);
if (val > 0 || vExpr === "0") {
vars[vName] = Math.round(val * 10000) / 10000;
vars[vName] = Math.round(val * 100) / 100;
assignedHere.push(`${vName} = ${vars[vName]}`);
}
}
// 2) 자원 참조 (&X00026L& / Q = , &M00080& * 0.00438'㎥' = )
// 2) 자원 참조 (&X00026L& / Q = , &M00080& * 0.00438'㎥' = ) 또는 주석형 단가 요약
const refMatch = ln.match(/&([A-Z]\d{4,5})([LMS])?&(.*)/);
const commentCostMatch = !refMatch && ln.match(/(재료비|노무비|경\s*비)\s*[:=]\s*([\d,]+)/);
let refInfo = null;
if (refMatch) {
const refCode = refMatch[1];
@@ -116,6 +117,20 @@
baseUnitPrice,
calcAmt: roundedAmt,
};
} else if (commentCostMatch) {
const cKind = commentCostMatch[1].replace(/\s+/g, "");
const cVal = num(commentCostMatch[2], 0);
const cTag = cKind === "노무비" ? "L" : cKind === "경비" ? "S" : "M";
if (cTag === "L") sumL += cVal;
else if (cTag === "S") sumS += cVal;
else sumM += cVal;
refInfo = {
refCode: cKind,
compTag: cTag,
refName: "단가 직접지정",
baseUnitPrice: cVal,
calcAmt: cVal,
};
}
linesOut.push({
@@ -357,8 +372,10 @@
ctx.uiState.selectedIlwiCode &&
bdxRows.some((r) => String(r.CODE).trim() === ctx.uiState.selectedIlwiCode)
? ctx.uiState.selectedIlwiCode
: bdxRows[0]
? String(bdxRows[0].CODE).trim()
: bdxRows.find((r) => Boolean(memos[String(r.CODE || "").trim()])) || bdxRows[0]
? String(
(bdxRows.find((r) => Boolean(memos[String(r.CODE || "").trim()])) || bdxRows[0]).CODE,
).trim()
: "";
const selRow = bdxRows.find((r) => String(r.CODE).trim() === selCode) || {};
+5 -3
View File
@@ -518,14 +518,16 @@
`;
}
if (toolKind === "wExpnd") {
const bdxList = (ctx.state.ilwiItems || []).slice(0, 30);
return `
<div style="display:flex;flex-direction:column;gap:10px;">
<p style="margin:0;"><strong>[wExpnd / wM_Expnd] 일위대가·단가산출 내역서 풀어넣기</strong> — 호표 구성행을 내역서 하위 행으로 전개합니다.</p>
<div class="kanjub-16grid" style="grid-template-columns:repeat(2,1fr);">
<p style="margin:0;"><strong>[wExpnd / wM_Expnd] 일위대가·단가산출 내역서 풀어넣기</strong> — 선택한 호표의 재료·노무·경비 구성행을 내역서에 직접 전개합니다.</p>
<div class="kanjub-16grid" style="grid-template-columns:repeat(3,1fr);">
<div class="kanjub-field"><label>전개할 호표 선택</label><select id="expnd-code">${bdxList.map((x) => `<option value="${x.code}">${x.code} ${x.rawName || x.name}</option>`).join("")}</select></div>
<div class="kanjub-field"><label>집계 구분선(RGrpToT)</label><select id="expnd-tot"><option value="E1">소계(=)</option><option value="E2">계(==)</option><option value="E3">합계(===)</option></select></div>
<div class="kanjub-field"><label>단가 끝전 처리</label><select id="expnd-round"><option value="trunc">절삭하여 소수 0위 적용</option><option value="round">반올림하여 소수 0위 적용</option></select></div>
</div>
<div style="text-align:right;"><button class="win-btn primary" id="modal-apply-expnd">일위대가 풀어넣기 확인</button></div>
<div style="text-align:right;"><button class="win-btn primary" id="modal-apply-expnd">일위대가 풀어넣기 실행</button></div>
</div>
`;
}