/* -*- coding: utf-8 -*- */ /** * STMATE 계산 사슬 및 제어 옵션 시뮬레이터 UI 컨트롤러 (app.js) */ const STORAGE_KEY = "aislo_stmate_test_v1"; function createDefaultSample() { const mkRes = (id, name, spec, unit, kind, candidates, manualPrice, convertHourly = false) => ({ id, code: id, name, spec, unit, kind, candidates, adoptMode: "min", manualPrice, convertHourly, isUsd: false, }); return { sysConfig: { rxFormula: "1/8*16/12*25/20", condCodes: "L00008, L00009, L00010", usdRate1: 1350, usdRate2: 1400, useChangedUsd: false, ecdDigits: 0, chnMode: "bimok", optOrder: "SML", kOrdSim: { pclass: 7, regMode: 7, flag: 0, currentK: 2 }, }, resources: [ mkRes( "L00008", "건설기계운전사 (일노임→시간당)", "표준직종", "hr", "노무비", [0, 0, 0, 0, 267360], 267360, true, ), mkRes("L00001", "보통인부", "시중노임", "인", "노무비", [165545, 0, 0, 0, 165545], 165545), mkRes("L00002", "특별인부", "시중노임", "인", "노무비", [212410, 0, 0, 0, 212410], 212410), mkRes( "M00001", "경유 (중기연료)", "저유황", "L", "재료비", [1520, 1480, 1453, 1510, 1490], 1453, ), mkRes( "M00002", "레미콘 (사급자재)", "25-24-150", "㎥", "재료비", [92000, 89500, 91000, 88700, 90000], 88700, ), mkRes( "M00901", "관급 원심력콘크리트관(흄관)", "D1000mm", "본", "재료비", [285000, 279000, 281000, 0, 279000], 279000, ), mkRes( "S00902", "조달수수료 (관급부대비)", "0.54%", "식", "경비", [771029, 0, 0, 0, 771029], 771029, ), ], machines: [ { id: "X00001", code: "X00001", name: "굴삭기 (무한궤도)", spec: "0.2 ㎥", unit: "hr", operatorId: "L00008", operatorCount: 1, fuelId: "M00001", fuelConsumption: 5.0, miscRatePercent: 6.0, acquisitionPrice: 41800000, hourlyRateFactor: 0.000312, }, ], sanItems: [ { id: "D00002", code: "D00002", name: "구조물 터파기(토사) 굴삭기 0.2㎥", spec: "기계 100%", unit: "㎥", machineId: "X00001", formulaType: "3600_qKfE_Cm", q: 0.2, K: 0.7, f: 0.85, E: 0.55, Cm: 15, }, ], ilwiItems: [ { id: "B00001", code: "B00001", name: "소형 구조물 기초 콘크리트 타설 및 터파기 복합공", spec: "인력+기계복합", unit: "㎥", lines: [ { refId: "M00002", qty: 1.0, halPercent: 2.0, devd: false }, { refId: "L00001", qty: 0.35, halPercent: 0, devd: false }, { refId: "L00002", qty: 0.15, halPercent: 0, devd: false }, { refId: "D00002", qty: 1.2, halPercent: 0, devd: false }, ], }, ], boqItems: [ { id: "BOQ1", code: "D00002", name: "본선 구조물 터파기 (토사)", refId: "D00002", rowType: "normal", qty: 1250.5, changedQty: 1420.0, }, { id: "BOQ2", code: "B00001", name: "배수 구조물 콘크리트 및 기초 복합시공", refId: "B00001", rowType: "normal", qty: 340.3, changedQty: 395.0, }, { id: "BOQ3", code: "M00901", name: "[제외구역 C4] 관급 흄관 자재대 (원자재)", refId: "M00901", rowType: "gov_mat", qty: 120, changedQty: 120, }, { id: "BOQ4", code: "S00902", name: "[제외구역 C4] 관급 조달수수료", refId: "S00902", rowType: "gov_fee", qty: 1, changedQty: 1, }, ], kanjubConfig: { scheme: "T", indirectTruncDigits: 0, anjunBaseAdd: 5349000, anjunGovVatExcluded: true, anjunCap12: true, vatMode: "supply_10", totJeolDigits: -3, enableProfitEndAdj: true, govRoundMode: "up", govRoundDigits: -3, rates: { KANNO: 14.5, SANBO: 3.56, KOBO: 1.01, KUNBO: 3.545, SLVBO: 12.95, YUNBO: 4.5, TBUGUM: 0.0, ANJUN: 1.86, KITA: 6.0, HWAN: 0.8, EQIP: 0.4, ILBAN: 6.0, IYUN: 15.0, S_SUDO: 0.45, S_BOKRI: 1.15, S_SOMO: 0.65, S_TONGSIN: 0.85, S_SEGUM: 0.55, S_PEGI: 0.35, S_DOSEO: 0.25, S_JIGUP: 0.45, }, revModes: { KANNO: "recalculated", SANBO: "recalculated", KOBO: "recalculated", KUNBO: "carry_original", SLVBO: "carry_original", YUNBO: "carry_original", TBUGUM: "recalculated", ANJUN: "recalculated", KITA: "recalculated", HWAN: "recalculated", EQIP: "recalculated", }, }, }; } let state = loadState(); let activeTab = "resources"; let selectedIlwiId = state.ilwiItems[0]?.id || ""; function loadState() { try { const raw = sessionStorage.getItem(STORAGE_KEY); if (!raw) return createDefaultSample(); const parsed = JSON.parse(raw); if (parsed && Array.isArray(parsed.resources) && parsed.kanjubConfig) return parsed; } catch (_) {} return createDefaultSample(); } function saveState() { try { sessionStorage.setItem(STORAGE_KEY, JSON.stringify(state)); } catch (_) {} } const $ = (id) => document.getElementById(id); const esc = (s) => String(s ?? "").replace( /[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c], ); const fmt = (n, maxDec = 2) => new Intl.NumberFormat("ko-KR", { maximumFractionDigits: maxDec }).format(Number(n) || 0); const uid = (prefix) => `${prefix}${Date.now().toString(36).slice(-4)}${Math.random().toString(36).slice(2, 5)}`; function renderAll() { const res = StmateCalc.calculateAll(state); renderKpi(res); document.querySelectorAll("#mainTabs button[data-tab]").forEach((btn) => { btn.classList.toggle("active", btn.dataset.tab === activeTab); }); const panel = $("tabPanel"); if (activeTab === "resources") panel.innerHTML = renderResourcesTab(res); else if (activeTab === "machines") panel.innerHTML = renderMachinesTab(res); else if (activeTab === "ilwi") panel.innerHTML = renderIlwiTab(res); else if (activeTab === "boq") panel.innerHTML = StmateCostViews.renderBoqTab(state, res); else if (activeTab === "kanjub") panel.innerHTML = StmateCostViews.renderKanjubTab(state, res); else if (activeTab === "revision") panel.innerHTML = StmateCostViews.renderRevisionTab(state, res); } function renderKpi(res) { const k = res.kanjubOrig, kr = res.kanjubRev; const cards = [ [ "직접공사비 (재+직노+산출경비)", `${fmt(k.dT, 0)} 원`, `재료 ${fmt(k.dM, 0)} · 직노 ${fmt(k.dL, 0)} · 산출경비 ${fmt(k.dS, 0)}`, ], [ "순공사원가 (직접비+간접비)", `${fmt(k.pureConstructionCost, 0)} 원`, `간접노무비 ${fmt(k.kanno, 0)} · 제경비소계 ${fmt(k.indirectExpenseSum, 0)}`, ], [ "도급공사비 (끝전보정 후)", `${fmt(k.contractFinal, 0)} 원`, `이윤 세전조정: ${k.pretaxProfitAdj >= 0 ? "-" : "+"}${fmt(Math.abs(k.pretaxProfitAdj), 0)} 원`, ], [ "총공사비 (도급 + 관급자재)", `${fmt(k.grandTotal, 0)} 원`, `관급자재대 ${fmt(k.govFinal, 0)} · 변경차액 ${kr.grandTotal - k.grandTotal >= 0 ? "+" : ""}${fmt(kr.grandTotal - k.grandTotal, 0)}`, ], ]; $("kpiSummary").innerHTML = cards .map( ([title, val, sub]) => `
ST_Sys.CPM · INITIAL)STMATE는 RXNM_에 저장된 식(1/8*16/12*25/20)을 왼쪽부터 차례로 평가합니다. 계수를 미리 곱하면 부동소수점 오차로 55,699원이 되어 1원 오차가 발생합니다(18번 문서 §2.1).
COSTN.DBF · JMKN1..6)0이 아닌 후보 단가 중 최저가 자동채택(실무 76/76건 일치, 17번 문서 §5.5) 또는 특정 가격지 슬롯 수동고정을 실험합니다.
| 코드 | 품명 / 규격 | 단위 | 비목 | 후보1(조달) | 후보2(물자) | 후보3(물정) | 후보4(거래) | 후보5(견적) | 채택 규칙 | 시간환산 | 최종 채택단가(6칸) | 관리 |
|---|
X 코드 · 중기사용료 시트)중기 한 대를 참조할 때 노무비(&X..L&), 재료비(&X..M&), 경비(&X..S&) 세 성분을 각각 원 단위 절사하여 산출합니다(17번 문서 §3).
| 코드 | 기계명 | 규격 | 운전원(L) | 주연료(M) | 연료량(L/hr) | 잡품률(%) | 취득가격(원) | 시간손료계수 | 재료비(M) | 노무비(L) | 경비(S) | 시간당합계(T) | 관리 |
|---|
D 코드 · ST_SanCal.CPM · COSTN.SMT)작업량 Q를 소수 2자리로 먼저 확정한 뒤, 중기 시간당 성분단가를 Q로 나누어 소수 1자리 절사합니다. 내역서 수록 시에는 정수 절사값이 전달됩니다(18번 문서 §2.2).
| 코드 | 단가산출 공종명 | 참조 중기(&X..&) | Q 산출식 유형 | q(용량) | K(계수) | f(토량) | E(효율) | Cm(싸이클) | 작업량 Q(㎥/hr) | 재료비/Q | 노무비/Q | 경비/Q | 호표소계(소수1) | 관리 |
|---|
| 참조 자원 / 단가산출 | 원수량(QTY1) | 역수(DEVD1) | 할증(X_HAL %) | 적용수량 | 재료비 | 노무비 | 경비 | 행 합계 | 관리 |
|---|
ST_EdiLWi.CPM · BDQTY.DBF)구성 자원의 수량 할증(X_HAL) 및 나눗셈 수량 역수 변환(DEVD1: 1/QTY1, 16단계·30단계 REA 메모)을 적용하고, 호표 소계에서 각 성분을 원 단위로 절사하여 TAMT = MAMT + LAMT + SAMT 불변식을 유지합니다.