899 lines
53 KiB
PHP
899 lines
53 KiB
PHP
<?php
|
|
// views/settings/index.php
|
|
require_once dirname(__DIR__, 2) . '/models/Setting.php';
|
|
require_once dirname(__DIR__, 2) . '/models/Department.php';
|
|
$settingModel = new Setting();
|
|
$deptModel = new Department();
|
|
$flatSettings = $settingModel->getAllFlat();
|
|
|
|
// Handle Department Actions
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'department') {
|
|
if (ob_get_length()) ob_clean();
|
|
header('Content-Type: application/json');
|
|
try {
|
|
if ($_POST['sub_action'] === 'add') {
|
|
$deptModel->add($_POST['name']);
|
|
echo json_encode(['status' => 'success', 'message' => 'เพิ่มจุดรับ-ส่งเรียบร้อยแล้ว']);
|
|
} elseif ($_POST['sub_action'] === 'edit') {
|
|
$deptModel->update($_POST['id'], $_POST['name'], $_POST['status']);
|
|
echo json_encode(['status' => 'success', 'message' => 'แก้ไขจุดรับ-ส่งเรียบร้อยแล้ว']);
|
|
} elseif ($_POST['sub_action'] === 'delete') {
|
|
$deptModel->delete($_POST['id']);
|
|
echo json_encode(['status' => 'success', 'message' => 'ลบจุดรับ-ส่งเรียบร้อยแล้ว']);
|
|
}
|
|
} catch (Exception $e) {
|
|
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
|
|
}
|
|
exit;
|
|
}
|
|
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'save_settings') {
|
|
if (ob_get_length()) ob_clean(); // Clear any HTML output buffered by index.php
|
|
header('Content-Type: application/json');
|
|
try {
|
|
if (isset($_POST['settings']) && is_array($_POST['settings'])) {
|
|
foreach ($_POST['settings'] as $key => $value) {
|
|
$settingModel->set($key, $value);
|
|
}
|
|
}
|
|
echo json_encode(['status' => 'success', 'message' => 'บันทึกการตั้งค่าเรียบร้อยแล้ว']);
|
|
} catch (Exception $e) {
|
|
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
|
|
}
|
|
exit;
|
|
}
|
|
?>
|
|
<div class="mb-8">
|
|
<h2 class="text-3xl font-extrabold text-transparent bg-clip-text bg-gradient-to-r from-emerald-600 to-teal-400 dark:from-emerald-400 dark:to-teal-200 mb-2">ตั้งค่าระบบ (System Settings)</h2>
|
|
<p class="text-slate-500 dark:text-slate-400 text-lg">จัดการข้อมูลหน่วยงาน การแจ้งเตือน และการจ่ายงาน</p>
|
|
</div>
|
|
|
|
<?php
|
|
// Prepare SweetAlert message if saved
|
|
$swal_msg = '';
|
|
if (isset($_GET['saved'])) {
|
|
if ($_GET['saved'] === 'dept_add') $swal_msg = 'เพิ่มจุดรับ-ส่งเรียบร้อยแล้ว';
|
|
elseif ($_GET['saved'] === 'dept_edit') $swal_msg = 'แก้ไขจุดรับ-ส่งเรียบร้อยแล้ว';
|
|
elseif ($_GET['saved'] === 'dept_delete') $swal_msg = 'ลบจุดรับ-ส่งเรียบร้อยแล้ว';
|
|
else $swal_msg = 'บันทึกการตั้งค่าเรียบร้อยแล้ว';
|
|
}
|
|
?>
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-4 gap-6 pb-10">
|
|
|
|
<!-- Sidebar Navigation -->
|
|
<div class="lg:col-span-1">
|
|
<div class="glass-card sticky top-24 overflow-hidden border border-white/40 dark:border-slate-700/50 shadow-xl shadow-emerald-900/5 rounded-2xl">
|
|
<nav class="flex flex-col text-sm font-medium p-2 space-y-1" id="settingsTabs">
|
|
<a href="#tab-general" class="tab-link px-4 py-3 rounded-xl text-emerald-700 dark:text-emerald-300 bg-emerald-100/50 dark:bg-emerald-900/30 font-bold transition-all flex items-center group">
|
|
<div class="w-8 h-8 rounded-lg bg-emerald-100 dark:bg-emerald-800/50 flex items-center justify-center mr-3 group-hover:scale-110 transition-transform">
|
|
<i class="fa-solid fa-hospital text-emerald-600 dark:text-emerald-400"></i>
|
|
</div>
|
|
ข้อมูลหน่วยงาน
|
|
</a>
|
|
<a href="#tab-line" class="tab-link px-4 py-3 rounded-xl text-slate-600 dark:text-slate-400 hover:bg-slate-50 dark:hover:bg-slate-800/50 hover:text-slate-900 dark:hover:text-slate-200 transition-all flex items-center group">
|
|
<div class="w-8 h-8 rounded-lg bg-slate-100 dark:bg-slate-800 flex items-center justify-center mr-3 group-hover:scale-110 transition-transform">
|
|
<i class="fa-brands fa-line text-green-500"></i>
|
|
</div>
|
|
LINE Notify / Bot
|
|
</a>
|
|
<a href="#tab-telegram" class="tab-link px-4 py-3 rounded-xl text-slate-600 dark:text-slate-400 hover:bg-slate-50 dark:hover:bg-slate-800/50 hover:text-slate-900 dark:hover:text-slate-200 transition-all flex items-center group">
|
|
<div class="w-8 h-8 rounded-lg bg-slate-100 dark:bg-slate-800 flex items-center justify-center mr-3 group-hover:scale-110 transition-transform">
|
|
<i class="fa-brands fa-telegram text-blue-500"></i>
|
|
</div>
|
|
Telegram Bot
|
|
</a>
|
|
<a href="#tab-dispatch" class="tab-link px-4 py-3 rounded-xl text-slate-600 dark:text-slate-400 hover:bg-slate-50 dark:hover:bg-slate-800/50 hover:text-slate-900 dark:hover:text-slate-200 transition-all flex items-center group">
|
|
<div class="w-8 h-8 rounded-lg bg-slate-100 dark:bg-slate-800 flex items-center justify-center mr-3 group-hover:scale-110 transition-transform">
|
|
<i class="fa-solid fa-robot text-purple-500"></i>
|
|
</div>
|
|
ระบบจ่ายงานอัตโนมัติ
|
|
</a>
|
|
<a href="#tab-equipments" class="tab-link px-4 py-3 rounded-xl text-slate-600 dark:text-slate-400 hover:bg-slate-50 dark:hover:bg-slate-800/50 hover:text-slate-900 dark:hover:text-slate-200 transition-all flex items-center group">
|
|
<div class="w-8 h-8 rounded-lg bg-slate-100 dark:bg-slate-800 flex items-center justify-center mr-3 group-hover:scale-110 transition-transform">
|
|
<i class="fa-solid fa-wheelchair text-emerald-500"></i>
|
|
</div>
|
|
ประเภทอุปกรณ์
|
|
</a>
|
|
<a href="#tab-priorities" class="tab-link px-4 py-3 rounded-xl text-slate-600 dark:text-slate-400 hover:bg-slate-50 dark:hover:bg-slate-800/50 hover:text-slate-900 dark:hover:text-slate-200 transition-all flex items-center group">
|
|
<div class="w-8 h-8 rounded-lg bg-slate-100 dark:bg-slate-800 flex items-center justify-center mr-3 group-hover:scale-110 transition-transform">
|
|
<i class="fa-solid fa-triangle-exclamation text-red-500"></i>
|
|
</div>
|
|
ระดับความฉุกเฉิน
|
|
</a>
|
|
<a href="#tab-points" class="tab-link px-4 py-3 rounded-xl text-slate-600 dark:text-slate-400 hover:bg-slate-50 dark:hover:bg-slate-800/50 hover:text-slate-900 dark:hover:text-slate-200 transition-all flex items-center group">
|
|
<div class="w-8 h-8 rounded-lg bg-slate-100 dark:bg-slate-800 flex items-center justify-center mr-3 group-hover:scale-110 transition-transform">
|
|
<i class="fa-solid fa-map-location-dot text-rose-500"></i>
|
|
</div>
|
|
จุดรับ-ส่ง (จุดบริการ)
|
|
</a>
|
|
<a href="#tab-maps" class="tab-link px-4 py-3 rounded-xl text-slate-600 dark:text-slate-400 hover:bg-slate-50 dark:hover:bg-slate-800/50 hover:text-slate-900 dark:hover:text-slate-200 transition-all flex items-center group">
|
|
<div class="w-8 h-8 rounded-lg bg-slate-100 dark:bg-slate-800 flex items-center justify-center mr-3 group-hover:scale-110 transition-transform">
|
|
<i class="fa-solid fa-map text-amber-500"></i>
|
|
</div>
|
|
แผนผังอาคาร (Floor Plans)
|
|
</a>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Settings Content -->
|
|
<div class="lg:col-span-3 relative min-h-[500px]">
|
|
|
|
<form id="mainSettingsForm">
|
|
<input type="hidden" name="action" value="save_settings">
|
|
<input type="hidden" name="csrf_token" value="<?= generateCSRFToken() ?>">
|
|
|
|
<!-- General Settings -->
|
|
<div id="tab-general" class="glass-card p-6 tab-content">
|
|
<h3 class="text-lg font-bold text-slate-800 dark:text-white mb-4 flex items-center">
|
|
<i class="fa-solid fa-hospital text-emerald-500 mr-2"></i> ข้อมูลหน่วยงาน
|
|
</h3>
|
|
<div class="space-y-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">ชื่อโรงพยาบาล</label>
|
|
<input type="text" class="glass-input w-full px-4 py-2" name="settings[hospital_name]" value="<?= escape($settings['general']['hospital_name'] ?? 'โรงพยาบาลเกาะสมุย') ?>">
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">ชื่อหน่วยงาน</label>
|
|
<input type="text" class="glass-input w-full px-4 py-2" name="settings[department_name]" value="<?= escape($settings['general']['department_name'] ?? 'ศูนย์เปล (Patient Transport)') ?>">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- LINE Settings -->
|
|
<div id="tab-line" class="glass-card p-6 tab-content hidden">
|
|
<h3 class="text-lg font-bold text-slate-800 dark:text-white mb-4 flex items-center">
|
|
<i class="fa-brands fa-line text-green-500 mr-2"></i> LINE Notify / Bot
|
|
</h3>
|
|
<div class="space-y-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">LINE Notify Token</label>
|
|
<div class="relative">
|
|
<input type="password" class="glass-input w-full px-4 py-2 pr-10" name="settings[line_notify_token]" value="<?= escape($flatSettings['line_notify_token'] ?? '') ?>">
|
|
<button type="button" class="absolute inset-y-0 right-0 px-3 flex items-center text-slate-400 hover:text-slate-600 toggle-password">
|
|
<i class="fa-solid fa-eye"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">LINE Group ID</label>
|
|
<input type="text" class="glass-input w-full px-4 py-2" name="settings[line_group_id]" value="<?= escape($flatSettings['line_group_id'] ?? '') ?>">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Telegram Settings -->
|
|
<div id="tab-telegram" class="glass-card p-6 tab-content hidden">
|
|
<h3 class="text-lg font-bold text-slate-800 dark:text-white mb-4 flex items-center">
|
|
<i class="fa-brands fa-telegram text-blue-500 mr-2"></i> Telegram Bot
|
|
</h3>
|
|
<div class="space-y-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">Telegram Bot Token</label>
|
|
<div class="relative">
|
|
<input type="password" class="glass-input w-full px-4 py-2 pr-10" name="settings[telegram_bot_token]" value="<?= escape($flatSettings['telegram_bot_token'] ?? '') ?>">
|
|
<button type="button" class="absolute inset-y-0 right-0 px-3 flex items-center text-slate-400 hover:text-slate-600 toggle-password">
|
|
<i class="fa-solid fa-eye"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">Telegram Chat ID</label>
|
|
<input type="text" class="glass-input w-full px-4 py-2" name="settings[telegram_chat_id]" value="<?= escape($flatSettings['telegram_chat_id'] ?? '') ?>">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Dispatch Settings -->
|
|
<div id="tab-dispatch" class="glass-card p-6 tab-content hidden">
|
|
<h3 class="text-lg font-bold text-slate-800 dark:text-white mb-4 flex items-center">
|
|
<i class="fa-solid fa-robot text-purple-500 mr-2"></i> ระบบจ่ายงานอัตโนมัติ
|
|
</h3>
|
|
<div class="space-y-4">
|
|
<div class="flex items-center justify-between p-4 bg-slate-50 dark:bg-slate-800/50 rounded-xl border border-slate-200 dark:border-slate-700">
|
|
<div>
|
|
<p class="font-medium text-slate-800 dark:text-white">เปิดใช้งาน Smart Auto Dispatch</p>
|
|
<p class="text-sm text-slate-500">ระบบจะค้นหาและจ่ายงานให้เจ้าหน้าที่ที่ว่างและอยู่ใกล้ที่สุดอัตโนมัติ</p>
|
|
</div>
|
|
<label class="relative inline-flex items-center cursor-pointer">
|
|
<input type="hidden" name="settings[auto_dispatch_enabled]" value="0">
|
|
<input type="checkbox" name="settings[auto_dispatch_enabled]" value="1" class="sr-only peer" <?= (isset($flatSettings['auto_dispatch_enabled']) && $flatSettings['auto_dispatch_enabled'] == '1') ? 'checked' : '' ?>>
|
|
<div class="w-11 h-6 bg-slate-200 peer-focus:outline-none rounded-full peer dark:bg-slate-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-emerald-500"></div>
|
|
</label>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">เวลามาตรฐาน SLA สำหรับงานส่งผู้ป่วย (นาที)</label>
|
|
<input type="number" class="glass-input w-full px-4 py-2" name="settings[sla_minutes_default]" value="<?= escape($flatSettings['sla_minutes_default'] ?? '15') ?>">
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">น้ำหนักระยะทาง (กม.) ในการพิจารณา</label>
|
|
<p class="text-xs text-slate-500 mb-2">ระยะทางสูงสุดที่จะนำมาคำนวณการจ่ายงานอัตโนมัติ</p>
|
|
<input type="number" step="0.1" class="glass-input w-full px-4 py-2" name="settings[dispatch_max_distance]" value="<?= escape($flatSettings['dispatch_max_distance'] ?? '2.0') ?>">
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">ความสำคัญของระยะทาง (คะแนน)</label>
|
|
<p class="text-xs text-slate-500 mb-2">คะแนนเพิ่มสำหรับเจ้าหน้าที่ที่อยู่ใกล้ที่สุด (0-100)</p>
|
|
<input type="number" class="glass-input w-full px-4 py-2" name="settings[dispatch_distance_weight]" value="<?= escape($flatSettings['dispatch_distance_weight'] ?? '50') ?>">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Equipments Settings -->
|
|
<div id="tab-equipments" class="glass-card p-6 tab-content hidden">
|
|
<h3 class="text-lg font-bold text-slate-800 dark:text-white mb-4 flex items-center justify-between">
|
|
<span><i class="fa-solid fa-wheelchair text-emerald-500 mr-2"></i> ประเภทอุปกรณ์</span>
|
|
<button type="button" class="btn-secondary-glass py-1 px-3 text-sm" onclick="addEquipmentItem()">
|
|
<i class="fa-solid fa-plus me-1"></i> เพิ่มอุปกรณ์
|
|
</button>
|
|
</h3>
|
|
<div class="space-y-4">
|
|
<p class="text-sm text-slate-500 mb-2">กำหนดประเภทอุปกรณ์ที่สามารถเลือกได้ในหน้าแบบฟอร์มร้องของาน</p>
|
|
<input type="hidden" name="settings[equipment_types]" id="equipmentTypesJson">
|
|
<div id="equipmentList" class="space-y-3">
|
|
<!-- Dynamic content via JS -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Priorities Settings -->
|
|
<div id="tab-priorities" class="glass-card p-6 tab-content hidden">
|
|
<h3 class="text-lg font-bold text-slate-800 dark:text-white mb-4 flex items-center justify-between">
|
|
<span><i class="fa-solid fa-triangle-exclamation text-red-500 mr-2"></i> ระดับความฉุกเฉิน</span>
|
|
<button type="button" class="btn-secondary-glass py-1 px-3 text-sm" onclick="addPriorityItem()">
|
|
<i class="fa-solid fa-plus me-1"></i> เพิ่มความฉุกเฉิน
|
|
</button>
|
|
</h3>
|
|
<div class="space-y-4">
|
|
<p class="text-sm text-slate-500 mb-2">กำหนดระดับความฉุกเฉินและสีที่จะใช้แสดงผล</p>
|
|
<input type="hidden" name="settings[job_priorities]" id="jobPrioritiesJson">
|
|
<div id="priorityList" class="space-y-3">
|
|
<!-- Dynamic content via JS -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Save Button Area -->
|
|
<div class="sticky bottom-4 z-10 p-4 mt-6 flex justify-end bg-white/70 dark:bg-slate-900/70 backdrop-blur-md rounded-2xl border border-emerald-500/20 shadow-[0_8px_30px_rgb(0,0,0,0.12)]">
|
|
<button type="submit" class="btn-primary-glass py-2 px-8 font-medium text-lg rounded-xl flex items-center hover:scale-105 transition-transform duration-200">
|
|
<i class="fa-solid fa-save me-2"></i> บันทึกการตั้งค่า
|
|
</button>
|
|
</div>
|
|
</form>
|
|
|
|
<!-- Tab Content for Points (Outside the main form so it can have its own forms) -->
|
|
<div id="tab-points" class="tab-content hidden animate-[fadeUp_0.3s_ease-out]">
|
|
<div class="glass-card p-6">
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h3 class="text-lg font-bold text-slate-800 dark:text-white flex items-center">
|
|
<i class="fa-solid fa-map-location-dot text-rose-500 mr-2"></i> จุดรับ-ส่ง (จุดบริการ)
|
|
</h3>
|
|
<button type="button" onclick="openAddPointModal()" class="btn-primary-glass py-1 px-4 text-sm font-medium">
|
|
<i class="fa-solid fa-plus me-1"></i> เพิ่มจุดรับ-ส่ง
|
|
</button>
|
|
</div>
|
|
|
|
<div class="overflow-x-auto">
|
|
<table class="w-full text-left border-collapse">
|
|
<thead>
|
|
<tr class="text-xs font-semibold text-slate-500 dark:text-slate-400 uppercase tracking-wider border-b border-slate-200 dark:border-slate-700">
|
|
<th class="pb-3 px-4">ชื่อจุดบริการ</th>
|
|
<th class="pb-3 px-4 text-center">สถานะ</th>
|
|
<th class="pb-3 px-4 text-right">จัดการ</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="text-sm text-slate-700 dark:text-slate-300 divide-y divide-slate-200 dark:divide-slate-700">
|
|
<?php
|
|
$departments = $deptModel->getAll();
|
|
foreach ($departments as $dept):
|
|
?>
|
|
<tr class="hover:bg-slate-50 dark:hover:bg-slate-800/50 transition-colors">
|
|
<td class="py-3 px-4 font-medium"><?= escape($dept['name']) ?></td>
|
|
<td class="py-3 px-4 text-center">
|
|
<?php if ($dept['status'] === 'active'): ?>
|
|
<span class="bg-green-100 text-green-800 px-2 py-1 rounded-full text-xs font-medium">เปิดใช้งาน</span>
|
|
<?php else: ?>
|
|
<span class="bg-slate-100 text-slate-800 px-2 py-1 rounded-full text-xs font-medium">ปิดใช้งาน</span>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td class="py-3 px-4 text-right">
|
|
<a href="?page=public_request&dept_id=<?= $dept['id'] ?>" target="_blank" class="text-emerald-500 hover:text-emerald-700 mr-3" title="ดู/พิมพ์ QR Code (หน้าสแกนเรียกเวรเปล)">
|
|
<i class="fa-solid fa-qrcode"></i>
|
|
</a>
|
|
<button type="button" onclick="openEditPointModal(<?= $dept['id'] ?>, '<?= escape(addslashes($dept['name'])) ?>', '<?= $dept['status'] ?>')" class="text-blue-500 hover:text-blue-700 mr-3" title="แก้ไข">
|
|
<i class="fa-solid fa-edit"></i>
|
|
</button>
|
|
<form class="inline dept-delete-form">
|
|
<input type="hidden" name="csrf_token" value="<?= generateCSRFToken() ?>">
|
|
<input type="hidden" name="action" value="department">
|
|
<input type="hidden" name="sub_action" value="delete">
|
|
<input type="hidden" name="id" value="<?= $dept['id'] ?>">
|
|
<button type="submit" class="text-red-500 hover:text-red-700"><i class="fa-solid fa-trash"></i></button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Add/Edit Point Modal -->
|
|
<div id="pointModal" class="fixed inset-0 z-50 hidden bg-slate-900/50 backdrop-blur-sm flex items-center justify-center">
|
|
<div class="glass-card w-full max-w-md p-6 transform transition-all">
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h3 class="text-xl font-bold text-slate-800 dark:text-white" id="pointModalTitle">เพิ่มจุดรับ-ส่ง</h3>
|
|
<button type="button" onclick="closePointModal()" class="text-slate-400 hover:text-slate-600 dark:hover:text-slate-200">
|
|
<i class="fa-solid fa-times fa-lg"></i>
|
|
</button>
|
|
</div>
|
|
<form id="deptModalForm">
|
|
<input type="hidden" name="csrf_token" value="<?= generateCSRFToken() ?>">
|
|
<input type="hidden" name="action" value="department">
|
|
<input type="hidden" name="sub_action" id="pointSubAction" value="add">
|
|
<input type="hidden" name="id" id="pointId" value="">
|
|
|
|
<div class="space-y-4 mb-6">
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">ชื่อจุดบริการ <span class="text-red-500">*</span></label>
|
|
<input type="text" id="pointName" name="name" class="glass-input w-full px-4 py-2" required>
|
|
</div>
|
|
<div id="statusContainer" class="hidden">
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">สถานะ</label>
|
|
<select id="pointStatus" name="status" class="glass-input w-full px-4 py-2">
|
|
<option value="active">เปิดใช้งาน</option>
|
|
<option value="inactive">ปิดใช้งาน</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex justify-end gap-3">
|
|
<button type="button" onclick="closePointModal()" class="btn-secondary-glass py-2 px-4">ยกเลิก</button>
|
|
<button type="submit" class="btn-primary-glass py-2 px-6">บันทึก</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tab Content for Maps -->
|
|
<div id="tab-maps" class="tab-content hidden animate-[fadeUp_0.3s_ease-out]">
|
|
<div class="glass-card p-6">
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h3 class="text-lg font-bold text-slate-800 dark:text-white flex items-center">
|
|
<i class="fa-solid fa-map text-amber-500 mr-2"></i> แผนผังอาคาร
|
|
</h3>
|
|
<button type="button" onclick="openMapUploadModal()" class="btn-primary-glass py-1 px-4 text-sm font-medium">
|
|
<i class="fa-solid fa-plus me-1"></i> เพิ่มแผนผัง
|
|
</button>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6" id="mapsGrid">
|
|
<!-- Dynamic Map Cards -->
|
|
<div class="col-span-full text-center text-slate-500 py-8">กำลังโหลดข้อมูลแผนผัง...</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Map Upload Modal -->
|
|
<div id="mapUploadModal" class="fixed inset-0 z-50 hidden bg-slate-900/50 backdrop-blur-sm flex items-center justify-center p-4">
|
|
<div class="glass-card w-full max-w-md p-6 transform transition-all">
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h3 class="text-xl font-bold text-slate-800 dark:text-white">เพิ่มแผนผังอาคาร</h3>
|
|
<button type="button" onclick="closeMapUploadModal()" class="text-slate-400 hover:text-slate-600 dark:hover:text-slate-200">
|
|
<i class="fa-solid fa-times fa-lg"></i>
|
|
</button>
|
|
</div>
|
|
<form id="mapUploadForm">
|
|
<input type="hidden" name="action" value="upload">
|
|
<div class="space-y-4 mb-6">
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">ชื่อแผนผัง <span class="text-red-500">*</span></label>
|
|
<input type="text" name="name" class="glass-input w-full px-4 py-2" required placeholder="เช่น ชั้น 1 อาคารผู้ป่วยนอก">
|
|
</div>
|
|
<div class="grid grid-cols-2 gap-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">ตึก/อาคาร <span class="text-red-500">*</span></label>
|
|
<input type="text" name="building" class="glass-input w-full px-4 py-2" required>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">ชั้น <span class="text-red-500">*</span></label>
|
|
<input type="text" name="floor" class="glass-input w-full px-4 py-2" required>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">ตำแหน่งศูนย์เปล/จุดพักคอย (ถ้ามี)</label>
|
|
<input type="text" name="transport_center_location" class="glass-input w-full px-4 py-2" placeholder="เช่น บริเวณหน้าลิฟต์ฝั่งตะวันออก">
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">ไฟล์รูปภาพแผนผัง <span class="text-red-500">*</span></label>
|
|
<input type="file" name="map_image" class="block w-full text-sm text-slate-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-emerald-50 file:text-emerald-700 hover:file:bg-emerald-100" accept="image/jpeg, image/png, image/webp" required>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex justify-end gap-3">
|
|
<button type="button" onclick="closeMapUploadModal()" class="btn-secondary-glass py-2 px-4">ยกเลิก</button>
|
|
<button type="submit" class="btn-primary-glass py-2 px-6">อัปโหลด</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Data from server
|
|
let equipmentTypesData = <?= isset($settings['general']['equipment_types']) && !empty($settings['general']['equipment_types']) ? $settings['general']['equipment_types'] : '[{"id":"wheelchair","name":"รถนั่ง (Wheelchair)","icon":"fa-wheelchair"},{"id":"stretcher","name":"รถนอน (Stretcher)","icon":"fa-bed"},{"id":"bed","name":"เตียง (Bed)","icon":"fa-bed-pulse"}]' ?>;
|
|
let jobPrioritiesData = <?= isset($settings['general']['job_priorities']) && !empty($settings['general']['job_priorities']) ? $settings['general']['job_priorities'] : '[{"id":"normal","name":"ทั่วไป (Normal)","color":"blue"},{"id":"urgent","name":"ด่วน (Urgency)","color":"amber"},{"id":"emergency","name":"ฉุกเฉิน (Emergency)","color":"red"}]' ?>;
|
|
|
|
// Ensure data is array if it's string
|
|
if (typeof equipmentTypesData === 'string') {
|
|
try { equipmentTypesData = JSON.parse(equipmentTypesData); } catch (e) { equipmentTypesData = []; }
|
|
}
|
|
if (typeof jobPrioritiesData === 'string') {
|
|
try { jobPrioritiesData = JSON.parse(jobPrioritiesData); } catch (e) { jobPrioritiesData = []; }
|
|
}
|
|
|
|
// Equipment Logic
|
|
function renderEquipments() {
|
|
const container = document.getElementById('equipmentList');
|
|
container.innerHTML = '';
|
|
equipmentTypesData.forEach((item, index) => {
|
|
const html = `
|
|
<div class="flex items-center gap-3 p-3 bg-slate-50 dark:bg-slate-800/50 rounded-xl border border-slate-200 dark:border-slate-700">
|
|
<div class="w-10 text-center text-slate-400"><i class="fa-solid ${item.icon} text-lg"></i></div>
|
|
<div class="flex-1 grid grid-cols-3 gap-3">
|
|
<input type="text" class="glass-input px-3 py-1 text-sm" placeholder="ID (เช่น wheelchair)" value="${item.id}" onchange="updateEquipment(${index}, 'id', this.value)">
|
|
<input type="text" class="glass-input px-3 py-1 text-sm" placeholder="ชื่อ (เช่น รถนั่ง)" value="${item.name}" onchange="updateEquipment(${index}, 'name', this.value)">
|
|
<input type="text" class="glass-input px-3 py-1 text-sm" placeholder="Icon (เช่น fa-wheelchair)" value="${item.icon}" onchange="updateEquipment(${index}, 'icon', this.value)">
|
|
</div>
|
|
<button type="button" class="text-red-500 hover:text-red-700 p-2" onclick="removeEquipment(${index})"><i class="fa-solid fa-trash"></i></button>
|
|
</div>`;
|
|
container.insertAdjacentHTML('beforeend', html);
|
|
});
|
|
document.getElementById('equipmentTypesJson').value = JSON.stringify(equipmentTypesData);
|
|
}
|
|
window.addEquipmentItem = function() {
|
|
equipmentTypesData.push({id: '', name: '', icon: 'fa-box'});
|
|
renderEquipments();
|
|
};
|
|
window.removeEquipment = function(index) {
|
|
equipmentTypesData.splice(index, 1);
|
|
renderEquipments();
|
|
};
|
|
window.updateEquipment = function(index, field, value) {
|
|
equipmentTypesData[index][field] = value;
|
|
document.getElementById('equipmentTypesJson').value = JSON.stringify(equipmentTypesData);
|
|
if(field === 'icon') renderEquipments(); // re-render to update icon preview
|
|
};
|
|
|
|
// Priority Logic
|
|
function renderPriorities() {
|
|
const container = document.getElementById('priorityList');
|
|
container.innerHTML = '';
|
|
jobPrioritiesData.forEach((item, index) => {
|
|
const html = `
|
|
<div class="flex items-center gap-3 p-3 bg-slate-50 dark:bg-slate-800/50 rounded-xl border border-slate-200 dark:border-slate-700">
|
|
<div class="w-10 text-center text-${item.color}-500"><i class="fa-solid fa-circle text-lg"></i></div>
|
|
<div class="flex-1 grid grid-cols-3 gap-3">
|
|
<input type="text" class="glass-input px-3 py-1 text-sm" placeholder="ID (เช่น normal)" value="${item.id}" onchange="updatePriority(${index}, 'id', this.value)">
|
|
<input type="text" class="glass-input px-3 py-1 text-sm" placeholder="ชื่อ (เช่น ทั่วไป)" value="${item.name}" onchange="updatePriority(${index}, 'name', this.value)">
|
|
<select class="glass-input px-3 py-1 text-sm" onchange="updatePriority(${index}, 'color', this.value)">
|
|
<option value="blue" ${item.color==='blue'?'selected':''}>Blue (ฟ้า)</option>
|
|
<option value="emerald" ${item.color==='emerald'?'selected':''}>Emerald (เขียว)</option>
|
|
<option value="amber" ${item.color==='amber'?'selected':''}>Amber (เหลือง)</option>
|
|
<option value="orange" ${item.color==='orange'?'selected':''}>Orange (ส้ม)</option>
|
|
<option value="red" ${item.color==='red'?'selected':''}>Red (แดง)</option>
|
|
<option value="purple" ${item.color==='purple'?'selected':''}>Purple (ม่วง)</option>
|
|
<option value="slate" ${item.color==='slate'?'selected':''}>Slate (เทา)</option>
|
|
</select>
|
|
</div>
|
|
<button type="button" class="text-red-500 hover:text-red-700 p-2" onclick="removePriority(${index})"><i class="fa-solid fa-trash"></i></button>
|
|
</div>`;
|
|
container.insertAdjacentHTML('beforeend', html);
|
|
});
|
|
document.getElementById('jobPrioritiesJson').value = JSON.stringify(jobPrioritiesData);
|
|
}
|
|
window.addPriorityItem = function() {
|
|
jobPrioritiesData.push({id: '', name: '', color: 'blue'});
|
|
renderPriorities();
|
|
};
|
|
window.removePriority = function(index) {
|
|
jobPrioritiesData.splice(index, 1);
|
|
renderPriorities();
|
|
};
|
|
window.updatePriority = function(index, field, value) {
|
|
jobPrioritiesData[index][field] = value;
|
|
document.getElementById('jobPrioritiesJson').value = JSON.stringify(jobPrioritiesData);
|
|
if(field === 'color') renderPriorities(); // re-render to update color preview
|
|
};
|
|
|
|
// Initialize
|
|
renderEquipments();
|
|
renderPriorities();
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Password Toggle
|
|
document.querySelectorAll('.toggle-password').forEach(btn => {
|
|
btn.addEventListener('click', function() {
|
|
const input = this.previousElementSibling;
|
|
const icon = this.querySelector('i');
|
|
if (input.type === 'password') {
|
|
input.type = 'text';
|
|
icon.classList.remove('fa-eye');
|
|
icon.classList.add('fa-eye-slash');
|
|
} else {
|
|
input.type = 'password';
|
|
icon.classList.remove('fa-eye-slash');
|
|
icon.classList.add('fa-eye');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Tab Switching Logic
|
|
const tabLinks = document.querySelectorAll('.tab-link');
|
|
const tabContents = document.querySelectorAll('.tab-content');
|
|
|
|
tabLinks.forEach(link => {
|
|
link.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
|
|
// Remove active classes from all links
|
|
tabLinks.forEach(l => {
|
|
l.classList.remove('text-emerald-700', 'dark:text-emerald-300', 'bg-emerald-100/50', 'dark:bg-emerald-900/30', 'font-bold');
|
|
l.classList.add('text-slate-600', 'dark:text-slate-400', 'hover:bg-slate-50', 'dark:hover:bg-slate-800/50', 'hover:text-slate-900', 'dark:hover:text-slate-200');
|
|
// Change icon bg back
|
|
const iconBg = l.querySelector('.w-8.h-8');
|
|
if (iconBg) {
|
|
iconBg.classList.remove('bg-emerald-100', 'dark:bg-emerald-800/50');
|
|
iconBg.classList.add('bg-slate-100', 'dark:bg-slate-800');
|
|
}
|
|
});
|
|
|
|
// Add active class to clicked link
|
|
this.classList.remove('text-slate-600', 'dark:text-slate-400', 'hover:bg-slate-50', 'dark:hover:bg-slate-800/50', 'hover:text-slate-900', 'dark:hover:text-slate-200');
|
|
this.classList.add('text-emerald-700', 'dark:text-emerald-300', 'bg-emerald-100/50', 'dark:bg-emerald-900/30', 'font-bold');
|
|
// Change icon bg to active
|
|
const iconBg = this.querySelector('.w-8.h-8');
|
|
if (iconBg) {
|
|
iconBg.classList.remove('bg-slate-100', 'dark:bg-slate-800');
|
|
iconBg.classList.add('bg-emerald-100', 'dark:bg-emerald-800/50');
|
|
}
|
|
|
|
// Hide all tab contents
|
|
tabContents.forEach(content => {
|
|
content.classList.add('hidden');
|
|
});
|
|
|
|
// Show target tab content
|
|
const targetId = this.getAttribute('href');
|
|
const targetContent = document.querySelector(targetId);
|
|
if (targetContent) {
|
|
targetContent.classList.remove('hidden');
|
|
targetContent.classList.add('animate-[fadeUp_0.3s_ease-out]');
|
|
|
|
// Save active tab to localStorage
|
|
localStorage.setItem('activeSettingsTab', targetId);
|
|
|
|
// If it's the points tab or maps tab, hide the main form's submit button section
|
|
const mainSaveBtn = document.querySelector('#mainSettingsForm .sticky.bottom-4');
|
|
if (targetId === '#tab-points' || targetId === '#tab-maps') {
|
|
if(mainSaveBtn) mainSaveBtn.classList.add('hidden');
|
|
} else {
|
|
if(mainSaveBtn) mainSaveBtn.classList.remove('hidden');
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Handle AJAX Submission for Main Settings
|
|
$('#mainSettingsForm').on('submit', function(e) {
|
|
e.preventDefault();
|
|
const btn = $(this).find('button[type="submit"]');
|
|
btn.addClass('btn-loading');
|
|
|
|
$.ajax({
|
|
url: '?page=settings',
|
|
type: 'POST',
|
|
data: $(this).serialize(),
|
|
dataType: 'json',
|
|
success: function(response) {
|
|
btn.removeClass('btn-loading');
|
|
if (response.status === 'success') {
|
|
Swal.fire({
|
|
icon: 'success',
|
|
title: 'สำเร็จ',
|
|
text: response.message,
|
|
background: document.documentElement.classList.contains('dark') ? '#1e293b' : '#fff',
|
|
color: document.documentElement.classList.contains('dark') ? '#f1f5f9' : '#1e293b',
|
|
timer: 2000,
|
|
showConfirmButton: false
|
|
});
|
|
} else {
|
|
Swal.fire('ผิดพลาด', response.message, 'error');
|
|
}
|
|
},
|
|
error: function() {
|
|
btn.removeClass('btn-loading');
|
|
Swal.fire('ผิดพลาด', 'ไม่สามารถเชื่อมต่อเซิร์ฟเวอร์ได้', 'error');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Handle AJAX Submission for Department Delete
|
|
$('.dept-delete-form').on('submit', function(e) {
|
|
e.preventDefault();
|
|
|
|
Swal.fire({
|
|
title: 'ยืนยันการลบ?',
|
|
text: "คุณต้องการลบจุดบริการนี้ใช่หรือไม่",
|
|
icon: 'warning',
|
|
showCancelButton: true,
|
|
confirmButtonColor: '#ef4444',
|
|
cancelButtonColor: '#94a3b8',
|
|
confirmButtonText: 'ลบ',
|
|
cancelButtonText: 'ยกเลิก',
|
|
background: document.documentElement.classList.contains('dark') ? '#1e293b' : '#fff',
|
|
color: document.documentElement.classList.contains('dark') ? '#f1f5f9' : '#1e293b'
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
$.ajax({
|
|
url: '?page=settings',
|
|
type: 'POST',
|
|
data: $(this).serialize(),
|
|
dataType: 'json',
|
|
success: function(response) {
|
|
if (response.status === 'success') {
|
|
Swal.fire({
|
|
icon: 'success',
|
|
title: 'สำเร็จ',
|
|
text: response.message,
|
|
background: document.documentElement.classList.contains('dark') ? '#1e293b' : '#fff',
|
|
color: document.documentElement.classList.contains('dark') ? '#f1f5f9' : '#1e293b',
|
|
timer: 1500,
|
|
showConfirmButton: false
|
|
}).then(() => {
|
|
window.location.reload();
|
|
});
|
|
} else {
|
|
Swal.fire('ผิดพลาด', response.message, 'error');
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
// Handle AJAX Submission for Department Modal (Add/Edit)
|
|
$('#deptModalForm').on('submit', function(e) {
|
|
e.preventDefault();
|
|
const btn = $(this).find('button[type="submit"]');
|
|
btn.addClass('btn-loading');
|
|
|
|
$.ajax({
|
|
url: '?page=settings',
|
|
type: 'POST',
|
|
data: $(this).serialize(),
|
|
dataType: 'json',
|
|
success: function(response) {
|
|
btn.removeClass('btn-loading');
|
|
if (response.status === 'success') {
|
|
closePointModal();
|
|
Swal.fire({
|
|
icon: 'success',
|
|
title: 'สำเร็จ',
|
|
text: response.message,
|
|
background: document.documentElement.classList.contains('dark') ? '#1e293b' : '#fff',
|
|
color: document.documentElement.classList.contains('dark') ? '#f1f5f9' : '#1e293b',
|
|
timer: 1500,
|
|
showConfirmButton: false
|
|
}).then(() => {
|
|
window.location.reload();
|
|
});
|
|
} else {
|
|
Swal.fire('ผิดพลาด', response.message, 'error');
|
|
}
|
|
},
|
|
error: function() {
|
|
btn.removeClass('btn-loading');
|
|
Swal.fire('ผิดพลาด', 'ไม่สามารถเชื่อมต่อเซิร์ฟเวอร์ได้', 'error');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Restore active tab from localStorage
|
|
const savedTab = localStorage.getItem('activeSettingsTab');
|
|
if (savedTab) {
|
|
const linkToClick = document.querySelector(`.tab-link[href="${savedTab}"]`);
|
|
if (linkToClick) {
|
|
linkToClick.click();
|
|
}
|
|
}
|
|
|
|
// Trigger SweetAlert if saved
|
|
<?php if (!empty($swal_msg)): ?>
|
|
Swal.fire({
|
|
icon: 'success',
|
|
title: 'สำเร็จ',
|
|
text: '<?= $swal_msg ?>',
|
|
background: document.documentElement.classList.contains('dark') ? '#1e293b' : '#fff',
|
|
color: document.documentElement.classList.contains('dark') ? '#f1f5f9' : '#1e293b',
|
|
timer: 3000,
|
|
showConfirmButton: false
|
|
}).then(() => {
|
|
// Clean up URL to prevent alert on reload
|
|
window.history.replaceState(null, null, window.location.pathname + '?page=settings');
|
|
});
|
|
<?php endif; ?>
|
|
});
|
|
|
|
function openAddPointModal() {
|
|
document.getElementById('pointModalTitle').textContent = 'เพิ่มจุดรับ-ส่ง';
|
|
document.getElementById('pointSubAction').value = 'add';
|
|
document.getElementById('pointId').value = '';
|
|
document.getElementById('pointName').value = '';
|
|
document.getElementById('statusContainer').classList.add('hidden');
|
|
document.getElementById('pointModal').classList.remove('hidden');
|
|
}
|
|
|
|
function openEditPointModal(id, name, status) {
|
|
document.getElementById('pointModalTitle').textContent = 'แก้ไขจุดรับ-ส่ง';
|
|
document.getElementById('pointSubAction').value = 'edit';
|
|
document.getElementById('pointId').value = id;
|
|
document.getElementById('pointName').value = name;
|
|
document.getElementById('pointStatus').value = status;
|
|
document.getElementById('statusContainer').classList.remove('hidden');
|
|
document.getElementById('pointModal').classList.remove('hidden');
|
|
}
|
|
|
|
function closePointModal() {
|
|
document.getElementById('pointModal').classList.add('hidden');
|
|
}
|
|
|
|
// --- MAPS MANAGEMENT LOGIC ---
|
|
function loadMaps() {
|
|
fetch('api/maps.php?action=list')
|
|
.then(res => res.json())
|
|
.then(res => {
|
|
const grid = document.getElementById('mapsGrid');
|
|
if (res.status === 'success') {
|
|
if (res.data.length === 0) {
|
|
grid.innerHTML = '<div class="col-span-full text-center text-slate-500 py-8">ยังไม่มีข้อมูลแผนผังอาคาร</div>';
|
|
return;
|
|
}
|
|
let html = '';
|
|
res.data.forEach(map => {
|
|
html += `
|
|
<div class="bg-white dark:bg-slate-800 rounded-xl shadow-sm border border-slate-200 dark:border-slate-700 overflow-hidden group">
|
|
<div class="h-40 bg-slate-100 dark:bg-slate-900 relative overflow-hidden">
|
|
<img src="${map.image_path}" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300">
|
|
<div class="absolute top-2 right-2 flex gap-1">
|
|
<span class="bg-white/90 dark:bg-slate-800/90 backdrop-blur-sm text-xs px-2 py-1 rounded-md font-bold text-slate-700 dark:text-slate-200 shadow-sm">
|
|
${map.building} ชั้น ${map.floor}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div class="p-4">
|
|
<h4 class="font-bold text-slate-800 dark:text-white mb-1 truncate" title="${map.name}">${map.name}</h4>
|
|
<div class="text-xs text-slate-500 dark:text-slate-400 mb-3 flex items-start">
|
|
<i class="fa-solid fa-location-dot mt-0.5 text-rose-500 mr-1.5 w-3"></i>
|
|
<span class="line-clamp-2">${map.transport_center_location || '- ไม่ระบุจุดศูนย์เปล -'}</span>
|
|
</div>
|
|
<div class="flex justify-between items-center mt-4">
|
|
<span class="text-xs ${map.status === 'active' ? 'text-green-500 bg-green-50 dark:bg-green-900/20' : 'text-slate-500 bg-slate-100 dark:bg-slate-800'} px-2 py-1 rounded-full">
|
|
${map.status === 'active' ? 'ใช้งาน' : 'ไม่ใช้งาน'}
|
|
</span>
|
|
<button onclick="deleteMap(${map.id}, '${map.name}')" class="text-red-500 hover:text-red-700 bg-red-50 hover:bg-red-100 dark:bg-red-900/20 dark:hover:bg-red-900/40 w-8 h-8 rounded-full flex items-center justify-center transition-colors">
|
|
<i class="fa-solid fa-trash text-xs"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>`;
|
|
});
|
|
grid.innerHTML = html;
|
|
}
|
|
});
|
|
}
|
|
|
|
function openMapUploadModal() {
|
|
document.getElementById('mapUploadForm').reset();
|
|
document.getElementById('mapUploadModal').classList.remove('hidden');
|
|
}
|
|
|
|
function closeMapUploadModal() {
|
|
document.getElementById('mapUploadModal').classList.add('hidden');
|
|
}
|
|
|
|
document.getElementById('mapUploadForm').addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
const formData = new FormData(this);
|
|
|
|
const btn = this.querySelector('button[type="submit"]');
|
|
const originalText = btn.innerHTML;
|
|
btn.innerHTML = '<i class="fa-solid fa-spinner fa-spin mr-2"></i> กำลังอัปโหลด...';
|
|
btn.disabled = true;
|
|
|
|
fetch('api/maps.php', {
|
|
method: 'POST',
|
|
body: formData
|
|
})
|
|
.then(res => res.json())
|
|
.then(data => {
|
|
btn.innerHTML = originalText;
|
|
btn.disabled = false;
|
|
|
|
if (data.status === 'success') {
|
|
Swal.fire({
|
|
icon: 'success',
|
|
title: 'อัปโหลดสำเร็จ',
|
|
showConfirmButton: false,
|
|
timer: 1500
|
|
});
|
|
closeMapUploadModal();
|
|
loadMaps();
|
|
} else {
|
|
Swal.fire('ข้อผิดพลาด', data.message, 'error');
|
|
}
|
|
}).catch(err => {
|
|
btn.innerHTML = originalText;
|
|
btn.disabled = false;
|
|
Swal.fire('ข้อผิดพลาด', 'ไม่สามารถเชื่อมต่อเซิร์ฟเวอร์ได้', 'error');
|
|
});
|
|
});
|
|
|
|
function deleteMap(id, name) {
|
|
Swal.fire({
|
|
title: 'ยืนยันการลบแผนผัง?',
|
|
text: `ต้องการลบแผนผัง "${name}" ใช่หรือไม่? (รูปภาพจะถูกลบด้วย)`,
|
|
icon: 'warning',
|
|
showCancelButton: true,
|
|
confirmButtonColor: '#ef4444',
|
|
cancelButtonColor: '#94a3b8',
|
|
confirmButtonText: 'ลบข้อมูล',
|
|
cancelButtonText: 'ยกเลิก',
|
|
background: document.documentElement.classList.contains('dark') ? '#1e293b' : '#fff',
|
|
color: document.documentElement.classList.contains('dark') ? '#f1f5f9' : '#1e293b'
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
const formData = new FormData();
|
|
formData.append('action', 'delete');
|
|
formData.append('id', id);
|
|
|
|
fetch('api/maps.php', {
|
|
method: 'POST',
|
|
body: formData
|
|
})
|
|
.then(res => res.json())
|
|
.then(data => {
|
|
if (data.status === 'success') {
|
|
loadMaps();
|
|
Swal.fire({
|
|
title: 'ลบสำเร็จ!',
|
|
icon: 'success',
|
|
timer: 1500,
|
|
showConfirmButton: false,
|
|
background: document.documentElement.classList.contains('dark') ? '#1e293b' : '#fff',
|
|
color: document.documentElement.classList.contains('dark') ? '#f1f5f9' : '#1e293b'
|
|
});
|
|
} else {
|
|
Swal.fire('ข้อผิดพลาด', data.message, 'error');
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Initialize maps on load
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
if (window.location.hash === '#tab-maps') {
|
|
loadMaps();
|
|
}
|
|
|
|
// Also add click listener to map tab link to load data if not loaded
|
|
document.querySelector('a[href="#tab-maps"]').addEventListener('click', function() {
|
|
if(document.getElementById('mapsGrid').innerHTML.includes('กำลังโหลด')) {
|
|
loadMaps();
|
|
}
|
|
});
|
|
});
|
|
</script>
|