- STMATE_PLUGINS(screens · actions · menus) · STMATE_APP(ctx 와 화면 도우미) — app.js 가 등록된 화면을 그리고 메뉴 단추를 붙임 - /plugins_manifest.js 가 scr_*.js 를 불러옴 · server.py 가 api_*.py 의 router 를 연결 - 도구 창 바인딩을 app_modals.js 로 분리(app.js 718 → 613줄) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
160 lines
5.4 KiB
JavaScript
160 lines
5.4 KiB
JavaScript
/**
|
|
* STMATE 도구 창(wITNum · wBoqRate · wM_Rate · wExpnd · wQtyList · wM_Boxa · wM_Edt_Hal) 바인딩 (app_modals.js)
|
|
* app.js 에서 떼어 냄 — api = window.STMATE_APP
|
|
*/
|
|
(function (global) {
|
|
"use strict";
|
|
|
|
const ViewPrjBoq = () => global.STMATE_VIEW_PRJ_BOQ;
|
|
|
|
function bindModalEvents(api) {
|
|
const { ctx, Calc, num, $, onClick, bindEach, closeModal, renderWorkspace, cascadeAndRender } =
|
|
api;
|
|
const insertBoqRow = (...a) => api.insertBoqRow(...a);
|
|
onClick("modal-apply-itnum", () => {
|
|
if (!ctx.dbfData || !ctx.dbfData.boq_rows) return;
|
|
let t4 = 0,
|
|
t2 = 0,
|
|
lf = 0;
|
|
const fmtVal = $("itnum-leaf-fmt").value;
|
|
ctx.dbfData.boq_rows.forEach((r) => {
|
|
const bd = String(r.BDCODE1 || "").trim();
|
|
if (bd === "T4") ((t4 += 1), (t2 = 0), (r.ITNUM = `${t4}.`));
|
|
else if (bd === "T2") ((t2 += 1), (lf = 0), (r.ITNUM = `${t4}.${t2}`));
|
|
else if (bd && !/^(T\d|E\d|C\d|:)$/.test(bd)) {
|
|
lf += 1;
|
|
r.ITNUM = fmtVal === "01" ? String(lf).padStart(2, "0") : fmtVal === "-1" ? `-${lf}` : "";
|
|
}
|
|
});
|
|
closeModal();
|
|
renderWorkspace();
|
|
});
|
|
onClick("modal-apply-boqrate", () => {
|
|
const [rm, rl, rs] = ["m", "l", "s"].map((k) => num($(`boqrate-${k}`).value, 100) / 100);
|
|
ctx.state.resources.forEach((r) => {
|
|
const mult = r.kind === "재료비" ? rm : r.kind === "노무비" ? rl : rs;
|
|
r.manualPrice = Math.floor(num(r.manualPrice) * mult);
|
|
});
|
|
closeModal();
|
|
renderWorkspace();
|
|
});
|
|
onClick("modal-apply-mrate", () => {
|
|
ctx.state.sysConfig.ecdDigits = parseInt($("mrate-digits").value, 10) || 0;
|
|
closeModal();
|
|
renderWorkspace();
|
|
});
|
|
onClick("modal-apply-expnd", () => {
|
|
const code = ($("expnd-code") || {}).value;
|
|
const ilwi =
|
|
(ctx.state.ilwiItems || []).find((x) => x.code === code) || ctx.state.ilwiItems[0];
|
|
((ilwi && ilwi.lines) || []).forEach((ln) => {
|
|
const r = ctx.state.resources.find((x) => x.id === ln.refId || x.code === ln.refId);
|
|
insertBoqRow(
|
|
r ? r.code : ln.refId,
|
|
`[전개] ${r ? r.name : ln.refId}`,
|
|
r ? r.spec : "",
|
|
r ? r.unit : "식",
|
|
ln.qty || 1,
|
|
);
|
|
});
|
|
closeModal();
|
|
renderWorkspace();
|
|
});
|
|
bindEach(".btn-apply-qty-expr", "onclick", (btn) => {
|
|
const id = btn.getAttribute("data-id");
|
|
const inp = document.querySelector(`.qty-expr-input[data-id="${id}"]`);
|
|
const val = inp ? Calc.evalFormula(inp.value, {}) : 0;
|
|
const item = ctx.state.boqItems.find((b) => b.id === id);
|
|
if (item && val > 0) {
|
|
item.qty = Math.round(val * 100) / 100;
|
|
const drow =
|
|
ctx.dbfData &&
|
|
ctx.dbfData.boq_rows &&
|
|
ctx.dbfData.boq_rows.find((x) => x._recno === item._recno);
|
|
if (drow) drow.QTY1 = String(item.qty);
|
|
renderWorkspace();
|
|
}
|
|
});
|
|
onClick("modal-apply-boxa", () => {
|
|
const mode = $("boxa-adopt-mode").value;
|
|
(ctx.dbfData ? ctx.dbfData.costn_rows : []).forEach((r) => {
|
|
const code = String(r.CODE || "").trim();
|
|
if (!code.startsWith("M")) return;
|
|
const nonZero = [
|
|
num(r.AMT_11),
|
|
num(r.AMT_21),
|
|
num(r.AMT_31),
|
|
num(r.AMT_41),
|
|
num(r.AMT_51),
|
|
].filter((x) => x > 0);
|
|
if (nonZero.length) {
|
|
const picked =
|
|
mode === "min" ? Math.min(...nonZero) : nonZero[parseInt(mode, 10)] || nonZero[0];
|
|
ViewPrjBoq().syncCostnUnitPrice(ctx, code, picked, 0, 0);
|
|
}
|
|
});
|
|
closeModal();
|
|
cascadeAndRender();
|
|
});
|
|
onClick("modal-apply-edthal", () => {
|
|
const kind = $("edthal-kind").value,
|
|
pct = num($("edthal-pct").value, 100) / 100,
|
|
rmode = $("edthal-round").value;
|
|
(ctx.dbfData ? ctx.dbfData.costn_rows : []).forEach((r) => {
|
|
const code = String(r.CODE || "").trim();
|
|
if (!code || r.UC === "T" || (kind !== "ALL" && code[0].toUpperCase() !== kind)) return;
|
|
const fn = (v) => (rmode === "round" ? Math.round(v * pct) : Math.floor(v * pct));
|
|
ViewPrjBoq().syncCostnUnitPrice(
|
|
ctx,
|
|
code,
|
|
fn(num(r.MAMT1)),
|
|
fn(num(r.LAMT1)),
|
|
fn(num(r.SAMT1)),
|
|
);
|
|
});
|
|
closeModal();
|
|
cascadeAndRender();
|
|
});
|
|
bindEach(".btn-use-special-san", "onclick", (btn) => {
|
|
const spec = (ctx.catalogData.special_san || [])[parseInt(btn.getAttribute("data-idx"), 10)];
|
|
if (!spec) return;
|
|
ctx.uiState.editedSmtMap[ctx.uiState.selectedIlwiCode || "D00016"] = (
|
|
spec["산식행"] || []
|
|
).join("\r\n");
|
|
ctx.uiState.activeScreen = "wM_Edit_iLWi";
|
|
closeModal();
|
|
renderWorkspace();
|
|
});
|
|
}
|
|
|
|
function insertBoqRow(api, code, name, spec, unit, qty) {
|
|
const { ctx, renderWorkspace } = api;
|
|
const recno = Date.now() % 100000;
|
|
ctx.state.boqItems.push({
|
|
id: "BOQ_" + recno,
|
|
code,
|
|
name,
|
|
refId: code,
|
|
rowType: "normal",
|
|
qty,
|
|
changedQty: qty,
|
|
_recno: recno,
|
|
});
|
|
if (ctx.dbfData && ctx.dbfData.boq_rows) {
|
|
ctx.dbfData.boq_rows.splice(4, 0, {
|
|
_recno: recno,
|
|
ITNUM: "",
|
|
BDCODE1: code,
|
|
NAME1: name,
|
|
SIZE1: spec,
|
|
UNIT1: unit,
|
|
QTY1: String(qty),
|
|
ENDCODE: "0.0000",
|
|
});
|
|
}
|
|
renderWorkspace();
|
|
}
|
|
|
|
global.STMATE_APP_MODALS = { bindModalEvents, insertBoqRow };
|
|
})(window);
|