179 lines
7.9 KiB
JavaScript
179 lines
7.9 KiB
JavaScript
// 원본 갑지(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 `<div class="business-tools">${[
|
||
["docf-list", "양식목록"],
|
||
["docf-save", "양식저장하기"],
|
||
["docf-default", "기본양식으로 저장"],
|
||
["docf-init", kind === "gabgi" ? "갑지초기화" : "표지초기화"],
|
||
["docf-print", "인쇄"],
|
||
["docf-detail", "상세편집"],
|
||
]
|
||
.map(([a, l]) => `<button data-action="${a}" data-kind="${kind}">${l}</button>`)
|
||
.join("")}</div>`;
|
||
}
|
||
// 처음 여는 갑지·표지에 기본양식을 채움(저장은 사용자가 [저장])
|
||
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) => `<button data-action="docf-load" data-kind="${kind}" data-name="${esc(f.name)}">${esc(f.name)}</button><button data-action="docf-delete" data-kind="${kind}" data-name="${esc(f.name)}" title="지우기">×</button>`).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" ? "갑지" : "표지"} 상세편집`,
|
||
`<div id="doc-detail" contenteditable="true" style="min-height:360px;max-height:480px;overflow:auto;border:1px solid #bbb;padding:8px;background:#fff">${EstDocEditor.clean(html)}</div><button data-action="docf-detail-save" data-kind="${kind}">저장</button> <button data-action="docf-detail-clear" data-kind="${kind}">상세편집 해제</button>`,
|
||
);
|
||
} 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 };
|
||
})();
|