/** * STMATE w 8.0 — 초기값 입력및 수정 화면(wM_Set_Sys) 끼워 넣기 (scr_ui_sys.js) * 배치 근거: resource-TWM_SET_SYS.dfm.json — 환율/노임계수 · 소수점 적용기준 · 계산방식 · 금액 보정순서 * · 단가의 조사시점 · 재료비 적용단가 일괄적용 · 공사원가호환규정(XML) 계산방식 일괄적용 * 편집 = ctx.uiState.sysDraft(초안) → [전체 재계산후 종료]·[작업 종료] 때 dbfData.start_ini 와 state.sysConfig 에 반영 */ (function (global) { "use strict"; const P = (global.STMATE_PLUGINS = global.STMATE_PLUGINS || { screens: {}, actions: {}, menus: [], }); const S = global.STMATE_UI_SYS; const U = global.STMATE_UI_DAN; const esc = (s) => String(s == null ? "" : s).replace( /[&<>"]/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """ })[c], ); function draft(ctx) { const u = ctx.uiState; const ini = ctx.dbfData.start_ini || (ctx.dbfData.start_ini = {}); if (!u.sysDraft || u.sysDraftSrc !== ctx.currentSourcePath) { u.sysDraft = S.draftFromIni(ini); u.sysDraftSrc = ctx.currentSourcePath; u.sysRx = u.sysRx || "T"; } return u.sysDraft; } function field(f, d, n) { const k = S.keyOf(f, n || d.ARENM); const v = d[k] == null ? "" : d[k]; const title = f.hint ? ` title="${esc(f.hint)}"` : ""; if (f.type === "sel") return ``; if (f.type === "codes") return ``; return ``; } const row = (f, d, n) => `
${esc(f.cap)}${field(f, d, n)}
`; function render(ctx) { if (!ctx.dbfData) return `
초기값 입력및 수정 [wM_Set_Sys]

열린 프로젝트 없음 — 초기값(Start8x.Ini)은 프로젝트를 연 뒤 고칩니다.

`; const d = draft(ctx), u = ctx.uiState, ini = ctx.dbfData.start_ini; const changed = S.applyDraft(Object.assign({}, ini), d); const rx = S.RX_SETS.find((s) => s.id === u.sysRx) || S.RX_SETS[0]; const rxv = S.checkFormula(d.RXXNM); const slots = U.slotNames(ini); const errs = S.validate(d); return `
초기값 입력및 수정 [wM_Set_Sys · Start8x.Ini]바뀐 칸 ${changed.length}개${changed.length ? ` (${esc(changed.join(", "))})` : ""}
※ 수정하기 원하는 항목을 고치세요 ※ ${errs.length ? `${esc(errs.join(" · "))}` : ""}
환 율 / 노 임 계 수
환율 칸 ${d.ARENM === "2" ? "2(변경)" : "1(당초)"} 편집
${S.FIELDS.rate.map((f) => row(f, d)).join("")}
노임환산식 값: ${rxv.ok && rxv.value != null ? rxv.value.toFixed(8) : esc(rxv.error || "-")}
${field({ key: rx.rx, type: "text" }, d)}
${field({ key: rx.con, type: "codes" }, d)}
소 수 점 적 용 기 준${S.FIELDS.digits.map((f) => row(f, d)).join("")}
계 산 방 식${S.FIELDS.calc.map((f) => row(f, d)).join("")}
${d.OPTNM.split( "", ) .map( (c, i) => `${i + 1}. ${S.ORDER_NAMES[c]} `, ) .join( "", )}
재료비 적용단가 일괄적용
${esc(u.sysMsg || "")}

직접수정 판정 = 적용단가가 후보 5칸 어디에도 없음

`; } function commit(ctx, api, recalc) { const d = draft(ctx); const errs = S.validate(d); if (errs.length) return alert("고칠 칸: " + errs.join(" · ")); const changed = S.applyDraft(ctx.dbfData.start_ini, d); ctx.state.sysConfig = S.sysConfigFromIni(ctx.dbfData.start_ini, ctx.state.sysConfig); ctx.uiState.sysDraft = null; ctx.uiState.sysMsg = ""; ctx.uiState.activeScreen = "wPrjList"; if (recalc) api.cascadeAndRender(); else api.renderWorkspace(); if (changed.length) ctx.uiState.boqMsg = `초기값 ${changed.length}칸 반영(${changed.join(", ")})`; } // 직종·노임 설정(wM_Set_JLab) — 노무비 코드 목록에서 고른 코드를 적용코드 목록으로(추가·삭제) · 적용단가 미리보기 function openJLab(ctx, api, conKey, orig) { const d = draft(ctx), $ = (id) => document.getElementById(id); const ev = global.STMATE_SMT_EVAL; const hourly = ev && ev.hourlyWage; const ini = Object.assign({}, ctx.dbfData.start_ini, d); const j = S.jlab(ctx.dbfData.costn_rows, ini, conKey, hourly); const fmt = api.fmt; const tr = (r, cls) => `${esc(r.code)}${esc(r.name)}${esc(r.size)}${esc(r.unit)}${cls === "jl-del" ? `${r.hourly == null ? "" : fmt(r.hourly)}` : ""}${fmt(r.price)}`; api.openModal( `시간당 노임산출계수 적용코드 [wM_Set_JLab] — ${conKey} · 환산식 ${j.formula || "(없음)"}`, `

노무비 코드를 목록에서 선택하십시요 — 선택코드 추가 · 선택코드삭제 · 적용 / 취소

노무비 목록(Grd_BDLst)
${j.source.map((r) => tr(r, "jl-add")).join("")}
코드번호명칭규격단위단가
적용될 코드목록(Grd_CONLTD)
${j.target.map((r) => tr(r, "jl-del")).join("")}
코드번호명칭규격단위적용단가단가
`, ); let cur = String(d[conKey] != null ? d[conKey] : ini[conKey] || ""); const back = orig == null ? cur : orig; const picked = (cls) => [...document.querySelectorAll(`.${cls}:checked`)].map((x) => x.value); const apply = (next) => ( (d[conKey] = next), api.closeModal(), openJLab(ctx, api, conKey, back) ); $("jl-add").onclick = () => apply((cur = S.jlabEdit(cur, picked("jl-add"), []))); $("jl-del").onclick = () => apply((cur = S.jlabEdit(cur, [], picked("jl-del")))); $("jl-ok").onclick = () => (api.closeModal(), api.renderWorkspace()); $("jl-cancel").onclick = () => ((d[conKey] = back), api.closeModal(), api.renderWorkspace()); } function bind(ctx, api) { if (!ctx.dbfData) return; document .querySelectorAll("#sys-form .sys-jlab") .forEach((b) => (b.onclick = () => openJLab(ctx, api, b.getAttribute("data-k")))); const d = draft(ctx), u = ctx.uiState, $ = (id) => document.getElementById(id); document.querySelectorAll("#sys-form .sys-f").forEach( (el) => (el.onchange = () => { const k = el.getAttribute("data-k"); d[k] = /^CON/.test(k) ? S.joinCodes(String(el.value).split(/[,\s]+/)) : String(el.value).trim(); api.renderWorkspace(); }), ); $("sys-rx-sel").onchange = (e) => ((u.sysRx = e.target.value), api.renderWorkspace()); document .querySelectorAll("#sys-form .sys-opt") .forEach( (b) => (b.onclick = () => ( (d.OPTNM = S.moveOrder( d.OPTNM, Number(b.getAttribute("data-i")), Number(b.getAttribute("data-dir")), )), api.renderWorkspace() )), ); $("sys-opt-df").onclick = () => ((d.OPTNM = "SML"), api.renderWorkspace()); $("sys-xml").onclick = () => (S.xmlPreset(d), api.renderWorkspace()); $("sys-cancel").onclick = () => ((u.sysDraft = null), api.renderWorkspace()); $("sys-recalc").onclick = () => commit(ctx, api, true); $("sys-close").onclick = () => commit(ctx, api, false); $("sys-selm-ok").onclick = () => { const how = $("sys-selm").value; if (how === "none") return; const ch = U.adoptAll(ctx.dbfData.costn_rows, how, { kinds: "M", skipZero: $("sys-skip0").checked, keepUser: $("sys-keep").checked, }); ch.forEach((c) => { const res = (ctx.state.resources || []).find((r) => r.code === c.code); if (res) Object.assign(res, { adoptMode: `slot${c.slot}`, manualPrice: c.to }); }); u.sysMsg = `재료비 ${ch.length}건 적용단가 바꿈`; api.cascadeAndRender(); }; } P.screens.wM_Set_Sys = { render, bind }; })(window);