// 원본 갑지(TFRMGABGI)·표지(TFRMCOVER) 팝업 — 양식저장하기·양식불러오기·양식목록(popupSaveFormat·popupLoadFormat·popupFormatTableS), // 기본양식으로 저장(popupSaveToDefault: 새 공사에서 갑지·표지를 처음 열 때 채움), 갑지·표지 초기화(popupInit), 인쇄(popupPrint). // 양식은 서버 양식 보관함 종류 document 에 { docKind, fields } 로 둔다(공사명은 양식에 넣지 않음 — 늘 현재 공사 이름). const EstDocForms = (() => { const DEFAULT = { gabgi: "기본양식-갑지", cover: "기본양식-표지" }; const FIELDS = { gabgi: ["Position", "CompanyName", "Date", "CompanyPos", "Explan", "Cost", "Gulga"], cover: ["Name2", "Date", "CompanyName", "CompanyPos"], }; const post = (body) => ({ method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); const field = (name) => document.querySelector(`#dialog-content [name="doc-${name}"]`); function read(kind) { return Object.fromEntries( FIELDS[kind] .filter((k) => field(k)) .map((k) => { const v = field(k).value; return [ k, k === "Gulga" ? v .split(/\r?\n/) .map((l) => l.trim()) .filter(Boolean) : k === "CompanyPos" ? Number(v) : v, ]; }), ); } function write(kind, fields) { for (const k of FIELDS[kind]) { const node = field(k); if (!node || fields[k] === undefined) continue; node.value = Array.isArray(fields[k]) ? fields[k].join("\n") : fields[k]; } } async function list(kind) { return (await EstApp.api("/api/forms")).filter( (f) => f.kind === "document" && f.data?.docKind === kind, ); } function panel(html) { let box = document.getElementById("doc-forms-panel"); if (!box) { box = document.createElement("div"); box.id = "doc-forms-panel"; box.className = "business-tools"; document.querySelector("#dialog-content .form-fields")?.before(box); } box.innerHTML = html; } function tools(kind) { return `
${[ ["docf-list", "양식목록"], ["docf-save", "양식저장하기"], ["docf-default", "기본양식으로 저장"], ["docf-init", kind === "gabgi" ? "갑지초기화" : "표지초기화"], ["docf-print", "인쇄"], ["docf-detail", "상세편집"], ] .map(([a, l]) => ``) .join("")}
`; } // 처음 여는 갑지·표지에 기본양식을 채움(저장은 사용자가 [저장]) async function fill(state, kind) { if (state.project.docs?.[kind]) return; const f = (await list(kind)).find((x) => x.name === DEFAULT[kind]); if (f) write(kind, f.data.fields); } async function run(name, state, node) { const kind = node.dataset.kind, esc = EstApp.esc; if (name === "docf-list") { const forms = await list(kind); panel( forms.length ? `양식목록 ${forms.map((f) => ``).join(" ")}` : "저장한 양식이 없습니다.", ); } else if (name === "docf-load") { const f = (await list(kind)).find((x) => x.name === node.dataset.name); if (!f) throw Error("양식이 없습니다."); write(kind, f.data.fields); panel(`「${esc(f.name)}」 양식을 불러왔습니다. [저장]을 누르면 반영됩니다.`); } else if (name === "docf-delete") { if (!confirm(`「${node.dataset.name}」 양식을 지우시겠습니까?`)) return; await EstApp.api("/api/forms/delete", post({ kind: "document", name: node.dataset.name })); return run("docf-list", state, node); } else if (name === "docf-save" || name === "docf-default") { const fname = name === "docf-default" ? DEFAULT[kind] : prompt("양식 이름", "")?.trim(); if (!fname) return; await EstApp.api( "/api/forms", post({ kind: "document", name: fname, data: { docKind: kind, fields: read(kind) } }), ); panel(`「${esc(fname)}」 양식으로 저장했습니다.`); } else if (name === "docf-init") { if (!confirm(`${kind === "gabgi" ? "갑지" : "표지"}를 처음 상태로 되돌리시겠습니까?`)) return; EstApp.byId("dialog").close(); EstApp.change((project) => { if (project.docs) delete project.docs[kind]; }, false); EstDocs.handle("doc-edit", state, { dataset: { kind } }); } else if (name === "docf-detail") { // 상세편집: 인쇄 모양을 자유 편집(원본은 미리보기 ↔ 편집 전환). 저장하면 인쇄가 이 모양을 씀, 「상세편집 해제」로 칸 값 모양으로 const doc = state.project.docs?.[kind] || {}; const html = doc.detailHtml || EstDocs.html(kind === "gabgi" ? 8 : 9, state.project); EstApp.showDialog( `${kind === "gabgi" ? "갑지" : "표지"} 상세편집`, `
${EstDocEditor.clean(html)}
`, ); } else if (name === "docf-detail-save" || name === "docf-detail-clear") { const html = name === "docf-detail-save" ? EstDocEditor.clean(document.getElementById("doc-detail").innerHTML) : null; EstApp.byId("dialog").close(); EstApp.change((project) => { project.docs ||= {}; project.docs[kind] = { ...(project.docs[kind] || {}) }; if (html) project.docs[kind].detailHtml = html; else delete project.docs[kind].detailHtml; }, false); state.notice = html ? "상세편집 모양을 저장했습니다. 인쇄에 그대로 쓰입니다." : "상세편집을 풀었습니다."; } else if (name === "docf-print") { EstApp.byId("dialog").close(); await EstReport.open(); const select = document.getElementById("print-form"); select.value = kind === "gabgi" ? "8" : "9"; select.dispatchEvent(new Event("change", { bubbles: true })); } } const names = new Set([ "docf-detail", "docf-detail-save", "docf-detail-clear", "docf-list", "docf-load", "docf-delete", "docf-save", "docf-default", "docf-init", "docf-print", ]); function handle(name, state, node) { if (!names.has(name)) return false; run(name, state, node).catch((error) => panel(EstApp.esc(error.message))); return true; } // 설계일자 선택(TfrmMonthDate 0xda6438): 갑지 「{년}년 {월}월 일 설계」(일은 빈칸) · 견적서 「{년}년 {월}월 {일}일」 function dateText(value, format) { const [y, m, d] = String(value).split("-").map(Number); if (!y || !m) return ""; return format === "estimate" ? `${y}년 ${m}월 ${d}일` : `${y}년 ${m}월 일 설계`; } if (typeof document !== "undefined" && document.addEventListener) document.addEventListener("change", (event) => { const t = event.target; if (t.dataset?.dateTarget === undefined || !t.value) return; const target = document.querySelector(`#dialog-content [name="${t.dataset.dateTarget}"]`); if (!target) return; target.value = dateText(t.value, t.dataset.dateFormat); target.dispatchEvent(new Event("input", { bubbles: true })); target.dispatchEvent(new Event("change", { bubbles: true })); }); return { tools, fill, dateText, handle }; })();