/**
* STMATE w 8.0 — 초기값(wM_Set_Sys) · 단가목록표(wM_JabPum) · 대가표/산근 편집기(wM_Edit_iLWi · wM_Edit_San · COSTN.SMT)
* 근거: 22_UI_폼_분석.md, 23_COSTN_SMT_전수파싱.md, 26_편집기와_사이클식.md, 28_변환_수량산출_식언어.md, 34_화면구조_정리.md
*/
(function (global) {
"use strict";
const Calc = global.STMATE_CALC;
const fmt = Calc.fmt;
const num = Calc.num;
const KIND_LABELS = {
ALL: "모든단가",
L: "노무비(L)",
M: "재료비(M)",
S: "경비(S)",
B: "일위대가(B)",
X: "중기비(X)",
D: "단가산출(D)",
W: "견적/표준시장(W)",
};
/**
* COSTN.SMT 텍스트를 실시간 평가하여 Q식, Cm식, 참조(&X00006L/M/S&) 단가 및 비목별 합계 산출
*/
function evaluateSmtFormulaText(smtText, ctx, codeHint) {
if (global.STMATE_ENGINE && global.STMATE_ENGINE.evaluateSmtFormulaText) {
return global.STMATE_ENGINE.evaluateSmtFormulaText(smtText, ctx, codeHint);
}
return { vars: {}, linesOut: [], sumM: 0, sumL: 0, sumS: 0, sumT: 0 };
}
/**
* 1. wM_Set_Sys (초기값 입력 및 수정 화면)
*/
function renderWMSetSys(ctx) {
const sys = ctx.state.sysConfig;
const prj = (ctx.dbfData && ctx.dbfData.prjlst) || {};
const evalRx = Calc.evalLeftToRight(sys.rxFormula);
return `
`;
}
/**
* 2. wM_JabPum (단가목록표 화면 — COSTN.DBF 100% 전수 조회·편집)
*/
function renderWMJabPum(ctx) {
const rawCostn = (ctx.dbfData && ctx.dbfData.costn_rows) || [];
const memos = (ctx.dbfData && ctx.dbfData.costn_memos) || {};
const filterKind = ctx.uiState.danFilter || "ALL";
const kw = (ctx.uiState.danSearch || "").trim().toLowerCase();
// state.resources 수정값 동기화
const resMap = {};
(ctx.computed.resList || []).forEach((r) => {
if (!r.isSynthetic) resMap[r.code] = r;
});
const counts = { ALL: rawCostn.length, L: 0, M: 0, S: 0, B: 0, X: 0, D: 0, W: 0 };
rawCostn.forEach((r) => {
const p = String(r.CODE || " ")[0].toUpperCase();
if (counts[p] !== undefined) counts[p]++;
});
const filtered = rawCostn.filter((r) => {
const code = String(r.CODE || "").trim();
if (!code) return false;
const p = code[0].toUpperCase();
if (filterKind !== "ALL" && p !== filterKind) return false;
if (kw) {
const memoTxt = memos[code] ? memos[code].text : "";
const hay =
`${code} ${r.NAME || ""} ${r.SIZE || ""} ${r.UNIT || ""} ${memoTxt}`.toLowerCase();
if (!hay.includes(kw)) return false;
}
return true;
});
return `
`;
}
/**
* 3. wM_Edit_iLWi / wM_Edit_San / wM_Edit_EQ (일위대가 · 단가산출근거 · 중기사용료 통합 편집 화면)
* - 좌측: COSTN.DBF 내 B(일위대가), D(단가산출), X(중기) 전체 목록 + COSTN.SMT 보유 여부
* - 우측 상단: 선택 항목의 COSTN.SMT 원문 편집기 (`&X00006L&`, `Q=3600*q*K*f*E/Cm`, `:=A01`)
* - 우측 하단: 실시간 파싱·변수 평가 결과 테이블 및 [단가에 반영(F9)]
*/
function renderWMEditIlwi(ctx) {
const rawCostn = (ctx.dbfData && ctx.dbfData.costn_rows) || [];
const memos = (ctx.dbfData && ctx.dbfData.costn_memos) || {};
const subFilter = ctx.uiState.ilwiSubFilter || "ALL_BDX";
const bdxRows = rawCostn.filter((r) => {
const c = String(r.CODE || "").trim();
if (!c) return false;
const p = c[0].toUpperCase();
if (subFilter === "ALL_BDX") return p === "B" || p === "D" || p === "X" || Boolean(memos[c]);
if (subFilter === "SMT_ONLY") return Boolean(memos[c]);
return p === subFilter;
});
const selCode =
ctx.uiState.selectedIlwiCode &&
bdxRows.some((r) => String(r.CODE).trim() === ctx.uiState.selectedIlwiCode)
? ctx.uiState.selectedIlwiCode
: 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) || {};
const memoObj = memos[selCode] || null;
const recipeComps =
global.STMATE_ENGINE && global.STMATE_ENGINE.getRecipeBreakdown
? global.STMATE_ENGINE.getRecipeBreakdown(ctx, selCode)
: [];
const defaultText = memoObj
? memoObj.text
: recipeComps.length
? `'▣ ${selRow.NAME || selCode} (${selRow.SIZE || ""}) — 표준 호표 조립 구성 (${recipeComps.length}행)'\r\n` +
recipeComps
.map(
(c, ci) =>
`'${ci + 1}. ${c["명칭"]} (${c["규격"] || "-"}) : 수량 ${c["수량"]} ${c["단위"] || ""}'`,
)
.join("\r\n") +
`\r\n'노 무 비 : ${num(selRow.LAMT1)}'\r\n'재 료 비 : ${num(selRow.MAMT1)}'\r\n'경 비 : ${num(selRow.SAMT1)}'\r\n(==)`
: `'▣ ${selRow.NAME || selCode} (${selRow.SIZE || ""})'\r\n'1. 재료비 : ${fmt(num(selRow.MAMT1))}원'\r\n'2. 노무비 : ${fmt(num(selRow.LAMT1))}원'\r\n'3. 경 비 : ${fmt(num(selRow.SAMT1))}원'\r\n(==)`;
const currentSmtText =
ctx.uiState.editedSmtMap && ctx.uiState.editedSmtMap[selCode] !== undefined
? ctx.uiState.editedSmtMap[selCode]
: defaultText;
const evalRes = evaluateSmtFormulaText(currentSmtText, ctx, selCode);
return `
`;
}
/**
* 4. 단가/카탈로그 모달 생성기 (wM_Boxa / wM_Edt_Hal / 표준카탈로그 894코드·350레시피·21특수산식)
*/
function buildDanModalHtml(modalKind, ctx) {
if (modalKind === "wM_Boxa") {
return `
[wM_Boxa] 5개 가격지 단가 비교·일괄 채택 — 자재 후보단가(AMT_11~51) 중 지정 슬롯 또는 최저가를 적용단가(AMT_61/MAMT1)로 일괄 채택합니다.
`;
}
if (modalKind === "wM_Edt_Hal") {
return `
[wM_Edt_Hal] 기준단가 비율 일괄 수정 — 적용단가 = 기준단가 × 비율(%) (적용단가 0원 및 보호항목 UC=T 제외).
`;
}
// 표준 카탈로그 (894 코드 · 350 일위대가 레시피 · 21 특수 단가산출)
const cat = ctx.catalogData || { codes: [], recipes: [], special_san: [] };
return `
[STMATE 표준 카탈로그 브라우저] — 30_원자료에서 추출한 표준코드 ${cat.codes.length}종 · 일위대가 레시피 ${cat.recipes.length}종 · 특수 단가산출 ${cat.special_san.length}종
표준 일위대가 레시피 (${cat.recipes.length}종 중 상위 60종)
`;
}
global.STMATE_VIEW_DAN_ILWI = {
evaluateSmtFormulaText,
renderWMSetSys,
renderWMJabPum,
renderWMEditIlwi,
buildDanModalHtml,
};
})(window);