/** * STMATE w 8.0 — 단가목록표 화면(wM_JabPum) 끼워 넣기 (scr_ui_dan.js) * 근거: ui_form_catalog.txt wM_JabPum(cBoxCode 10종 · cBox_IFORM 명칭,규격/산근내용) · wM_Boxa(RG_MComp) · wM_Edt_Hal(wcBx_Up) * 후보 5칸 = COSTN AMT_11~51(페이지 PG_11~51) · 채택 = PG_1 · 가격지 이름 = 초기값 JMOK1~5/JMK10~50 * 기초단가(M·L·S) 고침 = COSTN 자기 비목 칸 + 계산 원천 자원(manualPrice) → 연쇄 재계산 */ (function (global) { "use strict"; const P = (global.STMATE_PLUGINS = global.STMATE_PLUGINS || { screens: {}, actions: {}, menus: [], }); const U = global.STMATE_UI_DAN; const esc = (s) => String(s == null ? "" : s).replace( /[&<>"]/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """ })[c], ); const $ = (id) => document.getElementById(id); const prefs = () => (global.STMATE_UI_APP_MENU && global.STMATE_UI_APP_MENU.prefs) || {}; function st(ctx) { const u = ctx.uiState; u.dan = u.dan || { kind: u.danFilter && u.danFilter !== "ALL" ? u.danFilter : "ALL", kw: "", mode: "name", sort: "", code: "", }; return u.dan; } // 자원(계산 원천) 맞춤 — 기초단가 한 건 function syncRes(ctx, code, price, how) { const res = (ctx.state.resources || []).find((r) => r.code === code && !r.isSynthetic); if (res) Object.assign(res, { adoptMode: how || "manual", manualPrice: price }); } function render(ctx, api) { if (!ctx.dbfData) return `
단가목록표 [wM_JabPum]

열린 프로젝트 없음

`; const s = st(ctx), rows = ctx.dbfData.costn_rows || []; const ini = ctx.dbfData.start_ini || {}; const slots = U.slotNames(ini); const sort = s.sort || prefs().dflIndex || "C"; const list = U.filterRows(rows, { kind: s.kind, kw: s.kw, mode: s.mode, sort, memos: ctx.dbfData.costn_memos || {}, }); const cnt = U.counts(rows); const n2 = prefs().useName2; const nm = (r, k) => (n2 && String(r[`${k}2`] || "").trim() ? r[`${k}2`] : r[k]) || ""; const slotName = (n) => { const x = slots.list.find((q) => q.slot === n); return x ? x.short || x.name : ""; }; const { fmt } = api; const body = list .map((r, i) => { const c = U.codeOf(r), base = U.isBase(c), cand = U.candidates(r), pg = U.pages(r), ad = U.adoptedSlot(r); const priceCell = (k) => base && k[0] === c[0] ? `` : `${U.num(r[k]) ? fmt(r[k]) : ""}`; return ` ${i + 1}${c} ${esc(nm(r, "NAME"))}${esc(nm(r, "SIZE"))}${esc(r.UNIT)} ${priceCell("MAMT1")}${priceCell("LAMT1")}${priceCell("SAMT1")} ${fmt(U.appliedPrice(r))} ${slots.list .map(({ slot: n }) => { const v = cand[n - 1]; const on = ad === n ? "background:#fde68a;font-weight:700;" : ""; const click = base && v > 0 ? ` class="num dan-adopt" data-code="${c}" data-slot="${n}" style="cursor:pointer;${on}" title="이 단가 채택"` : ` class="num" style="${on}"`; return `${v ? fmt(v) : ""}${pg[n - 1] ? `
p.${esc(pg[n - 1])}` : ""}`; }) .join("")} ${ad ? esc(slotName(ad)) : base && U.isUserEdited(r) ? "직접" : ""} ${esc(r.BQCODE || "")}${esc(r.EQCODE || "")} ${/^[BDX]/.test(c) ? `` : ""} `; }) .join(""); return `
단가목록표 [wM_JabPum · COSTN.DBF] — ${rows.length}건 중 ${list.length}건${esc(slots.applied)} = 재료비 + 노무비 + 경비
${esc(ctx.uiState.danMsg || "")}
${slots.list.map((x) => ``).join("")}${body}
No코드명칭규격단위재료비노무비경비${esc(slots.applied)}${esc(x.name)}채택분류번호시설코드
`; } function boxa(ctx, api) { const slots = U.slotNames(ctx.dbfData.start_ini); const s = st(ctx); api.openModal( "단가목록표 가격지 비교 (wM_Boxa)", `
`, ); $("bx-ok").onclick = () => { const how = $("bx-how").value, scope = $("bx-scope").value; const rows = scope === "one" ? ctx.dbfData.costn_rows.filter((r) => U.codeOf(r) === s.code) : ctx.dbfData.costn_rows; const ch = U.adoptAll(rows, how, { kinds: scope === "one" ? "MLS" : scope, skipZero: $("bx-skip0").checked, keepUser: scope !== "one" && $("bx-keep").checked, }); ch.forEach((c) => syncRes(ctx, c.code, c.to, `slot${c.slot}`)); ctx.uiState.danMsg = `${ch.length}건 채택 바꿈`; api.closeModal(); api.cascadeAndRender(); }; } function edtHal(ctx, api) { const s = st(ctx); api.openModal( "기준단가 수정 (wM_Edt_Hal)", `
%

※ 단【 적용단가 】가 "0" 원인것은 수정안됨 · 기준단가 = 채택 물가지 단가(채택 없으면 지금 적용단가)

보호표시 칸은 COSTN 자료에서 확인되지 않아 걸러내지 못함

`, ); $("eh-ok").onclick = () => { const kind = $("eh-kind").value; const ch = U.edtHal(ctx.dbfData.costn_rows, { kinds: kind === "one" ? "MLS" : kind, codes: kind === "one" ? [s.code] : null, pct: $("eh-pct").value, digits: Number($("eh-dot").value), mode: $("eh-up").value, }); ch.forEach((c) => syncRes(ctx, c.code, c.to, "manual")); ctx.uiState.danMsg = `기준단가 수정 ${ch.length}건`; api.closeModal(); api.cascadeAndRender(); }; } function findUse(ctx, api) { const s = st(ctx), f = U.findUse(s.code, ctx.dbfData); const li = (a) => (a.length ? a.join("") : "
  • (없음)
  • "); api.openModal( `사용처 찾기 — ${s.code}`, `
    내역서 ${f.boq.length}곳 일위대가·중기 구성표 ${f.comp.length}곳 단가산출근거 식 ${f.memo.length}곳
    `, ); } function bind(ctx, api) { if (!ctx.dbfData) return; const s = st(ctx), rr = () => api.renderWorkspace(); $("dan-kind").onchange = (e) => ((s.kind = e.target.value), rr()); $("dan-mode").onchange = (e) => ((s.mode = e.target.value), rr()); $("dan-kw").onchange = (e) => ((s.kw = e.target.value), rr()); $("dan-sort").onchange = (e) => ((s.sort = e.target.value), rr()); $("dan-boxa").onclick = () => boxa(ctx, api); $("dan-edthal").onclick = () => edtHal(ctx, api); $("dan-use").onclick = () => findUse(ctx, api); const grid = $("dan-grid"); if (s.scroll) grid.scrollTop = s.scroll; grid.onscroll = () => (s.scroll = grid.scrollTop); document .querySelectorAll("#dan-form .dan-pick") .forEach((td) => (td.onclick = () => ((s.code = td.getAttribute("data-code")), rr()))); document.querySelectorAll("#dan-form .dan-price").forEach( (inp) => (inp.onchange = () => { const c = inp.getAttribute("data-code"); const r = ctx.dbfData.costn_rows.find((x) => U.codeOf(x) === c); const v = U.num(inp.value); U.writeBase(r, v); r.PG_1 = "0"; syncRes(ctx, c, v, "manual"); ctx.uiState.danMsg = `${c} 적용단가 ${v} 직접 수정`; api.cascadeAndRender(); }), ); document.querySelectorAll("#dan-form .dan-adopt").forEach( (td) => (td.onclick = () => { const c = td.getAttribute("data-code"); const r = ctx.dbfData.costn_rows.find((x) => U.codeOf(x) === c); const ch = U.adopt(r, td.getAttribute("data-slot"), { skipZero: true }); if (!ch) return; syncRes(ctx, c, ch.to, `slot${ch.slot}`); ctx.uiState.danMsg = `${c} ${ch.slot} 단가 채택`; api.cascadeAndRender(); }), ); document .querySelectorAll("#dan-form .dan-ilwi") .forEach( (b) => (b.onclick = () => ( (ctx.uiState.selectedIlwiCode = b.getAttribute("data-code")), (ctx.uiState.activeScreen = "wM_Edit_iLWi"), rr() )), ); } P.screens.wM_JabPum = { render, bind }; })(window);