// 원본 「엑셀물량 파일목록」(TfrmExcelMullang — spec_pa §7 · spec_small §8.3): 공사에 딸린 엑셀 물량 파일 목록(Index·FileName). // 원본은 파일을 공사 폴더에 두고, 웹은 작업(project.excelFiles)에 파일 내용을 담는다. 추가(btnNewProject) = 파일을 골라 목록에 // 넣음(원본은 엑셀에 띄우기만 하고 셀 연결 때 등록 — 웹은 엑셀이 없어 여기서 등록) · 같은 이름은 거부. 삭제(btnDelete) = 목록과 // 담은 파일을 지움(원본도 공사 폴더의 파일을 지움) — 그 파일 셀 연결은 남아 다음 갱신 때 못 찾음으로 드러남. 열기 = 내려받기. // 셀 수량 연결 창은 목록의 파일을 골라 쓸 수 있고, 새 파일로 연결하면 목록에 들어간다(0xc7328c). const EstExcelFiles = (() => { const list = (project) => project.excelFiles || []; function add(project, name, data) { const files = (project.excelFiles ||= []); if (files.some((f) => f.FileName === name)) throw Error("같은 이름의 파일이 내역서에 포함되어 있습니다."); const entry = { Index: files.reduce((m, f) => Math.max(m, Number(f.Index) || 0), 0) + 1, FileName: name, data, }; files.push(entry); return entry; } function remove(project, name) { const files = list(project), at = files.findIndex((f) => f.FileName === name); if (at < 0) throw Error("삭제할 엑셀파일을 선택하지 않았습니다."); files.splice(at, 1); if (!files.length) delete project.excelFiles; } const toBase64 = (buffer) => { const bytes = new Uint8Array(buffer); let out = ""; for (let i = 0; i < bytes.length; i += 0x8000) out += String.fromCharCode(...bytes.subarray(i, i + 0x8000)); return btoa(out); }; const toBuffer = (data) => Uint8Array.from(atob(data), (c) => c.charCodeAt(0)).buffer; let picked = ""; function dialog(state) { const { esc } = EstApp, files = list(state.project), links = state.project.excelQuantityLinks || []; EstApp.showDialog( "엑셀물량 파일목록", `
| 파 일 명 | 셀 연결 | |
|---|---|---|
| ${esc(f.FileName)} | ${links.filter((l) => l.file === f.FileName).length} | |
| 등록된 엑셀 파일이 없습니다. | ||