// 원본 엑셀형 수량산출서(TFRMMULEXCEL) 웹 편집 화면 — 셀 고르기·수식줄 편집·다시 계산, 셀 합(우·상·좌·하 btnSum*), // 수량으로 지정(popSetMullang)·지정 해제(popSetFree) = 셀 ↔ 수량 항목 연결(sheet.excelLinks). 항목 수량 = 연결 셀 값(산출서 자리수). // 원본 파일 속 셀↔항목 대응은 찾지 못해, 가져올 때 값이 같은 셀 하나(합계 수식·아래쪽 우선)를 「추정」 연결로 둔다. // 편집한 엑셀형 산출서는 .xls 로 다시 쓰지 못하므로 ESTX 저장을 막는다(sheet.excelEdited). const EstExcelView = (() => { const L = (n) => EstExcelSheet.letters(n); function render(sheet, state) { if (!sheet?.excel?.length) return ""; const { esc, number } = EstApp, sel = state.excelCell?.sheet === sheet.Code ? state.excelCell : null, links = sheet.excelLinks || {}; const linked = new Map( Object.entries(links).map(([code, l]) => [`${l.n},${l.row},${l.col}`, { code, ...l }]), ); return sheet.excel .map(({ name, cells }, n) => { const keys = Object.keys(cells).map((k) => k.split(",").map(Number)); const rows = Math.max(20, ...keys.map(([r]) => r + 2)), cols = Math.min(40, Math.max(8, ...keys.map(([, c]) => c + 2))); const raw = sel && sel.n === n ? cells[`${sel.row},${sel.col}`] : null; const bar = sel && sel.n === n ? `${L(sel.col)}${sel.row + 1} ` : "셀을 누르면 수식줄에서 고칩니다."; const items = (sheet.items || []) .map( (i) => ``, ) .join(""); const tools = sel && sel.n === n ? ` ` : ""; const body = Array.from({ length: rows }, (_, r) => { const tds = Array.from({ length: cols }, (_, c) => { const cell = cells[`${r},${c}`], link = linked.get(`${n},${r},${c}`), chosen = sel && sel.n === n && sel.row === r && sel.col === c; const value = cell == null ? "" : typeof cell.value === "number" ? number(cell.value) : esc(cell.value); const style = [ cell?.formula ? "font-weight:bold" : "", link ? "background:#e6f4ea" : "", chosen ? "outline:2px solid #316ea5" : "", ] .filter(Boolean) .join(";"); const title = [ typeof cell?.formula === "string" ? `=${cell.formula}` : "", link ? `수량: ${link.code}${link.inferred ? " (추정 연결)" : ""}` : "", ] .filter(Boolean) .join(" · "); return `${value}`; }).join(""); return `${r + 1}${tds}`; }).join(""); return `

엑셀형 산출서 · ${esc(name)}

${bar}${tools}
${Array.from({ length: cols }, (_, c) => ``).join("")}${body}
${L(c)}
`; }) .join(""); } function sheetOf(state) { return state.project.quantitySheets?.find((s) => s.Code === state.quantitySheet); } function setCell(sheet, n, row, col, text) { const cells = sheet.excel[n].cells, k = `${row},${col}`, t = String(text ?? ""); if (t === "") delete cells[k]; else if (t.startsWith("=")) cells[k] = { value: 0, formula: t.slice(1) }; else { const v = Number(t.replaceAll(",", "")); cells[k] = { value: t.trim() !== "" && Number.isFinite(v) ? v : t }; } sheet.excelEdited = true; return EstExcelSheet.recalc(cells); } function install() { document.addEventListener("click", (event) => { const td = event.target.closest("[data-excel-pick]"); if (!td) return; const [n, row, col] = td.dataset.excelPick.split(",").map(Number); EstApp.state.excelCell = { sheet: EstApp.state.quantitySheet, n, row, col }; EstApp.render(); }); document.addEventListener("change", (event) => { if (event.target.dataset.excelBar === undefined) return; const state = EstApp.state, sel = state.excelCell, value = event.target.value; let errors = []; EstApp.change(() => { errors = setCell(sheetOf(state), sel.n, sel.row, sel.col, value); }, false); if (errors.length) state.notice = errors.slice(0, 3).join(" / "); }); } function handle(name, state, node) { if (!["excel-sum", "excel-link", "excel-unlink"].includes(name)) return false; const sheet = sheetOf(state), sel = state.excelCell; if (!sheet?.excel || !sel) throw Error("엑셀형 산출서에서 셀을 고르세요."); if (name === "excel-sum") { const formula = EstExcelSheet.sumFormula( sheet.excel[sel.n].cells, sel.row, sel.col, node.dataset.dir, ); EstApp.change(() => setCell(sheet, sel.n, sel.row, sel.col, `=${formula}`), false); } else { const code = document.querySelector("[data-excel-item]")?.value; EstApp.change(() => { sheet.excelLinks ||= {}; for (const [k, l] of Object.entries(sheet.excelLinks)) if (l.n === sel.n && l.row === sel.row && l.col === sel.col) delete sheet.excelLinks[k]; if (name === "excel-link") { if (!code) throw Error("수량 항목을 고르세요."); sheet.excelLinks[code] = { n: sel.n, row: sel.row, col: sel.col }; } }, false); } return true; } if (typeof document !== "undefined" && document.addEventListener) install(); return { render, setCell, handle }; })();