420 lines
26 KiB
PHP
420 lines
26 KiB
PHP
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<h1 class="h3 mb-0 text-gray-800">PDF Template Designer</h1>
|
|
<a href="<?= BASE_URL ?>/settings" class="btn btn-outline-secondary shadow-sm"><i class="fa-solid fa-arrow-left me-1"></i> กลับ</a>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<!-- Tools & Fields Panel -->
|
|
<div class="col-lg-3">
|
|
<div class="card shadow-sm rounded-4 border-0 mb-4 overflow-hidden">
|
|
<div class="card-header bg-danger text-white py-3">
|
|
<h6 class="m-0 font-weight-bold"><i class="fa-solid fa-toolbox me-2"></i>เครื่องมือสร้างฟิลด์</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<p class="small text-muted mb-3">ลากฟิลด์ที่ต้องการไปวางบนแบบฟอร์ม PDF</p>
|
|
|
|
<div class="d-grid gap-2 mb-4" style="max-height: 400px; overflow-y: auto; padding-right: 5px;">
|
|
<!-- ข้อมูลบุคคล -->
|
|
<button class="btn btn-outline-primary btn-sm draggable-field text-start" draggable="true" data-type="Text" data-field="{fullname}">
|
|
<i class="fa-solid fa-user me-2"></i> ชื่อ-นามสกุล <code>{fullname}</code>
|
|
</button>
|
|
<button class="btn btn-outline-primary btn-sm draggable-field text-start" draggable="true" data-type="Text" data-field="{position}">
|
|
<i class="fa-solid fa-briefcase me-2"></i> ตำแหน่ง <code>{position}</code>
|
|
</button>
|
|
<button class="btn btn-outline-primary btn-sm draggable-field text-start" draggable="true" data-type="Text" data-field="{department}">
|
|
<i class="fa-solid fa-sitemap me-2"></i> หน่วยงาน <code>{department}</code>
|
|
</button>
|
|
<button class="btn btn-outline-primary btn-sm draggable-field text-start" draggable="true" data-type="Text" data-field="{personnel_type}">
|
|
<i class="fa-solid fa-id-badge me-2"></i> ประเภทบุคลากร <code>{personnel_type}</code>
|
|
</button>
|
|
|
|
<!-- ข้อมูลหนังสือและวันที่ -->
|
|
<button class="btn btn-outline-info btn-sm draggable-field text-start mt-2" draggable="true" data-type="Text" data-field="{doc_number}">
|
|
<i class="fa-solid fa-hashtag me-2"></i> เลขอ้างอิงหนังสือ <code>{doc_number}</code>
|
|
</button>
|
|
<button class="btn btn-outline-info btn-sm draggable-field text-start mt-1" draggable="true" data-type="Text" data-field="{doc_no}">
|
|
<i class="fa-solid fa-hashtag me-2"></i> เลขที่หนังสือ <code>{doc_no}</code>
|
|
</button>
|
|
<button class="btn btn-outline-info btn-sm draggable-field text-start mt-1" draggable="true" data-type="Text" data-field="{trip_running_number}">
|
|
<i class="fa-solid fa-list-ol me-2"></i> เลขที่หนังสือเดินทาง <code>{trip_running_number}</code>
|
|
</button>
|
|
<button class="btn btn-outline-info btn-sm draggable-field text-start" draggable="true" data-type="Text" data-field="{doc_date}">
|
|
<i class="fa-solid fa-calendar-day me-2"></i> วันที่หนังสือ <code>{doc_date}</code>
|
|
</button>
|
|
<button class="btn btn-outline-info btn-sm draggable-field text-start mt-1" draggable="true" data-type="Text" data-field="{title}">
|
|
<i class="fa-solid fa-heading me-2"></i> เรื่อง <code>{title}</code>
|
|
</button>
|
|
<button class="btn btn-outline-info btn-sm draggable-field text-start" draggable="true" data-type="Text" data-field="{meeting_date}">
|
|
<i class="fa-solid fa-calendar-week me-2"></i> วันที่ประชุม/เดินทาง <code>{meeting_date}</code>
|
|
</button>
|
|
<button class="btn btn-outline-info btn-sm draggable-field text-start" draggable="true" data-type="Text" data-field="{current_date}">
|
|
<i class="fa-regular fa-clock me-2"></i> วันที่ปัจจุบัน (พิมพ์) <code>{current_date}</code>
|
|
</button>
|
|
|
|
<!-- ข้อมูลสถานที่/ผู้จัด -->
|
|
<button class="btn btn-outline-secondary btn-sm draggable-field text-start mt-2" draggable="true" data-type="Text" data-field="{location}">
|
|
<i class="fa-solid fa-location-dot me-2"></i> สถานที่ <code>{location}</code>
|
|
</button>
|
|
<button class="btn btn-outline-secondary btn-sm draggable-field text-start" draggable="true" data-type="Text" data-field="{organizer}">
|
|
<i class="fa-solid fa-building me-2"></i> ผู้จัด <code>{organizer}</code>
|
|
</button>
|
|
|
|
<!-- ข้อมูลวันเดินทาง (แยกย่อย) -->
|
|
<button class="btn btn-outline-warning btn-sm draggable-field text-start mt-2" draggable="true" data-type="Text" data-field="{depart_datetime}">
|
|
<i class="fa-solid fa-plane-departure me-2"></i> (รวม) วันเวลาออกเดินทาง <code>{depart_datetime}</code>
|
|
</button>
|
|
<button class="btn btn-outline-warning btn-sm draggable-field text-start" draggable="true" data-type="Text" data-field="{arrive_datetime}">
|
|
<i class="fa-solid fa-plane-arrival me-2"></i> (รวม) วันเวลากลับถึง <code>{arrive_datetime}</code>
|
|
</button>
|
|
<button class="btn btn-outline-warning btn-sm draggable-field text-start mt-1" draggable="true" data-type="Text" data-field="{depart_date}">
|
|
<i class="fa-regular fa-calendar-check me-2"></i> วันที่ออกเดินทาง <code>{depart_date}</code>
|
|
</button>
|
|
<button class="btn btn-outline-warning btn-sm draggable-field text-start" draggable="true" data-type="Text" data-field="{depart_time}">
|
|
<i class="fa-regular fa-clock me-2"></i> เวลาออกเดินทาง <code>{depart_time}</code>
|
|
</button>
|
|
<button class="btn btn-outline-warning btn-sm draggable-field text-start" draggable="true" data-type="Text" data-field="{arrive_date}">
|
|
<i class="fa-regular fa-calendar-check me-2"></i> วันที่กลับถึง <code>{arrive_date}</code>
|
|
</button>
|
|
<button class="btn btn-outline-warning btn-sm draggable-field text-start" draggable="true" data-type="Text" data-field="{arrive_time}">
|
|
<i class="fa-regular fa-clock me-2"></i> เวลากลับถึง <code>{arrive_time}</code>
|
|
</button>
|
|
<button class="btn btn-outline-warning btn-sm draggable-field text-start mt-1" draggable="true" data-type="Text" data-field="{total_days}">
|
|
<i class="fa-solid fa-stopwatch me-2"></i> รวมจำนวนวัน <code>{total_days}</code>
|
|
</button>
|
|
|
|
<button class="btn btn-outline-success btn-sm draggable-field text-start mt-2" draggable="true" data-type="Text" data-field="{vehicle_type}">
|
|
<i class="fa-solid fa-car me-2"></i> ประเภทยานพาหนะ <code>{vehicle_type}</code>
|
|
</button>
|
|
<button class="btn btn-outline-success btn-sm draggable-field text-start" draggable="true" data-type="Text" data-field="{vehicle_plate}">
|
|
<i class="fa-solid fa-id-card me-2"></i> ทะเบียนรถ (หากมี) <code>{vehicle_plate}</code>
|
|
</button>
|
|
|
|
<!-- งบประมาณ -->
|
|
<button class="btn btn-outline-success btn-sm draggable-field text-start mt-2" draggable="true" data-type="Text" data-field="{budget_source}">
|
|
<i class="fa-solid fa-sack-dollar me-2"></i> เบิกค่าใช้จ่ายจาก <code>{budget_source}</code>
|
|
</button>
|
|
<button class="btn btn-outline-success btn-sm draggable-field text-start" draggable="true" data-type="Text" data-field="{organizer_support_amount}">
|
|
<i class="fa-solid fa-hand-holding-dollar me-2"></i> จำนวนเงินสนับสนุน <code>{organizer_support_amount}</code>
|
|
</button>
|
|
<button class="btn btn-outline-success btn-sm draggable-field text-start mt-1" draggable="true" data-type="Text" data-field="{budget}">
|
|
<i class="fa-solid fa-money-bill me-2"></i> จำนวนเงินรวม <code>{budget}</code>
|
|
</button>
|
|
<button class="btn btn-outline-success btn-sm draggable-field text-start mt-1" draggable="true" data-type="Text" data-field="{expense_accommodations_text}">
|
|
<i class="fa-solid fa-bed me-2"></i> รายละเอียดที่พัก <code>{expense_accommodations_text}</code>
|
|
</button>
|
|
<button class="btn btn-outline-success btn-sm draggable-field text-start" draggable="true" data-type="Text" data-field="{expense_allowances_text}">
|
|
<i class="fa-solid fa-utensils me-2"></i> รายละเอียดเบี้ยเลี้ยง <code>{expense_allowances_text}</code>
|
|
</button>
|
|
<button class="btn btn-outline-success btn-sm draggable-field text-start mt-1" draggable="true" data-type="Text" data-field="{expense_transport}">
|
|
<i class="fa-solid fa-ticket me-2"></i> ค่าโดยสารทั้งหมด <code>{expense_transport}</code>
|
|
</button>
|
|
<button class="btn btn-outline-success btn-sm draggable-field text-start" draggable="true" data-type="Text" data-field="{expense_registration}">
|
|
<i class="fa-solid fa-address-card me-2"></i> ค่าลงทะเบียน <code>{expense_registration}</code>
|
|
</button>
|
|
|
|
<!-- ลายเซ็น -->
|
|
<button class="btn btn-outline-dark btn-sm draggable-field text-start mt-2" draggable="true" data-type="Signature" data-field="{signature_1}">
|
|
<i class="fa-solid fa-signature me-2"></i> ลายเซ็นผู้อนุมัติ <code>{signature_1}</code>
|
|
</button>
|
|
<button class="btn btn-outline-dark btn-sm draggable-field text-start" draggable="true" data-type="QR" data-field="{qr_code}">
|
|
<i class="fa-solid fa-qrcode me-2"></i> QR Code อ้างอิง
|
|
</button>
|
|
</div>
|
|
|
|
<hr>
|
|
|
|
<!-- Property Editor Card (Hidden by default) -->
|
|
<div id="propertyEditor" class="card shadow-sm border-info mb-4 d-none">
|
|
<div class="card-header bg-info text-white py-2">
|
|
<h6 class="m-0 font-weight-bold small"><i class="fa-solid fa-palette me-2"></i>ปรับแต่งข้อความที่เลือก</h6>
|
|
</div>
|
|
<div class="card-body py-2 px-3">
|
|
<div class="mb-2">
|
|
<label class="form-label small fw-bold text-muted mb-1">ขนาดตัวอักษร</label>
|
|
<div class="input-group input-group-sm">
|
|
<input type="number" id="fieldSize" class="form-control" value="13" min="8" max="72">
|
|
<span class="input-group-text">pt</span>
|
|
</div>
|
|
</div>
|
|
<div class="mb-2">
|
|
<label class="form-label small fw-bold text-muted mb-1">สีตัวอักษร</label>
|
|
<input type="color" id="fieldColor" class="form-control form-control-color w-100" value="#000000" style="height: 38px;">
|
|
</div>
|
|
<small class="text-danger d-block mt-2"><i class="fa-solid fa-circle-info me-1"></i>กดปุ่ม Delete บนคีย์บอร์ดเพื่อลบ</small>
|
|
</div>
|
|
</div>
|
|
|
|
<form action="<?= BASE_URL ?>/settings/pdf-designer/upload" method="POST" enctype="multipart/form-data">
|
|
<input type="hidden" name="csrf_token" value="<?= $csrf_token ?>">
|
|
<div class="mb-3">
|
|
<label class="form-label fw-bold">อัปโหลดแบบฟอร์ม PDF ใหม่</label>
|
|
<input class="form-control form-control-sm" type="file" name="pdf_file" accept=".pdf" required>
|
|
</div>
|
|
<button type="submit" class="btn btn-sm btn-danger w-100"><i class="fa-solid fa-upload me-1"></i> อัปโหลด</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<button id="saveLayoutBtn" class="btn btn-success w-100 shadow-sm rounded-4 py-2"><i class="fa-solid fa-floppy-disk me-1"></i> บันทึกตำแหน่งฟิลด์</button>
|
|
</div>
|
|
|
|
<!-- Canvas Editor Area -->
|
|
<div class="col-lg-9">
|
|
<div class="card shadow-sm rounded-4 border-0 mb-4 overflow-hidden">
|
|
<div class="card-header bg-white py-3 d-flex justify-content-between align-items-center">
|
|
<div class="d-flex align-items-center">
|
|
<h6 class="m-0 font-weight-bold text-danger"><i class="fa-solid fa-object-group me-2"></i>พื้นที่ออกแบบ</h6>
|
|
</div>
|
|
<div>
|
|
<?php if($template): ?>
|
|
<a href="<?= BASE_URL . $template['file_path'] ?>" target="_blank" class="btn btn-sm btn-outline-info me-2">
|
|
<i class="fa-solid fa-file-pdf"></i> ต้นฉบับ
|
|
</a>
|
|
<a href="<?= BASE_URL ?>/settings/pdf-designer/preview" target="_blank" class="btn btn-sm btn-success me-2">
|
|
<i class="fa-solid fa-eye"></i> ดูตัวอย่าง (Preview)
|
|
</a>
|
|
<?php endif; ?>
|
|
<span class="badge bg-secondary me-2">แบบฟอร์ม: <?= $template ? htmlspecialchars($template['name']) : 'ยังไม่ได้อัปโหลด' ?></span>
|
|
<?php if($template): ?>
|
|
<form action="<?= BASE_URL ?>/settings/pdf-designer/delete" method="POST" class="d-inline" onsubmit="return confirm('คุณแน่ใจหรือไม่ว่าต้องการลบแม่แบบนี้?');">
|
|
<input type="hidden" name="csrf_token" value="<?= $csrf_token ?>">
|
|
<input type="hidden" name="id" value="<?= $template['id'] ?>">
|
|
<button type="submit" class="btn btn-sm btn-outline-danger"><i class="fa-solid fa-trash"></i> ลบ</button>
|
|
</form>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
<div class="card-body bg-light text-center p-0" style="height: 800px; overflow: auto; position: relative;" id="canvasContainer">
|
|
<div style="position: relative; margin: 20px auto; width: 800px; display: inline-block;" id="canvasWrapper">
|
|
<canvas id="pdfRenderer" width="800" height="1131" style="position: absolute; top: 0; left: 0; box-shadow: 0 4px 8px rgba(0,0,0,0.1); background-color: white; z-index: 1;"></canvas>
|
|
<canvas id="pdfCanvas" width="800" height="1131" style="position: absolute; top: 0; left: 0; z-index: 2;"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php
|
|
$pdfUrl = $template ? BASE_URL . $template['file_path'] : '';
|
|
$templateId = $template ? $template['id'] : 0;
|
|
$fieldMapping = !empty($template['field_mapping']) ? $template['field_mapping'] : '[]';
|
|
|
|
$extraScripts = '
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.1/fabric.min.js"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function() {
|
|
var pdfUrl = "' . $pdfUrl . '";
|
|
var templateId = ' . $templateId . ';
|
|
var existingMapping = ' . $fieldMapping . ';
|
|
var pdfRenderer = document.getElementById("pdfRenderer");
|
|
var canvasWrapper = document.getElementById("canvasWrapper");
|
|
|
|
// Initialize Fabric
|
|
var canvas = new fabric.Canvas("pdfCanvas");
|
|
canvas.preserveObjectStacking = true; // Keep objects in order
|
|
|
|
if (pdfUrl) {
|
|
pdfjsLib.GlobalWorkerOptions.workerSrc = "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.worker.min.js";
|
|
|
|
var loadingTask = pdfjsLib.getDocument(pdfUrl);
|
|
loadingTask.promise.then(function(pdf) {
|
|
return pdf.getPage(1);
|
|
}).then(function(page) {
|
|
var unscaledViewport = page.getViewport({scale: 1});
|
|
var scale = 800 / unscaledViewport.width;
|
|
var viewport = page.getViewport({scale: scale});
|
|
|
|
// Set underlying PDF canvas
|
|
pdfRenderer.height = viewport.height;
|
|
pdfRenderer.width = viewport.width;
|
|
|
|
// Adjust wrapper and Fabric canvas to match
|
|
canvasWrapper.style.width = viewport.width + "px";
|
|
canvasWrapper.style.height = viewport.height + "px";
|
|
canvas.setWidth(viewport.width);
|
|
canvas.setHeight(viewport.height);
|
|
|
|
var renderContext = {
|
|
canvasContext: pdfRenderer.getContext("2d"),
|
|
viewport: viewport
|
|
};
|
|
|
|
return page.render(renderContext).promise.then(function() {
|
|
// PDF is now rendered natively to the bottom canvas!
|
|
// We just load existing fields onto the transparent top canvas.
|
|
loadExistingMapping();
|
|
});
|
|
}).catch(function(err) {
|
|
console.error("Error rendering PDF", err);
|
|
Swal.fire("ข้อผิดพลาด PDF.js", "ไม่สามารถแสดง PDF ได้: " + err.message, "error");
|
|
loadDummyBackground();
|
|
});
|
|
} else {
|
|
loadDummyBackground();
|
|
}
|
|
|
|
function loadDummyBackground() {
|
|
fabric.Image.fromURL("https://via.placeholder.com/800x1131.png?text=Please+Upload+PDF+Template", function(img) {
|
|
img.set({ selectable: false, evented: false, opacity: 0.3 });
|
|
canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas));
|
|
loadExistingMapping();
|
|
});
|
|
}
|
|
|
|
function loadExistingMapping() {
|
|
if (!existingMapping || existingMapping.length === 0) return;
|
|
existingMapping.forEach(function(item) {
|
|
var textObj;
|
|
if (item.field.includes("signature") || item.field.includes("qr")) {
|
|
textObj = new fabric.Rect({
|
|
left: 0, top: 0, width: item.width, height: item.height,
|
|
fill: "rgba(255,0,0,0.2)", stroke: "red", strokeWidth: 2
|
|
});
|
|
var label = new fabric.Text(item.field, { left: 10, top: 15, fontSize: 16, fill: "red" });
|
|
textObj = new fabric.Group([textObj, label], { left: item.x, top: item.y });
|
|
textObj.customField = item.field;
|
|
} else {
|
|
textObj = new fabric.Text(item.field, {
|
|
left: item.x, top: item.y, fontSize: item.font_size || 13,
|
|
fontFamily: "Sarabun", fill: item.color || "#000000", borderColor: "blue"
|
|
});
|
|
textObj.customField = item.field;
|
|
}
|
|
canvas.add(textObj);
|
|
});
|
|
}
|
|
|
|
var fields = document.querySelectorAll(".draggable-field");
|
|
fields.forEach(function(field) {
|
|
field.addEventListener("dragstart", function(e) {
|
|
e.dataTransfer.setData("text/plain", JSON.stringify({
|
|
type: field.dataset.type,
|
|
field: field.dataset.field
|
|
}));
|
|
});
|
|
});
|
|
|
|
var container = document.getElementById("canvasContainer");
|
|
container.addEventListener("dragover", function(e) { e.preventDefault(); });
|
|
container.addEventListener("drop", function(e) {
|
|
e.preventDefault();
|
|
var data = JSON.parse(e.dataTransfer.getData("text/plain"));
|
|
var rect = document.querySelector(".canvas-container").getBoundingClientRect();
|
|
|
|
var x = e.clientX - rect.left;
|
|
var y = e.clientY - rect.top;
|
|
|
|
var textObj;
|
|
if(data.type === "Text") {
|
|
textObj = new fabric.Text(data.field, {
|
|
left: x, top: y, fontSize: 13, fontFamily: "Sarabun", fill: "#000000"
|
|
});
|
|
} else {
|
|
textObj = new fabric.Rect({
|
|
left: 0, top: 0, width: 150, height: 50,
|
|
fill: "rgba(255,0,0,0.2)", stroke: "red", strokeWidth: 2
|
|
});
|
|
var label = new fabric.Text(data.field, { left: 10, top: 15, fontSize: 16, fill: "red" });
|
|
textObj = new fabric.Group([textObj, label], { left: x, top: y });
|
|
}
|
|
textObj.customField = data.field;
|
|
canvas.add(textObj);
|
|
canvas.setActiveObject(textObj);
|
|
});
|
|
|
|
window.addEventListener("keydown", function(e) {
|
|
if(e.key === "Delete" || e.key === "Backspace") {
|
|
var activeObject = canvas.getActiveObject();
|
|
if (activeObject && !activeObject.isEditing) {
|
|
canvas.remove(activeObject);
|
|
document.getElementById("propertyEditor").classList.add("d-none");
|
|
}
|
|
}
|
|
});
|
|
|
|
// Handle selection for property editor
|
|
canvas.on("selection:created", showProperties);
|
|
canvas.on("selection:updated", showProperties);
|
|
canvas.on("selection:cleared", function() {
|
|
document.getElementById("propertyEditor").classList.add("d-none");
|
|
});
|
|
|
|
function showProperties(e) {
|
|
var obj = e.selected[0];
|
|
if (obj && obj.type === "text") {
|
|
document.getElementById("propertyEditor").classList.remove("d-none");
|
|
document.getElementById("fieldSize").value = Math.round(obj.fontSize * obj.scaleY);
|
|
document.getElementById("fieldColor").value = obj.fill;
|
|
} else {
|
|
document.getElementById("propertyEditor").classList.add("d-none");
|
|
}
|
|
}
|
|
|
|
document.getElementById("fieldSize").addEventListener("input", function() {
|
|
var obj = canvas.getActiveObject();
|
|
if (obj && obj.type === "text") {
|
|
obj.set("fontSize", parseInt(this.value) / obj.scaleY);
|
|
canvas.renderAll();
|
|
}
|
|
});
|
|
|
|
document.getElementById("fieldColor").addEventListener("input", function() {
|
|
var obj = canvas.getActiveObject();
|
|
if (obj && obj.type === "text") {
|
|
obj.set("fill", this.value);
|
|
canvas.renderAll();
|
|
}
|
|
});
|
|
|
|
|
|
document.getElementById("saveLayoutBtn").addEventListener("click", function() {
|
|
if (!templateId) {
|
|
Swal.fire("แจ้งเตือน", "กรุณาอัปโหลดไฟล์ PDF ต้นฉบับก่อนตั้งค่าพิกัด", "warning");
|
|
return;
|
|
}
|
|
|
|
var btn = this;
|
|
btn.innerHTML = "<i class=\'fa-solid fa-spinner fa-spin\'></i> กำลังบันทึก...";
|
|
btn.disabled = true;
|
|
|
|
var objects = canvas.getObjects();
|
|
var layoutData = [];
|
|
|
|
objects.forEach(function(obj) {
|
|
if(obj.customField) {
|
|
var isText = obj.type === "text";
|
|
layoutData.push({
|
|
field: obj.customField,
|
|
x: Math.round(obj.left),
|
|
y: Math.round(obj.top),
|
|
width: Math.round(obj.width * obj.scaleX),
|
|
height: Math.round(obj.height * obj.scaleY),
|
|
font_size: isText ? Math.round(obj.fontSize * obj.scaleY) : 0,
|
|
color: obj.fill || "#000000"
|
|
});
|
|
}
|
|
});
|
|
|
|
fetch("' . BASE_URL . '/settings/pdf-designer/save", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ template_id: templateId, fields: layoutData })
|
|
})
|
|
.then(res => res.json())
|
|
.then(data => {
|
|
btn.innerHTML = "<i class=\'fa-solid fa-floppy-disk me-1\'></i> บันทึกตำแหน่งฟิลด์";
|
|
btn.disabled = false;
|
|
if(data.status === "success") {
|
|
Swal.fire("สำเร็จ", "บันทึกตำแหน่ง (X,Y) เข้าสู่ฐานข้อมูลเรียบร้อยแล้ว จำนวน " + layoutData.length + " ฟิลด์", "success");
|
|
} else {
|
|
Swal.fire("ผิดพลาด", data.message || "เกิดข้อผิดพลาดในการบันทึก", "error");
|
|
}
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
';
|
|
?>
|