370 lines
20 KiB
PHP
370 lines
20 KiB
PHP
<?php
|
|
require_once 'config.php';
|
|
requireLogin();
|
|
requireAdmin();
|
|
|
|
$success = '';
|
|
$error = '';
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$days_before = $_POST['days_before_due'] ?? '3';
|
|
$notification_time = $_POST['notification_time'] ?? '08:00';
|
|
$footer_text = $_POST['footer_text'] ?? 'ระบบแจ้งเตือนส่งงาน';
|
|
$telegram_bot_token = $_POST['telegram_bot_token'] ?? '';
|
|
$telegram_group_chat_id = $_POST['telegram_group_chat_id'] ?? '';
|
|
$line_notify_token = $_POST['line_notify_token'] ?? '';
|
|
|
|
// Checkboxes
|
|
$notify_via_line = isset($_POST['notify_via_line']) ? '1' : '0';
|
|
$notify_via_telegram = isset($_POST['notify_via_telegram']) ? '1' : '0';
|
|
|
|
try {
|
|
$pdo->beginTransaction();
|
|
|
|
$settings = [
|
|
'days_before_due' => $days_before,
|
|
'notification_time' => $notification_time,
|
|
'footer_text' => $footer_text,
|
|
'telegram_bot_token' => $telegram_bot_token,
|
|
'telegram_group_chat_id' => $telegram_group_chat_id,
|
|
'line_notify_token' => $line_notify_token,
|
|
'notify_via_line' => $notify_via_line,
|
|
'notify_via_telegram' => $notify_via_telegram
|
|
];
|
|
|
|
$stmt = $pdo->prepare("INSERT INTO settings (setting_key, setting_value) VALUES (?, ?) ON DUPLICATE KEY UPDATE setting_value = ?");
|
|
foreach ($settings as $key => $val) {
|
|
$stmt->execute([$key, $val, $val]);
|
|
}
|
|
|
|
$pdo->commit();
|
|
|
|
// Exclude sensitive tokens from logs
|
|
$safe_settings = $settings;
|
|
$safe_settings['telegram_bot_token'] = !empty($safe_settings['telegram_bot_token']) ? '***' : '';
|
|
$safe_settings['line_notify_token'] = !empty($safe_settings['line_notify_token']) ? '***' : '';
|
|
|
|
logActivity($pdo, 'UPDATE_SETTINGS', json_encode($safe_settings, JSON_UNESCAPED_UNICODE));
|
|
|
|
$success = 'บันทึกการตั้งค่าสำเร็จ';
|
|
} catch (Exception $e) {
|
|
$pdo->rollBack();
|
|
$error = 'เกิดข้อผิดพลาด: ' . $e->getMessage();
|
|
}
|
|
}
|
|
|
|
$days_before_due = getSetting($pdo, 'days_before_due') ?: '3';
|
|
$notification_time = getSetting($pdo, 'notification_time') ?: '08:00';
|
|
$footer_text = getSetting($pdo, 'footer_text') ?: 'ระบบแจ้งเตือนส่งงาน';
|
|
$bot_token = getSetting($pdo, 'telegram_bot_token') ?: '';
|
|
$group_chat_id = getSetting($pdo, 'telegram_group_chat_id') ?: '';
|
|
$line_notify_token = getSetting($pdo, 'line_notify_token') ?: '';
|
|
$notify_via_line = getSetting($pdo, 'notify_via_line') === '0' ? false : true; // Default true
|
|
$notify_via_telegram = getSetting($pdo, 'notify_via_telegram') === '0' ? false : true; // Default true
|
|
|
|
include 'includes/header.php';
|
|
include 'includes/sidebar.php';
|
|
?>
|
|
|
|
<div class="mb-4">
|
|
<h2 class="text-2xl font-bold text-gray-800">ตั้งค่าระบบ</h2>
|
|
<p class="text-gray-600 mt-1">ตั้งค่าการแจ้งเตือนและการเชื่อมต่อ API</p>
|
|
</div>
|
|
|
|
<!-- Tabs Navigation -->
|
|
<div class="mb-6 border-b border-gray-200">
|
|
<nav class="-mb-px flex space-x-8" aria-label="Tabs">
|
|
<button onclick="switchTab('general')" id="tab-general" class="border-blue-500 text-blue-600 whitespace-nowrap py-3 px-1 border-b-2 font-bold text-sm transition-colors">
|
|
<i class="fas fa-cogs mr-2"></i> การตั้งค่าทั่วไป
|
|
</button>
|
|
<button onclick="switchTab('logs')" id="tab-logs" class="border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 whitespace-nowrap py-3 px-1 border-b-2 font-medium text-sm transition-colors">
|
|
<i class="fas fa-history mr-2"></i> ประวัติการใช้งาน
|
|
</button>
|
|
</nav>
|
|
</div>
|
|
|
|
<?php if ($error): ?>
|
|
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 mb-6 rounded shadow-sm">
|
|
<p><i class="fas fa-exclamation-circle mr-2"></i> <?= htmlspecialchars($error) ?></p>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($success): ?>
|
|
<script>
|
|
Swal.fire({
|
|
icon: 'success',
|
|
title: 'บันทึกสำเร็จ',
|
|
text: '<?= addslashes($success) ?>',
|
|
timer: 2000,
|
|
showConfirmButton: false
|
|
});
|
|
</script>
|
|
<?php endif; ?>
|
|
|
|
<!-- General Settings Content -->
|
|
<div id="content-general">
|
|
<form method="POST" action="" id="settingsForm">
|
|
<!-- General Settings -->
|
|
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
|
|
<h3 class="text-lg font-bold mb-4 border-b pb-2"><i class="fas fa-cogs text-gray-500 mr-2"></i> ตั้งค่าทั่วไป (General)</h3>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<label class="block text-gray-700 text-sm font-bold mb-2" for="days_before_due">จำนวนวันแจ้งเตือนล่วงหน้า (วัน)</label>
|
|
<div class="flex items-center">
|
|
<input type="number" name="days_before_due" id="days_before_due" value="<?= htmlspecialchars($days_before_due) ?>" min="1" max="30" class="shadow appearance-none border rounded py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:ring-2 focus:ring-blue-500 w-24 mr-2" required>
|
|
<span class="text-gray-600 text-sm">วันก่อนถึงวันกำหนดส่ง</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-gray-700 text-sm font-bold mb-2" for="notification_time">เวลาที่จะแจ้งเตือน</label>
|
|
<input type="time" name="notification_time" id="notification_time" value="<?= htmlspecialchars($notification_time) ?>" class="shadow appearance-none border rounded py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:ring-2 focus:ring-blue-500 w-32" required>
|
|
<p class="text-xs text-gray-500 mt-1">เวลาที่ระบบจะส่งข้อความแจ้งเตือน (ใช้เป็นข้อมูลอ้างอิงในการตั้ง Cron Job)</p>
|
|
</div>
|
|
|
|
<div class="md:col-span-2">
|
|
<label class="block text-gray-700 text-sm font-bold mb-2" for="footer_text">ข้อความ Footer ด้านล่างสุด</label>
|
|
<input type="text" name="footer_text" id="footer_text" value="<?= htmlspecialchars($footer_text) ?>" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="เช่น ระบบส่งงานนักเรียน" required>
|
|
<p class="text-xs text-gray-500 mt-1">ข้อความที่จะแสดงที่แถบด้านล่างสุดของทุกหน้า (ปีปัจจุบันจะถูกเพิ่มให้อัตโนมัติ)</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
|
|
<!-- LINE Settings -->
|
|
<div class="bg-white rounded-lg shadow-md p-6 border-t-4 border-green-500">
|
|
<div class="flex items-center justify-between mb-4 border-b pb-2">
|
|
<h3 class="text-lg font-bold text-green-600"><i class="fab fa-line mr-2"></i> LINE Notify</h3>
|
|
<label class="inline-flex items-center cursor-pointer">
|
|
<input type="checkbox" name="notify_via_line" value="1" class="sr-only peer" <?= $notify_via_line ? 'checked' : '' ?>>
|
|
<div class="relative w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-green-300 rounded-full peer 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 peer-checked:bg-green-600"></div>
|
|
<span class="ml-3 text-sm font-medium text-gray-700">เปิดใช้งาน</span>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="mb-4">
|
|
<label class="block text-gray-700 text-sm font-bold mb-2" for="line_notify_token">LINE Notify Token</label>
|
|
<input type="password" name="line_notify_token" id="line_notify_token" value="<?= htmlspecialchars($line_notify_token) ?>" placeholder="ออก Token จาก notify-bot.line.me" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:ring-2 focus:ring-green-500">
|
|
<p class="text-xs text-gray-500 mt-1">ใช้สำหรับส่งแจ้งเตือนเข้ากลุ่ม LINE</p>
|
|
</div>
|
|
|
|
<div class="mt-4 flex space-x-2">
|
|
<button type="button" onclick="testLine()" class="bg-gray-100 hover:bg-gray-200 text-gray-800 font-semibold py-2 px-4 border border-gray-300 rounded shadow-sm text-sm flex-1">
|
|
<i class="fas fa-paper-plane text-green-500 mr-1"></i> ทดสอบส่ง
|
|
</button>
|
|
</div>
|
|
|
|
<div class="mt-6 bg-gray-50 p-3 rounded text-sm text-gray-600">
|
|
<strong>วิธีใช้งาน:</strong>
|
|
<ol class="list-decimal pl-4 mt-1">
|
|
<li>ไปที่ <a href="https://notify-bot.line.me/" target="_blank" class="text-blue-500 hover:underline">notify-bot.line.me</a></li>
|
|
<li>ออก Token โดยเลือกกลุ่มที่ต้องการ</li>
|
|
<li>เชิญ "LINE Notify" เข้ากลุ่มนั้น</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Telegram Settings -->
|
|
<div class="bg-white rounded-lg shadow-md p-6 border-t-4 border-blue-500">
|
|
<div class="flex items-center justify-between mb-4 border-b pb-2">
|
|
<h3 class="text-lg font-bold text-blue-600"><i class="fab fa-telegram-plane mr-2"></i> Telegram Bot</h3>
|
|
<label class="inline-flex items-center cursor-pointer">
|
|
<input type="checkbox" name="notify_via_telegram" value="1" class="sr-only peer" <?= $notify_via_telegram ? 'checked' : '' ?>>
|
|
<div class="relative w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 rounded-full peer 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 peer-checked:bg-blue-600"></div>
|
|
<span class="ml-3 text-sm font-medium text-gray-700">เปิดใช้งาน</span>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="mb-4">
|
|
<label class="block text-gray-700 text-sm font-bold mb-2" for="telegram_bot_token">Telegram Bot Token</label>
|
|
<input type="password" name="telegram_bot_token" id="telegram_bot_token" value="<?= htmlspecialchars($bot_token) ?>" placeholder="123456:ABC-DEF1234gh..." class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:ring-2 focus:ring-blue-500 mb-3">
|
|
|
|
<label class="block text-gray-700 text-sm font-bold mb-2" for="telegram_group_chat_id">Telegram Group Chat ID</label>
|
|
<input type="text" name="telegram_group_chat_id" id="telegram_group_chat_id" value="<?= htmlspecialchars($group_chat_id) ?>" placeholder="-1001234567890" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:ring-2 focus:ring-blue-500">
|
|
</div>
|
|
|
|
<div class="mt-4 flex space-x-2">
|
|
<button type="button" onclick="testTelegram()" class="bg-gray-100 hover:bg-gray-200 text-gray-800 font-semibold py-2 px-4 border border-gray-300 rounded shadow-sm text-sm flex-1">
|
|
<i class="fas fa-paper-plane text-blue-500 mr-1"></i> ทดสอบส่ง
|
|
</button>
|
|
</div>
|
|
|
|
<div class="mt-6 bg-gray-50 p-3 rounded text-sm text-gray-600">
|
|
<strong>วิธีใช้งาน:</strong>
|
|
<ol class="list-decimal pl-4 mt-1">
|
|
<li>สร้าง Bot กับ <a href="https://t.me/botfather" target="_blank" class="text-blue-500 hover:underline">@BotFather</a></li>
|
|
<li>ดึง Bot เข้ากลุ่มที่ต้องการแจ้งเตือน</li>
|
|
<li>หา Chat ID ของกลุ่ม (ใช้ @RawDataBot ช่วยหาได้)</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-white rounded-lg shadow-md p-4 flex justify-between items-center sticky bottom-4 border border-gray-200">
|
|
<div>
|
|
<a href="cron_notify.php" target="_blank" class="text-blue-600 hover:text-blue-800 text-sm font-medium">
|
|
<i class="fas fa-external-link-alt mr-1"></i> เปิดรัน Cron Job แบบ Manual
|
|
</a>
|
|
</div>
|
|
<button type="submit" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-6 rounded shadow-lg flex items-center transition duration-200">
|
|
<i class="fas fa-save mr-2"></i> บันทึกการตั้งค่าทั้งหมด
|
|
</button>
|
|
</div>
|
|
</form>
|
|
|
|
<script>
|
|
function testLine() {
|
|
const token = document.getElementById('line_notify_token').value;
|
|
if (!token) {
|
|
Swal.fire('ข้อผิดพลาด', 'กรุณากรอก LINE Notify Token', 'error');
|
|
return;
|
|
}
|
|
|
|
Swal.fire({
|
|
title: 'กำลังส่ง...',
|
|
allowOutsideClick: false,
|
|
didOpen: () => { Swal.showLoading(); }
|
|
});
|
|
|
|
$.ajax({
|
|
url: 'api/test_notify.php',
|
|
method: 'POST',
|
|
data: { type: 'line', token: token },
|
|
dataType: 'json',
|
|
success: function(res) {
|
|
Swal.fire(res.status === 'success' ? 'สำเร็จ' : 'ล้มเหลว', res.message, res.status);
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error(xhr.responseText);
|
|
let errMsg = 'ไม่สามารถเชื่อมต่อเซิร์ฟเวอร์ได้';
|
|
if (xhr.responseText) {
|
|
// Try to extract some readable error if possible, or just show a portion of it
|
|
errMsg += '<br><br><span class="text-xs text-red-500">' + xhr.responseText.substring(0, 200) + '...</span>';
|
|
}
|
|
Swal.fire({
|
|
title: 'ข้อผิดพลาด',
|
|
html: errMsg,
|
|
icon: 'error'
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
function testTelegram() {
|
|
const bot_token = document.getElementById('telegram_bot_token').value;
|
|
const chat_id = document.getElementById('telegram_group_chat_id').value;
|
|
|
|
if (!bot_token || !chat_id) {
|
|
Swal.fire('ข้อผิดพลาด', 'กรุณากรอกทั้ง Bot Token และ Chat ID', 'error');
|
|
return;
|
|
}
|
|
|
|
Swal.fire({
|
|
title: 'กำลังส่ง...',
|
|
allowOutsideClick: false,
|
|
didOpen: () => { Swal.showLoading(); }
|
|
});
|
|
|
|
$.ajax({
|
|
url: 'api/test_notify.php',
|
|
method: 'POST',
|
|
data: { type: 'telegram', bot_token: bot_token, chat_id: chat_id },
|
|
dataType: 'json',
|
|
success: function(res) {
|
|
Swal.fire(res.status === 'success' ? 'สำเร็จ' : 'ล้มเหลว', res.message, res.status);
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error(xhr.responseText);
|
|
let errMsg = 'ไม่สามารถเชื่อมต่อเซิร์ฟเวอร์ได้';
|
|
if (xhr.responseText) {
|
|
errMsg += '<br><br><span class="text-xs text-red-500 text-left overflow-hidden">' + xhr.responseText.substring(0, 200) + '...</span>';
|
|
}
|
|
Swal.fire({
|
|
title: 'ข้อผิดพลาด',
|
|
html: errMsg,
|
|
icon: 'error'
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
function switchTab(tab) {
|
|
// Hide all contents
|
|
document.getElementById('content-general').classList.add('hidden');
|
|
document.getElementById('content-logs').classList.add('hidden');
|
|
|
|
// Reset all tabs styling
|
|
document.getElementById('tab-general').className = "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 whitespace-nowrap py-3 px-1 border-b-2 font-medium text-sm transition-colors";
|
|
document.getElementById('tab-logs').className = "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 whitespace-nowrap py-3 px-1 border-b-2 font-medium text-sm transition-colors";
|
|
|
|
// Show active content and style active tab
|
|
document.getElementById('content-' + tab).classList.remove('hidden');
|
|
document.getElementById('tab-' + tab).className = "border-blue-500 text-blue-600 whitespace-nowrap py-3 px-1 border-b-2 font-bold text-sm transition-colors";
|
|
}
|
|
</script>
|
|
</div> <!-- End content-general -->
|
|
|
|
|
|
<div id="content-logs" class="hidden">
|
|
<!-- Activity Logs Section -->
|
|
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
|
|
<h3 class="text-lg font-bold mb-4 border-b pb-2"><i class="fas fa-history text-gray-500 mr-2"></i> ประวัติการใช้งานระบบ (Activity Logs)</h3>
|
|
|
|
<table id="logsTable" class="dataTable display min-w-full bg-white w-full">
|
|
<thead class="bg-gray-100 text-gray-600">
|
|
<tr>
|
|
<th class="py-3 px-4 text-center font-semibold text-sm border-b w-32">วันเวลา</th>
|
|
<th class="py-3 px-4 text-center font-semibold text-sm border-b w-48">ผู้ใช้งาน</th>
|
|
<th class="py-3 px-4 text-center font-semibold text-sm border-b w-48">การกระทำ (Action)</th>
|
|
<th class="py-3 px-4 text-center font-semibold text-sm border-b">รายละเอียด (Details)</th>
|
|
<th class="py-3 px-4 text-center font-semibold text-sm border-b w-32">IP Address</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="text-gray-700">
|
|
<!-- Data will be loaded via AJAX -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- DataTables Export Plugins for Logs -->
|
|
<script src="https://cdn.datatables.net/buttons/2.4.1/js/dataTables.buttons.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
|
|
<script src="https://cdn.datatables.net/buttons/2.4.1/js/buttons.html5.min.js"></script>
|
|
|
|
<script>
|
|
$(document).ready(function() {
|
|
$('#logsTable').DataTable({
|
|
ajax: 'api/get_logs_table.php',
|
|
columns: [
|
|
{ data: 'created_at' },
|
|
{ data: 'user' },
|
|
{ data: 'action' },
|
|
{ data: 'details' },
|
|
{ data: 'ip_address' }
|
|
],
|
|
order: [[0, 'desc']], // Sort by date descending
|
|
scrollX: true,
|
|
columnDefs: [{ className: "dt-head-center", targets: "_all" }],
|
|
pageLength: 10,
|
|
dom: '<"flex justify-between items-center mb-4"lBf>rt<"flex justify-between items-center mt-4"ip>',
|
|
buttons: [
|
|
{
|
|
extend: 'excelHtml5',
|
|
text: '<i class="fas fa-file-excel mr-1"></i> ส่งออก Excel',
|
|
className: 'bg-green-600 text-white hover:bg-green-700 px-3 py-1 rounded text-sm',
|
|
title: 'ประวัติการใช้งานระบบ',
|
|
exportOptions: {
|
|
columns: ':visible'
|
|
}
|
|
}
|
|
],
|
|
language: {
|
|
url: '//cdn.datatables.net/plug-ins/1.13.6/i18n/th.json'
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
</div>
|
|
<?php include 'includes/footer.php'; ?>
|