/** * 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 `
⚙️ 초기값 입력 및 수정 [wM_Set_Sys · PRJLST.DBF 초기값 변수 42종] 노임환산식 좌→우 평가: ${evalRx.toFixed(6)}
변경된 초기값은 기초단가·중기사용료·일위대가·내역서에 즉시 전파됩니다.
1. 환율 및 소수 자리수 설정 (EXLNM1/2 · KCD · ACD · ZCD · JCD · ECD · BPN)
2. 노임 시간당 환산식 (RXNM_ · 좌→우 순차 평가 18번 §2.1) 및 특수노임 조건코드 (RX1~5CD)

※ STMATE 고유 파서 검증: 1/8*16/12*25/20 → 좌→우 순차 평가 0.20833333 (기계운전원 일급 267,360원 × 0.20833333 = 55,700원/hr 정확 재현)

3. 현재 프로젝트 PRJLST.DBF 원본 초기값 필드
`; } /** * 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 `
📋 단가목록표 [wM_JabPum · COSTN.DBF 전수 원장] — 총 ${rawCostn.length}건 중 ${filtered.length}건 표시 5개 가격지 후보(AMT_11~51) 및 적용단가(TAMT1 = MAMT1 + LAMT1 + SAMT1)
${Object.keys(KIND_LABELS) .map( (k) => ` `, ) .join("")}
${filtered .map((r, i) => { const code = String(r.CODE || "").trim(); const p = code[0].toUpperCase(); const res = resMap[code]; const m1 = res ? res.kind === "재료비" ? res.appliedPrice : 0 : num(r.MAMT1); const l1 = res ? res.kind === "노무비" ? res.appliedPrice : 0 : num(r.LAMT1); const s1 = res ? (res.kind === "경비" ? res.appliedPrice : 0) : num(r.SAMT1); const t1 = m1 + l1 + s1 || num(r.TAMT1); const hasMemo = Boolean(memos[code]); return ` `; }) .join("")}
No 코드(CODE) 구분 명칭 (NAME) 규격 (SIZE) 단위 재료단가(MAMT1) 노무단가(LAMT1) 경비단가(SAMT1) 합계단가(TAMT1) 1단가(조달) 2단가(물가) 3단가(거래) 산근/대가
${i + 1} ${code} ${p} ${r.NAME || ""} ${r.SIZE || ""} ${r.UNIT || ""} ${fmt(t1)} ${num(r.AMT_11) ? fmt(r.AMT_11) : "-"} ${num(r.AMT_21) ? fmt(r.AMT_21) : "-"} ${num(r.AMT_31) ? fmt(r.AMT_31) : "-"} ${ hasMemo || p === "B" || p === "D" || p === "X" ? `` : "-" }
`; } /** * 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 `
🧮 일위대가 · 단가산출근거 · 중기사용료 편집기 [wM_Edit_iLWi / wM_Edit_San / COSTN.SMT] 선택 호표: ${selCode} ${selRow.NAME || ""} (SIxMemo 블록 #${memoObj ? memoObj.blockNo : "-"}, ${memoObj ? memoObj.byteLen : 0} bytes)
호표 마스터 목록 (클릭 시 우측 COSTN.SMT 전개식 로드) 총 ${bdxRows.length}건
${bdxRows .map((r) => { const c = String(r.CODE || "").trim(); const isSel = c === selCode; const hasM = Boolean(memos[c]); return ` `; }) .join("")}
코드 품명 (NAME) 규격 단위 합계단가 SMT
${c} ${r.NAME || ""} ${r.SIZE || ""} ${r.UNIT || ""} ${fmt(num(r.TAMT1))} ${hasM ? "📝" : "-"}
📝 COSTN.SMT 전개 텍스트 편집기 — &X00026L& 참조 · Q=3600*q*K*f*E/Cm · :=A01 문법 실시간 해석 DB 저장단가: 재 ${fmt(num(selRow.MAMT1))} / 노 ${fmt(num(selRow.LAMT1))} / 경 ${fmt(num(selRow.SAMT1))} / 계 ${fmt(num(selRow.TAMT1))}원
🔍 SIxMemo 수식 파서 실시간 평가 결과 (변수: ${ Object.keys(evalRes.vars) .map((k) => `${k}=${evalRes.vars[k]}`) .join(", ") || "없음" }) 평가 합계: 재 ${fmt(evalRes.sumM)} + 노 ${fmt(evalRes.sumL)} + 경 ${fmt(evalRes.sumS)} = ${fmt(evalRes.sumT)}원
${evalRes.linesOut .map( (ln) => ` `, ) .join("")}
행 산식 원문 (COSTN.SMT Line) 변수 대입/평가 자원참조(&코드&) 참조단가 산출금액
${ln.lineNo} ${ln.raw} ${ln.assigned || ""} ${ln.refInfo ? `${ln.refInfo.refCode}[${ln.refInfo.compTag}] (${ln.refInfo.refName})` : ""} ${ln.refInfo ? fmt(ln.refInfo.baseUnitPrice) : ""} ${ln.refInfo ? fmt(ln.refInfo.calcAmt, 1) : ""}
`; } /** * 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}종

특수 단가산출 21개 (Q식/사이클식 원문)
${(cat.special_san || []) .map( (s, idx) => ` `, ) .join("")}
호표명칭단위Q식편집기로 복사
#${s["호표"]} ${s["명칭"]} ${s["단위"]} ${(s["인자"] && s["인자"].Q) || ""}
표준 일위대가 레시피 (${cat.recipes.length}종 중 상위 60종)
${(cat.recipes || []) .slice(0, 60) .map( (r) => ` `, ) .join("")}
구분명칭규격단위구성수
${r["종류"]} ${r["명칭"]} ${r["규격"] || ""} ${r["단위"] || ""} ${(r["구성"] || []).length}행
`; } global.STMATE_VIEW_DAN_ILWI = { evaluateSmtFormulaText, renderWMSetSys, renderWMJabPum, renderWMEditIlwi, buildDanModalHtml, }; })(window);