Initial commit

This commit is contained in:
Porawit Dongwang
2026-09-16 23:20:08 +07:00
commit 0041668dbb
32577 changed files with 3687927 additions and 0 deletions
@@ -0,0 +1,67 @@
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0 text-gray-800">ระบบติดตาม (Audit Log)</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="card shadow border-0 rounded-4 mb-4">
<div class="card-header bg-white py-3">
<h6 class="m-0 font-weight-bold text-primary"><i class="fa-solid fa-list-check me-2"></i>ประวัติการใช้งานล่าสุด</h6>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-sm table-striped table-hover align-middle" id="auditTable">
<thead class="table-dark">
<tr>
<th>วัน-เวลา</th>
<th>User ID</th>
<th>Action</th>
<th>Entity Type</th>
<th>Entity ID</th>
</tr>
</thead>
<tbody>
<?php if (empty($logs)): ?>
<tr>
<td colspan="5" class="text-center py-3">ไม่มีข้อมูลการกระทำ</td>
</tr>
<?php else: ?>
<?php foreach ($logs as $log): ?>
<tr>
<td><?= date('d/m/Y H:i:s', strtotime($log['created_at'])) ?></td>
<td><?= $log['user_id'] ?></td>
<td>
<?php
$color = 'secondary';
if($log['action'] == 'CREATE') $color = 'success';
if($log['action'] == 'APPROVED') $color = 'primary';
if($log['action'] == 'REJECTED') $color = 'danger';
?>
<span class="badge bg-<?= $color ?>"><?= $log['action'] ?></span>
</td>
<td><code><?= $log['entity_type'] ?></code></td>
<td><?= $log['entity_id'] ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
<?php
$extraScripts = '
<script>
$(document).ready(function() {
if($("#auditTable tbody tr td").length > 1) {
$("#auditTable").DataTable({
"language": {
"url": "//cdn.datatables.net/plug-ins/1.13.6/i18n/th.json"
},
"order": [[ 0, "desc" ]]
});
}
});
</script>
';
?>
@@ -0,0 +1,77 @@
<!-- Theme & Language Controls -->
<div class="auth-controls">
<button class="control-btn" id="langToggleBtn" title="เปลี่ยนภาษา (Change Language)">
<i class="fa-solid fa-language"></i>
</button>
<button class="control-btn" id="themeToggleBtn" title="สลับโหมดสี (Toggle Theme)">
<i id="themeIcon" class="fa-regular fa-moon"></i>
</button>
</div>
<div class="glass-card">
<!-- Left Column: Premium Illustration -->
<div class="auth-illustration">
<!-- Logo Illustration -->
<img src="<?= BASE_URL ?>/assets/img/logo.png" alt="โลโก้กระทรวงสาธารณสุข" width="160" height="160" style="filter: drop-shadow(0 0 20px rgba(0, 102, 204, 0.2)); margin-bottom: 2rem; animation: float 10s infinite alternate ease-in-out;">
<h2 class="auth-title" style="font-size: 1.5rem;">ระบบขออนุมัติเดินทาง</h2>
<p class="auth-subtitle" style="margin-bottom: 0;">จัดการเอกสารและการอนุมัติอย่างเป็นระบบเพื่อองค์กรยุคใหม่</p>
</div>
<!-- Right Column: Login Form -->
<div class="auth-form-container">
<!-- Loading Overlay -->
<div class="auth-loading-overlay" id="loadingOverlay">
<div class="spinner"></div>
<div class="fw-semibold" style="color: var(--auth-text-main);">กำลังเข้าสู่ระบบ...</div>
</div>
<div class="text-center mb-4">
<h1 class="auth-title">ยินดีต้อนรับเข้าสู่ระบบ</h1>
<p class="auth-subtitle">ระบบขออนุมัติเดินทางประชุม-อบรม</p>
</div>
<?php if(isset($_SESSION['flash_error'])): ?>
<div class="alert alert-danger py-2 small rounded-3 border-0 shadow-sm" style="background-color: rgba(220, 53, 69, 0.1); color: #dc3545;">
<i class="fa-solid fa-circle-exclamation me-1"></i>
<?= \App\Core\Security::escape($_SESSION['flash_error']); unset($_SESSION['flash_error']); ?>
</div>
<?php endif; ?>
<form action="<?= BASE_URL ?>/login" method="POST" id="loginForm">
<input type="hidden" name="csrf_token" value="<?= $csrf_token ?>">
<div class="form-floating mb-3">
<input type="text" class="form-control" id="floatingInput" name="username" placeholder="ชื่อผู้ใช้งาน (HR)" required autofocus autocomplete="username">
<label for="floatingInput"><i class="fa-regular fa-user me-2"></i>ชื่อผู้ใช้งาน</label>
</div>
<div class="form-floating mb-4">
<input type="password" class="form-control" id="floatingPassword" name="password" placeholder="รหัสผ่าน" required autocomplete="current-password">
<label for="floatingPassword"><i class="fa-solid fa-lock me-2"></i>รหัสผ่าน</label>
</div>
<div class="d-flex justify-content-between align-items-center mb-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="rememberMe" style="border-color: var(--auth-input-border);">
<label class="form-check-label small" for="rememberMe" style="color: var(--auth-text-muted);">
จดจำฉันไว้ในระบบ
</label>
</div>
<a href="#" class="text-decoration-none small" style="color: var(--auth-btn-bg); font-weight: 500;">ลืมรหัสผ่าน?</a>
</div>
<button class="btn-auth w-100 d-flex justify-content-center align-items-center" type="submit" id="submitBtn">
<span>เข้าสู่ระบบ</span>
<i class="fa-solid fa-arrow-right ms-2 opacity-75"></i>
</button>
</form>
<div class="text-center mt-5">
<p class="small mb-0" style="color: var(--auth-text-muted);">
© <?= date('Y') ?> ระบบจัดการภายในองค์กร สงวนลิขสิทธิ์
</p>
</div>
</div>
</div>
@@ -0,0 +1,274 @@
<div class="d-flex justify-content-end mb-4">
<a href="<?= BASE_URL ?>/trip/create" class="btn btn-primary btn-lg shadow-sm rounded-pill fw-bold">
<i class="fa-solid fa-plus me-2"></i>สร้างคำขอใหม่
</a>
</div>
<div class="row">
<!-- Total Requests Card -->
<div class="col-xl-3 col-md-6 mb-4">
<div class="card border-0 border-start border-4 border-primary shadow-sm rounded-4 h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">คำขอทั้งหมด (ของคุณ)</div>
<div class="h5 mb-0 font-weight-bold text-gray-800"><?= number_format($stats['total_requests']) ?></div>
</div>
<div class="col-auto">
<i class="fa-solid fa-file-lines fa-2x text-black-50 opacity-25"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Pending Approval Card -->
<div class="col-xl-3 col-md-6 mb-4">
<div class="card border-0 border-start border-4 border-warning shadow-sm rounded-4 h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">รอการอนุมัติ</div>
<div class="h5 mb-0 font-weight-bold text-gray-800"><?= number_format($stats['pending_approval']) ?></div>
</div>
<div class="col-auto">
<i class="fa-solid fa-clock fa-2x text-black-50 opacity-25"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Approved Card -->
<div class="col-xl-3 col-md-6 mb-4">
<div class="card border-0 border-start border-4 border-success shadow-sm rounded-4 h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">อนุมัติแล้ว</div>
<div class="h5 mb-0 font-weight-bold text-gray-800"><?= number_format($stats['approved']) ?></div>
</div>
<div class="col-auto">
<i class="fa-solid fa-check-circle fa-2x text-black-50 opacity-25"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Rejected Card -->
<div class="col-xl-3 col-md-6 mb-4">
<div class="card border-0 border-start border-4 border-danger shadow-sm rounded-4 h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-danger text-uppercase mb-1">ไม่อนุมัติ/ยกเลิก</div>
<div class="h5 mb-0 font-weight-bold text-gray-800"><?= number_format($stats['rejected']) ?></div>
</div>
<div class="col-auto">
<i class="fa-solid fa-xmark-circle fa-2x text-black-50 opacity-25"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row mt-4">
<div class="col-lg-8">
<div class="card shadow-sm mb-4 border-0 rounded-4">
<div class="card-header py-3 bg-white d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">รายการคำขอ (ปี <?= $selectedYear + 543 ?>)</h6>
<form method="GET" class="d-inline-block">
<div class="input-group input-group-sm">
<label class="input-group-text border-0 bg-light">เลือกปี</label>
<select name="year" class="form-select form-select-sm border-light" onchange="this.form.submit()">
<?php foreach ($availableYears as $y): ?>
<option value="<?= $y ?>" <?= $y == $selectedYear ? 'selected' : '' ?>>ปี <?= $y + 543 ?></option>
<?php endforeach; ?>
</select>
</div>
</form>
</div>
<div class="card-body">
<?php if (empty($recentRequests)): ?>
<p class="text-center text-muted my-5">ยังไม่มีรายการคำขอในปีนี้</p>
<?php else: ?>
<div class="table-responsive">
<table class="table table-hover align-middle" id="dashboardTable">
<thead class="table-light">
<tr>
<th>วันที่ขอ</th>
<th>เลขที่หนังสือ</th>
<th>เรื่อง / สถานที่</th>
<th>สถานะ</th>
<th>จัดการ</th>
</tr>
</thead>
<tbody>
<?php foreach ($recentRequests as $req): ?>
<tr>
<td data-order="<?= strtotime($req['created_at']) ?>"><?= date('d/m/Y', strtotime($req['created_at'])) ?></td>
<td><?= \App\Core\Security::escape($req['doc_number'] ?: '-') ?></td>
<td>
<strong><?= \App\Core\Security::escape($req['title']) ?></strong><br>
<small class="text-muted"><i class="fa-solid fa-location-dot"></i> <?= \App\Core\Security::escape($req['location']) ?></small>
</td>
<td>
<?php if($req['status'] === 'Pending'): ?>
<span class="badge bg-warning text-dark">รออนุมัติ</span>
<?php elseif($req['status'] === 'Approved'): ?>
<span class="badge bg-success">อนุมัติแล้ว</span>
<?php elseif($req['status'] === 'Rejected'): ?>
<span class="badge bg-danger">ไม่อนุมัติ</span>
<?php else: ?>
<span class="badge bg-secondary"><?= $req['status'] ?></span>
<?php endif; ?>
</td>
<td>
<div class="btn-group btn-group-sm">
<?php if ($req['status'] === 'Approved'): ?>
<a href="<?= BASE_URL ?>/trip/print?id=<?= $req['id'] ?>" target="_blank" class="btn btn-outline-secondary" title="พิมพ์เอกสาร">
<i class="fa-solid fa-print"></i>
</a>
<button type="button" class="btn btn-outline-warning" title="ขอเปลี่ยนแปลงกำหนดการ" data-bs-toggle="modal" data-bs-target="#reviseModal<?= $req['id'] ?>">
<i class="fa-solid fa-pen"></i>
</button>
<button type="button" class="btn btn-outline-danger" title="ขอยกเลิกการเดินทาง" data-bs-toggle="modal" data-bs-target="#cancelModal<?= $req['id'] ?>">
<i class="fa-solid fa-ban"></i>
</button>
<!-- Modal for Revision Request -->
<div class="modal fade" id="reviseModal<?= $req['id'] ?>" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content text-start">
<form action="<?= BASE_URL ?>/trip/request-revise" method="POST">
<input type="hidden" name="csrf_token" value="<?= $csrf_token ?>">
<input type="hidden" name="id" value="<?= $req['id'] ?>">
<div class="modal-header bg-warning text-dark">
<h5 class="modal-title">ขอเปลี่ยนแปลงกำหนดการ</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p>คุณกำลังขอเปลี่ยนแปลงกำหนดการสำหรับ: <strong><?= \App\Core\Security::escape($req['title']) ?></strong></p>
<div class="mb-3">
<label class="form-label text-danger">ระบุรายละเอียดที่เปลี่ยนแปลง *</label>
<textarea class="form-control" name="revise_reason" rows="4" required placeholder="เช่น ขอเลื่อนวันเดินทางเป็นวันที่ 10-12 ต.ค. เนื่องจากผู้จัดเลื่อนกำหนดการ..."></textarea>
</div>
<div class="alert alert-info small">
<i class="fa-solid fa-circle-info"></i> คำขอนี้จะถูกส่งกลับไปให้ผู้อนุมัติพิจารณาการเปลี่ยนแปลงอีกครั้ง
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">ปิด</button>
<button type="submit" class="btn btn-warning"><i class="fa-solid fa-paper-plane me-1"></i> ส่งคำขอเปลี่ยนแปลง</button>
</div>
</form>
</div>
</div>
</div>
<!-- Modal for Cancellation Request -->
<div class="modal fade" id="cancelModal<?= $req['id'] ?>" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content text-start">
<form action="<?= BASE_URL ?>/trip/request-cancel" method="POST">
<input type="hidden" name="csrf_token" value="<?= $csrf_token ?>">
<input type="hidden" name="id" value="<?= $req['id'] ?>">
<div class="modal-header bg-danger text-white">
<h5 class="modal-title">ขอยกเลิกการเดินทาง</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p>คุณกำลังขอยกเลิกรายการ: <strong><?= \App\Core\Security::escape($req['title']) ?></strong></p>
<div class="mb-3">
<label class="form-label text-danger">เหตุผลที่ขอยกเลิก *</label>
<textarea class="form-control" name="cancel_reason" rows="3" required placeholder="เช่น ผู้จัดประกาศยกเลิกงาน หรือ ติดภารกิจด่วน"></textarea>
</div>
<div class="alert alert-warning small">
<i class="fa-solid fa-circle-info"></i> คำขอนี้จะถูกส่งกลับไปให้ผู้อนุมัติพิจารณาการยกเลิกอีกครั้ง
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">ปิด</button>
<button type="submit" class="btn btn-danger"><i class="fa-solid fa-paper-plane me-1"></i> ส่งคำขอยกเลิก</button>
</div>
</form>
</div>
</div>
</div>
<?php else: ?>
<button class="btn btn-outline-secondary" title="พิมพ์ได้เมื่ออนุมัติแล้วเท่านั้น" disabled>
<i class="fa-solid fa-print"></i>
</button>
<?php endif; ?>
<?php if ($req['status'] === 'Pending'): ?>
<a href="<?= BASE_URL ?>/trip/edit?id=<?= $req['id'] ?>" class="btn btn-outline-primary" title="แก้ไข">
<i class="fa-solid fa-pen-to-square"></i>
</a>
<?php endif; ?>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card shadow-sm mb-4 border-0 rounded-4">
<div class="card-header py-3 bg-white d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">สถิติ (Chart)</h6>
</div>
<div class="card-body">
<canvas id="myPieChart"></canvas>
</div>
</div>
</div>
</div>
<?php
// Adding extra script for Chart.js and DataTables
$extraScripts = '
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
// Initialize DataTables
if ($("#dashboardTable").length > 0) {
$("#dashboardTable").DataTable({
"language": {
"url": "//cdn.datatables.net/plug-ins/1.13.6/i18n/th.json"
},
"order": [[0, "desc"]], // เรียงจากวันที่ขอล่าสุด
"pageLength": 10 // แสดง 10 รายการต่อหน้า
});
}
var ctx = document.getElementById("myPieChart");
var myPieChart = new Chart(ctx, {
type: "doughnut",
data: {
labels: ["รออนุมัติ", "อนุมัติ", "ไม่อนุมัติ"],
datasets: [{
data: [' . $stats['pending_approval'] . ', ' . $stats['approved'] . ', ' . $stats['rejected'] . '],
backgroundColor: ["#ffc107", "#198754", "#dc3545"],
hoverBackgroundColor: ["#e0a800", "#157347", "#c82333"],
hoverBorderColor: "rgba(234, 236, 244, 1)",
}],
},
options: {
maintainAspectRatio: false,
cutout: "70%",
plugins: {
legend: {
position: "bottom"
}
}
},
});
});
</script>
';
?>
@@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>เกิดข้อผิดพลาด - ระบบขออนุมัติเดินทาง</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Sarabun:wght@300;400;500;600&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Sarabun', sans-serif;
background-color: #f4f6f9;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.error-container {
max-width: 500px;
width: 100%;
}
.error-icon {
font-size: 5rem;
color: #dc3545;
}
</style>
</head>
<body>
<div class="container text-center error-container">
<div class="card shadow border-0 rounded-4">
<div class="card-body p-5">
<i class="fa-solid fa-triangle-exclamation error-icon mb-4"></i>
<h2 class="fw-bold mb-3">โอ๊ะโอ! เกิดข้อผิดพลาด</h2>
<p class="text-muted mb-4">
<?= isset($error_message) ? htmlspecialchars($error_message) : 'เกิดข้อผิดพลาดในระบบ โปรดติดต่อผู้ดูแลระบบ' ?>
</p>
<div class="d-grid gap-2">
<a href="<?= isset($_SERVER['HTTP_REFERER']) ? htmlspecialchars($_SERVER['HTTP_REFERER']) : '/' ?>" class="btn btn-primary py-2">
<i class="fa-solid fa-arrow-rotate-left me-2"></i>กลับไปหน้าก่อนหน้า
</a>
<a href="/" class="btn btn-outline-secondary py-2">
<i class="fa-solid fa-house me-2"></i>กลับไปหน้าหลัก
</a>
</div>
</div>
</div>
<p class="text-muted mt-4 small">© <?= date('Y') ?> ระบบขออนุมัติเดินทางไปราชการ/ประชุม/อบรม</p>
</div>
</body>
</html>
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="th" dir="ltr" data-bs-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>เข้าสู่ระบบ | ระบบขออนุมัติเดินทางประชุม-อบรม</title>
<!-- Favicon -->
<link rel="shortcut icon" href="<?= BASE_URL ?>/assets/img/logo.png" type="image/png">
<!-- Google Fonts (Inter) -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<!-- Bootstrap 5 CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Font Awesome -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<!-- Custom Auth CSS -->
<link rel="stylesheet" href="<?= BASE_URL ?>/assets/css/auth.css?v=<?= time() ?>">
</head>
<body>
<!-- Particle Background Canvas -->
<canvas id="particleCanvas"></canvas>
<!-- Animated Gradient Background Elements -->
<div class="bg-shape shape-1"></div>
<div class="bg-shape shape-2"></div>
<div class="bg-shape shape-3"></div>
<!-- Main Content -->
<div class="auth-wrapper">
<?= $content ?>
</div>
<!-- Bootstrap 5 JS Bundle -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<!-- Custom Auth JS -->
<script src="<?= BASE_URL ?>/assets/js/auth.js?v=<?= time() ?>"></script>
</body>
</html>
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>เข้าสู่ระบบ | ระบบขออนุมัติเดินทางประชุม-อบรม</title>
<!-- Bootstrap 5 CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Font Awesome -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<!-- Google Fonts (Sarabun) -->
<link href="https://fonts.googleapis.com/css2?family=Sarabun:wght@300;400;500;600&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Sarabun', sans-serif;
background-color: #f4f6f9;
}
</style>
</head>
<body class="d-flex align-items-center py-4 bg-body-tertiary" style="min-height: 100vh;">
<?= $content ?>
<!-- Bootstrap 5 JS Bundle -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
@@ -0,0 +1,148 @@
<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ระบบขออนุมัติเดินทางประชุม-อบรม</title>
<!-- Bootstrap 5 CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Font Awesome -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<!-- Google Fonts (Sarabun & Inter) -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Sarabun:wght@300;400;500;600&display=swap" rel="stylesheet">
<!-- Premium Theme Styles -->
<link rel="stylesheet" href="<?= BASE_URL ?>/assets/css/premium.css?v=<?= time() ?>">
<style>
body {
font-family: 'Sarabun', sans-serif;
background-color: #f4f6f9;
}
.navbar-brand {
font-weight: 600;
}
.main-content {
padding: 2rem 0;
min-height: calc(100vh - 140px);
}
.footer {
background-color: #fff;
border-top: 1px solid #e9ecef;
padding: 1rem 0;
text-align: center;
}
</style>
</head>
<body>
<!-- Anti-FOUC Script for Premium Theme -->
<script>
if (localStorage.getItem('app_premium_theme') === 'true') {
document.body.setAttribute('data-premium-theme', 'true');
}
</script>
<!-- Navbar -->
<nav class="navbar navbar-expand-lg navbar-dark bg-primary shadow-sm">
<div class="container">
<a class="navbar-brand" href="<?= BASE_URL ?>/">
<i class="fa-solid fa-plane-departure me-2"></i>ระบบขอเดินทาง-อบรม
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto">
<li class="nav-item">
<a class="nav-link active" href="<?= BASE_URL ?>/"><i class="fa-solid fa-house me-1"></i>หน้าแรก</a>
</li>
<li class="nav-item">
<a class="nav-link" href="<?= BASE_URL ?>/trip/create"><i class="fa-solid fa-plus me-1"></i>ขออนุมัติเดินทาง</a>
</li>
<li class="nav-item">
<a class="nav-link" href="<?= BASE_URL ?>/trip/approvals"><i class="fa-solid fa-check-to-slot me-1"></i>พิจารณาอนุมัติ</a>
</li>
<li class="nav-item">
<a class="nav-link" href="<?= BASE_URL ?>/report"><i class="fa-solid fa-chart-pie me-1"></i>รายงานสรุป</a>
</li>
<li class="nav-item">
<a class="nav-link" href="<?= BASE_URL ?>/reports"><i class="fa-solid fa-file-excel me-1"></i>รายงาน</a>
</li>
<li class="nav-item">
<a class="nav-link" href="<?= BASE_URL ?>/audit"><i class="fa-solid fa-list-check me-1"></i>ประวัติการใช้งาน</a>
</li>
<li class="nav-item">
<a class="nav-link text-info" href="<?= BASE_URL ?>/manual"><i class="fa-solid fa-book-open me-1"></i>คู่มือ</a>
</li>
</ul>
<ul class="navbar-nav ms-auto">
<?php
$roleIcon = 'fa-user-circle';
$roles = $_SESSION['roles'] ?? [];
if (in_array('Admin', $roles)) {
$roleIcon = 'fa-user-shield text-danger';
} elseif (in_array('Approver_L2', $roles) || in_array('Approver_L1', $roles)) {
$roleIcon = 'fa-user-tie text-primary';
}
$display_name = $_SESSION['fullname'] ?? 'ผู้ใช้งาน';
?>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button" data-bs-toggle="dropdown">
<i class="fa-solid <?= $roleIcon ?> me-1"></i> <?= htmlspecialchars($display_name) ?>
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item" href="<?= BASE_URL ?>/settings"><i class="fa-solid fa-gear me-2"></i>ตั้งค่าระบบ</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item text-danger" href="<?= BASE_URL ?>/logout"><i class="fa-solid fa-sign-out-alt me-2"></i>ออกจากระบบ</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<!-- Main Content -->
<div class="container main-content">
<!-- Error/Success Messages Placeholder -->
<?php if(isset($_SESSION['flash_success'])): ?>
<div class="alert alert-success alert-dismissible fade show">
<?= \App\Core\Security::escape($_SESSION['flash_success']); unset($_SESSION['flash_success']); ?>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<?php endif; ?>
<?php if(isset($_SESSION['flash_error'])): ?>
<div class="alert alert-danger alert-dismissible fade show">
<?= \App\Core\Security::escape($_SESSION['flash_error']); unset($_SESSION['flash_error']); ?>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<?php endif; ?>
<?= $content ?>
</div>
<!-- Footer -->
<footer class="footer">
<div class="container">
<span class="text-muted">© <?= date('Y') ?> ระบบขออนุมัติเดินทางไปราชการ/ประชุม/อบรม</span>
</div>
</footer>
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<!-- Bootstrap 5 JS Bundle -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<!-- DataTables (Optional default) -->
<link href="https://cdn.datatables.net/1.13.6/css/dataTables.bootstrap5.min.css" rel="stylesheet">
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.13.6/js/dataTables.bootstrap5.min.js"></script>
<!-- Optional custom scripts pushed from views -->
<?php if(isset($extraScripts)) echo $extraScripts; ?>
<!-- Premium Theme Logic -->
<script src="<?= BASE_URL ?>/assets/js/premium.js?v=<?= time() ?>"></script>
</body>
</html>
@@ -0,0 +1,293 @@
<!-- Hero Banner -->
<div class="card shadow-sm border-0 mb-4 bg-primary text-white overflow-hidden" style="border-radius: 15px;">
<div class="card-body p-4 p-md-5 position-relative">
<div class="position-absolute top-0 end-0 opacity-10 pt-3 pe-3">
<i class="fa-solid fa-book-open-reader fa-10x"></i>
</div>
<div class="position-relative" style="z-index: 1;">
<h2 class="fw-bold mb-2">คู่มือการใช้งานระบบ</h2>
<p class="lead mb-0 opacity-75">ศูนย์รวมคำแนะนำและขั้นตอนการใช้งานสำหรับทุกระดับสิทธิ์</p>
</div>
</div>
</div>
<div class="row">
<!-- Sidebar Navigation -->
<div class="col-lg-3 mb-4">
<div class="card shadow-sm border-0" style="border-radius: 15px;">
<div class="card-header bg-white py-3 border-bottom-0 pt-4">
<h6 class="m-0 font-weight-bold text-muted text-uppercase" style="letter-spacing: 1px; font-size: 0.85rem;">หมวดหมู่คู่มือ</h6>
</div>
<div class="card-body p-0">
<div class="list-group list-group-flush" id="manual-tab" role="tablist" style="border-bottom-left-radius: 15px; border-bottom-right-radius: 15px; overflow: hidden;">
<a class="list-group-item list-group-item-action active p-3 border-0" id="list-user-list" data-bs-toggle="list" href="#list-user" role="tab">
<div class="d-flex align-items-center">
<div class="bg-primary bg-opacity-10 text-primary rounded-circle d-flex align-items-center justify-content-center me-3" style="width: 40px; height: 40px;">
<i class="fa-solid fa-user"></i>
</div>
<div>
<h6 class="mb-0 fw-bold">ผู้ใช้ทั่วไป</h6>
<small class="opacity-75">การขอเดินทางและติดตาม</small>
</div>
</div>
</a>
<a class="list-group-item list-group-item-action p-3 border-0" id="list-approver-list" data-bs-toggle="list" href="#list-approver" role="tab">
<div class="d-flex align-items-center">
<div class="bg-warning bg-opacity-10 text-warning rounded-circle d-flex align-items-center justify-content-center me-3" style="width: 40px; height: 40px;">
<i class="fa-solid fa-user-tie"></i>
</div>
<div>
<h6 class="mb-0 fw-bold">ผู้อนุมัติ</h6>
<small class="opacity-75">การพิจารณาคำขอ</small>
</div>
</div>
</a>
<?php if ($isAdmin): ?>
<a class="list-group-item list-group-item-action p-3 border-0" id="list-admin-list" data-bs-toggle="list" href="#list-admin" role="tab">
<div class="d-flex align-items-center">
<div class="bg-danger bg-opacity-10 text-danger rounded-circle d-flex align-items-center justify-content-center me-3" style="width: 40px; height: 40px;">
<i class="fa-solid fa-user-shield"></i>
</div>
<div>
<h6 class="mb-0 fw-bold">ผู้ดูแลระบบ</h6>
<small class="opacity-75">การตั้งค่าและจัดการระบบ</small>
</div>
</div>
</a>
<?php endif; ?>
</div>
</div>
</div>
</div>
<!-- Main Content Area -->
<div class="col-lg-9">
<div class="card shadow-sm border-0 mb-4" style="border-radius: 15px;">
<div class="card-body p-4 p-lg-5">
<div class="tab-content" id="nav-tabContent">
<!-- ส่วนของผู้ใช้ทั่วไป -->
<div class="tab-pane fade show active" id="list-user" role="tabpanel">
<div class="d-flex align-items-center mb-4 pb-3 border-bottom">
<i class="fa-solid fa-user fa-2x text-primary me-3"></i>
<h4 class="fw-bold mb-0">คู่มือสำหรับผู้ใช้งานทั่วไป</h4>
</div>
<div class="row g-4">
<div class="col-md-6">
<div class="card h-100 border-0 bg-light rounded-4">
<div class="card-body p-4">
<div class="mb-3">
<span class="badge bg-primary px-3 py-2 rounded-pill"><i class="fa-solid fa-pen me-1"></i> ขั้นตอนที่ 1</span>
</div>
<h5 class="fw-bold text-dark">การสร้างคำขอเดินทาง</h5>
<p class="text-muted small mb-3">คุณสามารถสร้างคำขอใหม่ได้จากเมนู <strong>"ขออนุมัติเดินทาง"</strong> หรือหน้าแดชบอร์ด</p>
<ul class="text-muted small ps-3 mb-0">
<li class="mb-2">กรอกรายละเอียดสถานที่ วันที่ และ <strong class="text-primary">แหล่งงบประมาณ</strong> ให้ครบถ้วน</li>
<li class="mb-2">สามารถแจกแจง <strong class="text-primary">รายละเอียดค่าใช้จ่าย</strong> (ค่าที่พัก, ค่าเบี้ยเลี้ยง, ค่าพาหนะ, ค่าลงทะเบียน) ได้ในระบบ</li>
<li class="mb-2">เมื่อสร้างคำขอสำเร็จ ระบบจะสร้าง <strong class="text-success">"เลขที่หนังสือเดินทาง"</strong> (เช่น พ.ศ./Running) ให้อัตโนมัติ</li>
<li>ระบบจะส่งคำขอให้ผู้อนุมัติของคุณโดยอัตโนมัติ ตามที่ Admin ตั้งค่าไว้</li>
</ul>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card h-100 border-0 bg-light rounded-4">
<div class="card-body p-4">
<div class="mb-3">
<span class="badge bg-info px-3 py-2 rounded-pill"><i class="fa-solid fa-magnifying-glass me-1"></i> ขั้นตอนที่ 2</span>
</div>
<h5 class="fw-bold text-dark">การติดตามสถานะและรายงาน</h5>
<p class="text-muted small mb-3">ตรวจสอบสถานะได้ที่ <strong>"แดชบอร์ด"</strong> และดูสถิติที่ <strong>"รายงานสรุป"</strong></p>
<div class="d-flex align-items-center mb-2">
<span class="badge bg-warning text-dark me-2" style="width: 70px;">รออนุมัติ</span>
<small class="text-muted">กำลังรอพิจารณา (สามารถแก้ไขได้)</small>
</div>
<div class="d-flex align-items-center mb-2">
<span class="badge bg-success me-2" style="width: 70px;">อนุมัติแล้ว</span>
<small class="text-muted">คลิก <i class="fa-solid fa-print mx-1"></i> เพื่อพิมพ์แบบฟอร์ม</small>
</div>
<div class="d-flex align-items-center mb-2">
<span class="badge bg-danger me-2" style="width: 70px;">ไม่อนุมัติ</span>
<small class="text-muted">คำขอถูกปฏิเสธ ดูหมายเหตุได้</small>
</div>
<hr class="my-2">
<small class="text-muted d-block"><i class="fa-solid fa-chart-pie me-1 text-primary"></i> <strong>รายงานสรุป:</strong> สามารถเลือกกรองสถิติตามปี พ.ศ. และ Export เป็น CSV ได้</small>
</div>
</div>
</div>
</div>
<div class="row g-4 mt-1">
<div class="col-12">
<div class="card border-0 bg-light rounded-4 shadow-sm">
<div class="card-body p-4">
<div class="mb-3">
<span class="badge bg-danger px-3 py-2 rounded-pill"><i class="fa-solid fa-ban me-1"></i> ขั้นตอนพิเศษ (กรณีมีการเปลี่ยนแปลงหน้างาน)</span>
</div>
<h5 class="fw-bold text-dark">การขอยกเลิก / ขอเปลี่ยนแปลงกำหนดการ</h5>
<p class="text-muted small mb-3">เมื่อคำขอได้รับการ <strong>"อนุมัติแล้ว"</strong> แต่มีการเปลี่ยนแปลงจากผู้จัดงาน คุณสามารถดำเนินการเพิ่มเติมได้จากหน้าแดชบอร์ด:</p>
<ul class="text-muted small ps-3 mb-0">
<li class="mb-2"><strong>ขอยกเลิก:</strong> กดปุ่มไอคอน <i class="fa-solid fa-ban text-danger mx-1"></i> พร้อมระบุเหตุผล (เช่น ผู้จัดประกาศยกเลิกงาน)</li>
<li class="mb-2"><strong>ขอเปลี่ยนแปลง:</strong> กดปุ่มไอคอน <i class="fa-solid fa-pen text-warning mx-1"></i> พร้อมระบุรายละเอียดที่เปลี่ยนแปลง (เช่น ขอเลื่อนวันเดินทาง)</li>
<li><span class="text-danger fw-bold">สำคัญ:</span> คำขอดังกล่าวจะถูกเปลี่ยนสถานะเป็น <span class="badge bg-danger">ขอยกเลิก</span> หรือ <span class="badge bg-warning text-dark">ขอเปลี่ยนแปลง</span> และจะถูกส่งกลับไปให้ <strong>ผู้อนุมัติ</strong> พิจารณาอีกครั้ง</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<!-- ส่วนของผู้อนุมัติ -->
<div class="tab-pane fade" id="list-approver" role="tabpanel">
<div class="d-flex align-items-center mb-4 pb-3 border-bottom">
<i class="fa-solid fa-user-tie fa-2x text-warning me-3"></i>
<h4 class="fw-bold mb-0">คู่มือสำหรับผู้อนุมัติ</h4>
</div>
<div class="card border-0 bg-warning bg-opacity-10 rounded-4 mb-4">
<div class="card-body p-4">
<h5 class="fw-bold text-warning-emphasis"><i class="fa-regular fa-bell me-2"></i> การรับการแจ้งเตือน</h5>
<p class="text-muted small mb-0">
เมื่อมีคำขอที่ต้องให้คุณพิจารณา ระบบจะส่งการแจ้งเตือนไปหาคุณ (หากองค์กรของคุณเปิดใช้งาน LINE หรือ Telegram) หรือคุณสามารถหมั่นเข้ามาตรวจสอบได้ที่เมนู <strong>"พิจารณาอนุมัติ"</strong>
</p>
</div>
</div>
<h5 class="fw-bold mt-4"><i class="fa-solid fa-list-check text-warning me-2"></i> ขั้นตอนการอนุมัติเอกสาร</h5>
<div class="timeline mt-3 px-3 border-start border-3 border-warning ms-2">
<div class="position-relative mb-4 ps-4">
<div class="position-absolute bg-warning rounded-circle" style="width: 12px; height: 12px; left: -8px; top: 5px;"></div>
<h6 class="fw-bold">1. เปิดรายการคำขอ</h6>
<p class="text-muted small">ไปที่เมนูพิจารณาอนุมัติ และคลิกปุ่ม <span class="badge bg-primary">พิจารณา</span> ที่รายการที่ต้องการ</p>
</div>
<div class="position-relative mb-4 ps-4">
<div class="position-absolute bg-warning rounded-circle" style="width: 12px; height: 12px; left: -8px; top: 5px;"></div>
<h6 class="fw-bold">2. ตรวจสอบข้อมูล</h6>
<p class="text-muted small">ระบบจะแสดงหน้าต่าง (Modal) ให้คุณตรวจสอบสถานที่ วันที่ และงบประมาณโดยละเอียด</p>
</div>
<div class="position-relative ps-4">
<div class="position-absolute bg-warning rounded-circle" style="width: 12px; height: 12px; left: -8px; top: 5px;"></div>
<h6 class="fw-bold">3. บันทึกผล</h6>
<p class="text-muted small mb-0">คุณสามารถระบุ <strong>"หมายเหตุ"</strong> เพื่อสื่อสารกับผู้ขอได้ จากนั้นคลิกปุ่ม <span class="text-success fw-bold">อนุมัติ</span> หรือ <span class="text-danger fw-bold">ไม่อนุมัติ</span></p>
</div>
</div>
</div>
<!-- ส่วนของผู้ดูแลระบบ -->
<?php if ($isAdmin): ?>
<div class="tab-pane fade" id="list-admin" role="tabpanel">
<div class="d-flex align-items-center mb-4 pb-3 border-bottom">
<i class="fa-solid fa-user-shield fa-2x text-danger me-3"></i>
<h4 class="fw-bold mb-0">คู่มือสำหรับผู้ดูแลระบบ (Admin)</h4>
</div>
<div class="alert alert-danger bg-danger bg-opacity-10 border-0 text-danger-emphasis rounded-4 mb-4" role="alert">
<i class="fa-solid fa-lock me-2"></i> เนื้อหาส่วนนี้จะแสดงผลให้เฉพาะผู้ที่มีสิทธิ์ Admin เท่านั้น
</div>
<!-- Accordion for Admin Manual -->
<div class="accordion accordion-flush" id="adminManualAccordion">
<!-- Item 1 -->
<div class="accordion-item border-0 mb-3 bg-light rounded-4 overflow-hidden">
<h2 class="accordion-header">
<button class="accordion-button collapsed bg-transparent fw-bold text-dark shadow-none" type="button" data-bs-toggle="collapse" data-bs-target="#adminCollapseOne">
<i class="fa-solid fa-users-gear text-info me-3"></i> 1. การจัดการสิทธิ์ (Roles) และสายงานอนุมัติ
</button>
</h2>
<div id="adminCollapseOne" class="accordion-collapse collapse" data-bs-parent="#adminManualAccordion">
<div class="accordion-body text-muted small pt-0 pb-4">
<ul>
<li class="mb-2"><strong>จัดการสิทธิ์:</strong> ไปที่หน้าตั้งค่า > จัดการสิทธิ์ เพื่อพิมพ์ค้นหาชื่อพนักงาน และมอบหมาย Role เช่น Admin หรือ Approver</li>
<li><strong>สายงานอนุมัติ:</strong> ไปที่หน้าตั้งค่า > สายงานอนุมัติ
<ul class="mt-1">
<li>สามารถ <strong>ค้นหาชื่อ-สกุล</strong> ของพนักงานและผู้อนุมัติจากฐานข้อมูล HR ได้โดยตรง</li>
<li>สามารถกดปุ่ม <i class="fa-solid fa-trash text-danger"></i> ลบรายการรายบุคคลออกจากตารางได้ทันที</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
<!-- Item 2 -->
<div class="accordion-item border-0 mb-3 bg-light rounded-4 overflow-hidden">
<h2 class="accordion-header">
<button class="accordion-button collapsed bg-transparent fw-bold text-dark shadow-none" type="button" data-bs-toggle="collapse" data-bs-target="#adminCollapseTwo">
<i class="fa-solid fa-file-pdf text-danger me-3"></i> 2. การออกแบบฟอร์ม PDF ต้นฉบับ
</button>
</h2>
<div id="adminCollapseTwo" class="accordion-collapse collapse" data-bs-parent="#adminManualAccordion">
<div class="accordion-body text-muted small pt-0 pb-4">
<p class="mb-2">เมนู <strong>"ฟอร์ม PDF ต้นฉบับ"</strong> ในหน้าตั้งค่าระบบ ใช้สำหรับสร้างเอกสารฟอร์มใบปะหน้า</p>
<ul>
<li class="mb-1">อัปโหลดไฟล์ PDF เปล่าที่เป็นฟอร์มขององค์กร</li>
<li class="mb-1">ลาก (Drag) แท็กตัวแปรต่างๆ จากแถบด้านซ้าย ไปวางทับพิกัดบนฟอร์ม PDF ให้ตรงช่อง (Drop)</li>
<li class="mb-1">กดบันทึกพิกัด เมื่อผู้ใช้งานสั่งพิมพ์ ระบบจะนำพิกัดเหล่านี้ไปวางทับใน PDF อัตโนมัติ</li>
<li><span class="text-primary fw-bold">ใหม่!</span> เพิ่มตัวแปร <code class="text-info">{trip_running_number}</code> สำหรับแสดงเลขที่หนังสือเดินทาง และ <code class="text-info">{current_date}</code> สำหรับวันที่พิมพ์เอกสารปัจจุบัน</li>
</ul>
</div>
</div>
</div>
<!-- Item 3 -->
<div class="accordion-item border-0 mb-3 bg-light rounded-4 overflow-hidden">
<h2 class="accordion-header">
<button class="accordion-button collapsed bg-transparent fw-bold text-dark shadow-none" type="button" data-bs-toggle="collapse" data-bs-target="#adminCollapseThree">
<i class="fa-solid fa-bell text-success me-3"></i> 3. การเชื่อมต่อและระบบแจ้งเตือน
</button>
</h2>
<div id="adminCollapseThree" class="accordion-collapse collapse" data-bs-parent="#adminManualAccordion">
<div class="accordion-body text-muted small pt-0 pb-4">
<ul>
<li class="mb-2"><strong>Google Sheets:</strong> ตั้งค่าดึงข้อมูลจากไฟล์ Spreadsheet ภายนอกเข้าสู่ระบบผ่าน API หรือ Public Link</li>
<li class="mb-2"><strong>LINE Notify:</strong> นำ Token ของ LINE Notify มากรอกเพื่อให้ระบบแจ้งเตือนเข้ากลุ่ม LINE</li>
<li><strong>Telegram:</strong> ระบุ Bot Token และ Chat ID สำหรับรับการแจ้งเตือนทาง Telegram</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
</div>
<style>
/* Custom Styling for the Manual Page */
.list-group-item.active {
background-color: transparent !important;
color: #0d6efd !important;
font-weight: 600;
border-left: 4px solid #0d6efd !important;
}
.list-group-item.active .bg-opacity-10 {
background-color: #0d6efd !important;
color: white !important;
}
.accordion-button:not(.collapsed) {
color: inherit;
background-color: transparent;
box-shadow: none;
}
.timeline {
position: relative;
}
.timeline::before {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 14px;
width: 3px;
background: #ffc107;
opacity: 0.3;
}
</style>
@@ -0,0 +1,237 @@
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0 text-gray-800">รายงานสรุป (Summary Reports)</h1>
<div class="d-flex gap-2">
<select class="form-select form-select-sm shadow-sm" id="yearFilter" onchange="window.location.href='<?= BASE_URL ?>/report?year='+this.value">
<?php
$currentCE = date('Y');
for($i = 0; $i <= 3; $i++) {
$yearCE = $currentCE - $i;
$yearBE = $yearCE + 543;
$selected = (isset($filterYear) && $filterYear == $yearCE) ? 'selected' : '';
echo "<option value='{$yearCE}' {$selected}>ปี พ.ศ. {$yearBE}</option>";
}
?>
</select>
<a href="<?= BASE_URL ?>/report/export?year=<?= isset($filterYear) ? $filterYear : date('Y') ?>" class="btn btn-sm btn-success shadow-sm">
<i class="fas fa-download fa-sm text-white-50"></i> Export to CSV
</a>
</div>
</div>
<!-- Content Row -->
<div class="row">
<!-- Total Trips -->
<div class="col-xl-3 col-md-6 mb-4">
<div class="card border-0 border-start border-4 border-primary shadow-sm rounded-4 h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">จำนวนการขอเดินทาง (ปีนี้)</div>
<div class="h5 mb-0 font-weight-bold text-gray-800"><?= number_format($totalTrips) ?> ครั้ง</div>
</div>
<div class="col-auto">
<i class="fas fa-calendar fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Total Budget -->
<div class="col-xl-3 col-md-6 mb-4">
<div class="card border-0 border-start border-4 border-success shadow-sm rounded-4 h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">งบประมาณที่อนุมัติแล้ว (ปีนี้)</div>
<div class="h5 mb-0 font-weight-bold text-gray-800">฿<?= number_format($totalBudget, 2) ?></div>
</div>
<div class="col-auto">
<i class="fas fa-money-bill-wave fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Pending Requests -->
<div class="col-xl-3 col-md-6 mb-4">
<div class="card border-0 border-start border-4 border-warning shadow-sm rounded-4 h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">รอการอนุมัติ (Pending)</div>
<div class="h5 mb-0 font-weight-bold text-gray-800"><?= number_format($pendingCount) ?> รายการ</div>
</div>
<div class="col-auto">
<i class="fas fa-clock fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Rejected Requests -->
<div class="col-xl-3 col-md-6 mb-4">
<div class="card border-0 border-start border-4 border-danger shadow-sm rounded-4 h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-danger text-uppercase mb-1">ไม่อนุมัติ (Rejected)</div>
<div class="h5 mb-0 font-weight-bold text-gray-800"><?= number_format($rejectedCount) ?> รายการ</div>
</div>
<div class="col-auto">
<i class="fas fa-times-circle fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<!-- Area Chart -->
<div class="col-xl-8 col-lg-7">
<div class="card shadow-sm border-0 rounded-4 mb-4">
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">สถิติการใช้งบประมาณรายเดือน</h6>
</div>
<div class="card-body">
<div class="chart-area">
<canvas id="myAreaChart"></canvas>
</div>
</div>
</div>
</div>
<!-- Pie Chart -->
<div class="col-xl-4 col-lg-5">
<div class="card shadow-sm border-0 rounded-4 mb-4">
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">สัดส่วนสถานะการอนุมัติ</h6>
</div>
<div class="card-body">
<div class="chart-pie pt-4 pb-2">
<canvas id="myPieChart"></canvas>
</div>
<div class="mt-4 text-center small">
<span class="mr-2"><i class="fas fa-circle text-success"></i> อนุมัติแล้ว</span>
<span class="mr-2"><i class="fas fa-circle text-warning"></i> รอพิจารณา</span>
<span class="mr-2"><i class="fas fa-circle text-danger"></i> ไม่อนุมัติ</span>
</div>
</div>
</div>
</div>
</div>
<!-- Recent Trips Table -->
<div class="card shadow-sm border-0 rounded-4 mb-4 overflow-hidden">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">ประวัติรายการเดินทางล่าสุด</h6>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
<thead>
<tr>
<th>เลขที่หนังสือเดินทาง</th>
<th>ชื่อเรื่อง</th>
<th>สถานที่</th>
<th>วันที่เดินทาง</th>
<th>งบประมาณ</th>
<th>สถานะ</th>
</tr>
</thead>
<tbody>
<?php foreach ($recentTrips as $trip): ?>
<tr>
<td><?= htmlspecialchars($trip['trip_running_number'] ?? '-') ?></td>
<td><?= htmlspecialchars($trip['title']) ?></td>
<td><?= htmlspecialchars($trip['location']) ?></td>
<td><?= date('d/m/Y', strtotime($trip['start_date'])) ?></td>
<td><?= number_format($trip['budget'], 2) ?></td>
<td>
<?php if ($trip['status'] === 'Approved'): ?>
<span class="badge bg-success">อนุมัติแล้ว</span>
<?php elseif ($trip['status'] === 'Rejected'): ?>
<span class="badge bg-danger">ไม่อนุมัติ</span>
<?php else: ?>
<span class="badge bg-warning text-dark">รอพิจารณา</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<?php
$extraScripts = '
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
// Area Chart (Budget per month)
var ctxArea = document.getElementById("myAreaChart");
var monthlyData = ' . json_encode($monthlyBudget) . ';
var myLineChart = new Chart(ctxArea, {
type: "line",
data: {
labels: ["ม.ค.", "ก.พ.", "มี.ค.", "เม.ย.", "พ.ค.", "มิ.ย.", "ก.ค.", "ส.ค.", "ก.ย.", "ต.ค.", "พ.ย.", "ธ.ค."],
datasets: [{
label: "งบประมาณ (บาท)",
lineTension: 0.3,
backgroundColor: "rgba(78, 115, 223, 0.05)",
borderColor: "rgba(78, 115, 223, 1)",
pointRadius: 3,
pointBackgroundColor: "rgba(78, 115, 223, 1)",
pointBorderColor: "rgba(78, 115, 223, 1)",
pointHoverRadius: 3,
pointHoverBackgroundColor: "rgba(78, 115, 223, 1)",
pointHoverBorderColor: "rgba(78, 115, 223, 1)",
pointHitRadius: 10,
pointBorderWidth: 2,
data: monthlyData,
}],
},
options: {
maintainAspectRatio: false,
layout: { padding: { left: 10, right: 25, top: 25, bottom: 0 } },
scales: { x: { grid: { display: false, drawBorder: false } }, y: { ticks: { maxTicksLimit: 5, padding: 10 }, grid: { color: "rgb(234, 236, 244)", zeroLineColor: "rgb(234, 236, 244)", drawBorder: false, borderDash: [2], zeroLineBorderDash: [2] } } },
plugins: { legend: { display: false } }
}
});
// Pie Chart (Status)
var ctxPie = document.getElementById("myPieChart");
var myPieChart = new Chart(ctxPie, {
type: "doughnut",
data: {
labels: ["อนุมัติแล้ว", "รอพิจารณา", "ไม่อนุมัติ"],
datasets: [{
data: [' . $approvedCount . ', ' . $pendingCount . ', ' . $rejectedCount . '],
backgroundColor: ["#1cc88a", "#f6c23e", "#e74a3b"],
hoverBackgroundColor: ["#17a673", "#dda20a", "#e02d1b"],
hoverBorderColor: "rgba(234, 236, 244, 1)",
}],
},
options: {
maintainAspectRatio: false,
plugins: { legend: { display: false } },
cutout: "80%",
},
});
// DataTable
$("#dataTable").DataTable({
"language": {
"url": "//cdn.datatables.net/plug-ins/1.13.6/i18n/th.json"
},
"order": [[2, "desc"]]
});
});
</script>
';
?>
@@ -0,0 +1,36 @@
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0 text-gray-800">ระบบรายงาน</h1>
</div>
<div class="row">
<div class="col-md-4">
<div class="card shadow border-0 mb-4 h-100 rounded-4">
<div class="card-body text-center p-5">
<i class="fa-solid fa-file-excel fa-4x text-success mb-3"></i>
<h4 class="card-title fw-bold">สรุปการเดินทางทั้งหมด</h4>
<p class="card-text text-muted mb-4">
ส่งออกข้อมูลคำขอเดินทางทั้งหมดในรูปแบบไฟล์ Excel (CSV)
</p>
<a href="<?= BASE_URL ?>/reports/export" class="btn btn-outline-success px-4 rounded-pill" target="_blank">
<i class="fa-solid fa-download me-1"></i> ดาวน์โหลด Excel
</a>
</div>
</div>
</div>
<!-- Placeholder for more reports -->
<div class="col-md-4">
<div class="card shadow border-0 mb-4 h-100 rounded-4 opacity-50">
<div class="card-body text-center p-5">
<i class="fa-solid fa-chart-bar fa-4x text-primary mb-3"></i>
<h4 class="card-title fw-bold">รายงานแยกตามหน่วยงาน</h4>
<p class="card-text text-muted mb-4">
(เร็วๆ นี้) สรุปงบประมาณและจำนวนครั้งที่เดินทาง แยกตามแผนก
</p>
<button class="btn btn-outline-primary px-4" disabled>
<i class="fa-solid fa-eye me-1"></i> ดูรายงาน
</button>
</div>
</div>
</div>
</div>
@@ -0,0 +1,134 @@
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0 text-gray-800">จัดการสิทธิ์ผู้ใช้งาน (Roles)</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">
<!-- ฟอร์มเพิ่มสิทธิ์ -->
<div class="col-lg-4">
<div class="card shadow-sm border-0 rounded-4 mb-4 overflow-hidden">
<div class="card-header bg-primary text-white py-3">
<h6 class="m-0 font-weight-bold"><i class="fa-solid fa-user-plus me-2"></i>มอบสิทธิ์ให้ผู้ใช้</h6>
</div>
<div class="card-body">
<form action="<?= BASE_URL ?>/roles/assign" method="POST">
<input type="hidden" name="csrf_token" value="<?= $csrf_token ?>">
<div class="mb-3">
<label class="form-label fw-bold">ค้นหาผู้ใช้ (ชื่อ - นามสกุล)</label>
<select class="form-control" id="userSelect" name="user_id" required>
<option value="">-- พิมพ์ชื่อเพื่อค้นหา --</option>
</select>
<div class="form-text">ระบบจะค้นหาจากฐานข้อมูลบุคลากร (HR)</div>
</div>
<div class="mb-4">
<label class="form-label fw-bold">เลือกสิทธิ์ (Role)</label>
<select class="form-select" name="role_id" required>
<option value="">-- เลือกสิทธิ์ --</option>
<?php foreach($roles as $role): ?>
<option value="<?= $role['id'] ?>"><?= $role['name'] ?> (<?= $role['description'] ?>)</option>
<?php endforeach; ?>
</select>
</div>
<button type="submit" class="btn btn-primary w-100"><i class="fa-solid fa-check me-1"></i> มอบสิทธิ์</button>
</form>
</div>
</div>
</div>
<!-- ตารางผู้ที่มีสิทธิ์ -->
<div class="col-lg-8">
<div class="card shadow-sm border-0 rounded-4 mb-4 overflow-hidden">
<div class="card-header bg-white py-3">
<h6 class="m-0 font-weight-bold text-primary"><i class="fa-solid fa-users-gear me-2"></i>รายชื่อผู้ที่ได้รับสิทธิ์ในระบบ</h6>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered table-hover align-middle" id="rolesTable">
<thead class="table-light">
<tr>
<th>รหัส (HR_CID)</th>
<th>ชื่อ - นามสกุล</th>
<th>สิทธิ์ที่ได้รับ</th>
<th class="text-center" width="100">จัดการ</th>
</tr>
</thead>
<tbody>
<?php if(empty($assigned)): ?>
<tr>
<td colspan="4" class="text-center py-3">ยังไม่มีผู้ได้รับสิทธิ์</td>
</tr>
<?php else: ?>
<?php foreach($assigned as $a): ?>
<tr>
<td><?= $a['user_id'] ?></td>
<td><?= htmlspecialchars($a['fullname']) ?></td>
<td>
<span class="badge bg-info text-dark">
<?= htmlspecialchars($a['role_name']) ?>
</span>
<small class="text-muted d-block"><?= htmlspecialchars($a['role_desc']) ?></small>
</td>
<td class="text-center">
<form action="<?= BASE_URL ?>/roles/remove" method="POST" onsubmit="return confirm('ยืนยันการลบสิทธิ์นี้?');">
<input type="hidden" name="csrf_token" value="<?= $csrf_token ?>">
<input type="hidden" name="user_id" value="<?= $a['user_id'] ?>">
<input type="hidden" name="role_id" value="<?= $a['role_id'] ?>">
<button type="submit" class="btn btn-sm btn-outline-danger"><i class="fa-solid fa-trash"></i></button>
</form>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<?php
// เพิ่ม Select2 CSS & JS
$extraScripts = '
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/select2-bootstrap-5-theme@1.3.0/dist/select2-bootstrap-5-theme.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script>
$(document).ready(function() {
if($("#rolesTable tbody tr td").length > 1) {
$("#rolesTable").DataTable({
"language": {
"url": "//cdn.datatables.net/plug-ins/1.13.6/i18n/th.json"
}
});
}
$("#userSelect").select2({
theme: "bootstrap-5",
placeholder: "-- พิมพ์ชื่อเพื่อค้นหา --",
allowClear: true,
ajax: {
url: "'.BASE_URL.'/roles/search",
dataType: "json",
delay: 250,
data: function (params) {
return {
q: params.term
};
},
processResults: function (data) {
return {
results: data
};
},
cache: true
},
minimumInputLength: 2
});
});
</script>
';
?>
@@ -0,0 +1,154 @@
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0 text-gray-800">ตั้งค่า Google Sheets Sync</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">
<div class="col-lg-8">
<div class="card shadow-sm border-0 rounded-4 mb-4 overflow-hidden">
<div class="card-header bg-white py-3">
<h6 class="m-0 font-weight-bold text-success"><i class="fa-solid fa-plug me-2"></i>รายละเอียดการเชื่อมต่อ</h6>
</div>
<div class="card-body">
<form action="<?= BASE_URL ?>/settings/google-sheets/save" method="POST">
<input type="hidden" name="csrf_token" value="<?= $csrf_token ?>">
<div class="mb-3">
<label class="form-label fw-bold">รูปแบบการเชื่อมต่อ (Connection Type)</label>
<div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="connection_type" id="connAPI" value="API" <?= ($setting['connection_type'] ?? 'API') === 'API' ? 'checked' : '' ?>>
<label class="form-check-label" for="connAPI">ใช้ Google API Key (มาตรฐาน)</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="connection_type" id="connPublic" value="Public" <?= ($setting['connection_type'] ?? '') === 'Public' ? 'checked' : '' ?>>
<label class="form-check-label" for="connPublic">ดึงจากไฟล์ Public (ไม่ต้องใช้ API Key)</label>
</div>
</div>
</div>
<div class="mb-3">
<label class="form-label fw-bold">Spreadsheet ID</label>
<input type="text" class="form-control" name="spreadsheet_id" value="<?= htmlspecialchars($setting['spreadsheet_id'] ?? '') ?>" placeholder="เช่น 1BxiMVs0XRYFgwnTE...">
<div class="form-text">รหัส 44 ตัวอักษรที่อยู่ใน URL ของ Google Sheets</div>
</div>
<div class="mb-3" id="apiKeyContainer">
<label class="form-label fw-bold">Google API Key</label>
<input type="text" class="form-control" name="api_key" value="<?= htmlspecialchars($setting['api_key'] ?? '') ?>" placeholder="เช่น AIzaSyC...">
<div class="form-text">รหัส API Key จาก Google Cloud Console (จำเป็นสำหรับการดึงข้อมูลจริง)</div>
</div>
<div class="row mb-3">
<div class="col-md-6">
<label class="form-label fw-bold">Sheet Name</label>
<input type="text" class="form-control" name="sheet_name" value="<?= htmlspecialchars($setting['sheet_name'] ?? 'Sheet1') ?>" placeholder="เช่น Sheet1">
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Sync Range</label>
<input type="text" class="form-control" name="sync_range" value="<?= htmlspecialchars($setting['sync_range'] ?? 'A2:B') ?>" placeholder="เช่น A2:B">
</div>
</div>
<div class="mb-4">
<label class="form-label fw-bold">Column Mapping (JSON)</label>
<textarea class="form-control text-monospace" name="column_mapping" rows="4"><?= htmlspecialchars($setting['column_mapping'] ?? '{"1": "doc_number", "4": "doc_no", "5": "title", "10": "doc_date", "11": "doc_link"}') ?></textarea>
<div class="form-text">รูปแบบ JSON เพื่อแมปคอลัมน์จาก Sheet (Index 0) เข้าสู่ฐานข้อมูล</div>
</div>
<button type="submit" class="btn btn-success"><i class="fa-solid fa-save me-1"></i> บันทึกการตั้งค่า</button>
<button type="button" class="btn btn-outline-primary ms-2" id="testSyncBtn"><i class="fa-solid fa-rotate me-1"></i> ทดสอบดึงข้อมูล</button>
</form>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card shadow-sm border-0 rounded-4 bg-success text-white overflow-hidden">
<div class="card-body p-4 text-center">
<i class="fa-solid fa-cloud-arrow-down fa-3x mb-3 opacity-75"></i>
<h5>สถานะการเชื่อมต่อ</h5>
<p class="mb-0">
<?php if(!empty($setting['last_synced_at'])): ?>
<span class="badge bg-light text-success mb-2">ทำงานปกติ</span><br>
<small>ดึงข้อมูลล่าสุด: <?= date('d/m/Y H:i', strtotime($setting['last_synced_at'])) ?></small>
<?php else: ?>
<span class="badge bg-warning text-dark mb-2">ยังไม่เคยดึงข้อมูล</span>
<?php endif; ?>
</p>
</div>
</div>
<div class="card shadow-sm border-0 rounded-4 mt-4 overflow-hidden">
<div class="card-body">
<h6 class="fw-bold"><i class="fa-solid fa-circle-info text-info me-2"></i>ข้อควรระวัง</h6>
<ul class="small text-muted ps-3 mb-0">
<li class="mb-1">ต้องแชร์ Spreadsheet ให้อ่านได้ (Anyone with the link) หรือผ่าน Service Account</li>
<li class="mb-1">วันที่ใน Google Sheets ควรใช้ Format `YYYY-MM-DD` เพื่อง่ายต่อการนำเข้า MySQL</li>
<li>หากต้องการดึงอัตโนมัติ ต้องตั้ง Cron Job เรียกใช้ API Endpoint ของระบบ</li>
</ul>
</div>
</div>
</div>
</div>
<?php
$extraScripts = '
<script>
document.addEventListener("DOMContentLoaded", function() {
const connAPI = document.getElementById("connAPI");
const connPublic = document.getElementById("connPublic");
const apiKeyContainer = document.getElementById("apiKeyContainer");
function toggleApiKey() {
if (connAPI.checked) {
apiKeyContainer.style.display = "block";
} else {
apiKeyContainer.style.display = "none";
}
}
connAPI.addEventListener("change", toggleApiKey);
connPublic.addEventListener("change", toggleApiKey);
toggleApiKey(); // Initial check
});
document.getElementById("testSyncBtn").addEventListener("click", function() {
const btn = this;
btn.disabled = true;
btn.innerHTML = \'<i class="fa-solid fa-spinner fa-spin me-1"></i> กำลังทดสอบ...\';
fetch("' . BASE_URL . '/settings/google-sheets/test", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: "csrf_token=' . $csrf_token . '"
})
.then(async res => {
const text = await res.text();
try {
return JSON.parse(text);
} catch (e) {
// คืนค่า Text ดิบๆ ไปเลยเพื่อให้ User เห็นว่า Server ฟ้องว่าอะไร
throw new Error("Server ไม่ได้ตอบกลับเป็น JSON: " + text.substring(0, 100));
}
})
.then(data => {
btn.disabled = false;
btn.innerHTML = \'<i class="fa-solid fa-rotate me-1"></i> ทดสอบดึงข้อมูล\';
if (data.status === "success") {
alert("เชื่อมต่อสำเร็จ! พบข้อมูล " + data.rows + " แถว\\nตัวอย่างรายการแรก: " + JSON.stringify(data.preview));
} else {
alert("เกิดข้อผิดพลาด: " + data.message);
}
})
.catch(err => {
btn.disabled = false;
btn.innerHTML = \'<i class="fa-solid fa-rotate me-1"></i> ทดสอบดึงข้อมูล\';
alert("Error: " + err.message);
});
});
</script>
';
?>
@@ -0,0 +1,129 @@
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0 text-gray-800">ตั้งค่าสายงานอนุมัติ (Approval Hierarchy)</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">
<!-- ฟอร์มเพิ่มสายงานอนุมัติ -->
<div class="col-lg-4">
<div class="card shadow-sm border-0 rounded-4 mb-4 overflow-hidden">
<div class="card-header bg-primary text-white py-3">
<h6 class="m-0 font-weight-bold"><i class="fa-solid fa-sitemap me-2"></i>กำหนดผู้อนุมัติ</h6>
</div>
<div class="card-body">
<form action="<?= BASE_URL ?>/settings/hierarchy/add" method="POST">
<input type="hidden" name="csrf_token" value="<?= $csrf_token ?>">
<div class="mb-3">
<label class="form-label fw-bold">พนักงาน (ผู้ขออนุมัติ)</label>
<select class="form-control userSelect" name="user_id" required>
<option value="">-- พิมพ์ชื่อเพื่อค้นหาพนักงาน --</option>
</select>
</div>
<div class="mb-4">
<label class="form-label fw-bold">ผู้อนุมัติ (Approver)</label>
<select class="form-control userSelect" name="approver_id" required>
<option value="">-- พิมพ์ชื่อเพื่อค้นหาผู้อนุมัติ --</option>
</select>
</div>
<button type="submit" class="btn btn-primary w-100"><i class="fa-solid fa-save me-1"></i> บันทึกข้อมูล</button>
</form>
</div>
</div>
</div>
<!-- ตารางสายงานอนุมัติ -->
<div class="col-lg-8">
<div class="card shadow-sm border-0 rounded-4 mb-4 overflow-hidden">
<div class="card-header bg-white py-3">
<h6 class="m-0 font-weight-bold text-primary"><i class="fa-solid fa-list me-2"></i>รายชื่อสายงานอนุมัติในระบบ</h6>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered table-hover align-middle" id="hierarchyTable">
<thead class="table-light">
<tr>
<th>พนักงาน</th>
<th>ผู้อนุมัติ</th>
<th class="text-center" width="100">จัดการ</th>
</tr>
</thead>
<tbody>
<?php if (empty($hierarchy)): ?>
<tr>
<td colspan="3" class="text-center py-3">ยังไม่มีการกำหนดสายงานอนุมัติ</td>
</tr>
<?php else: ?>
<?php foreach ($hierarchy as $h): ?>
<tr>
<td>
<i class="fa-solid fa-user me-2 text-muted"></i>
<?= htmlspecialchars($h['user_name']) ?>
<small class="text-muted d-block">(<?= htmlspecialchars($h['user_id']) ?>)</small>
</td>
<td>
<i class="fa-solid fa-user-check me-2 text-success"></i>
<?= htmlspecialchars($h['approver_name']) ?>
<small class="text-muted d-block">(<?= htmlspecialchars($h['approver_id']) ?>)</small>
</td>
<td class="text-center">
<form action="<?= BASE_URL ?>/settings/hierarchy/remove" method="POST" onsubmit="return confirm('ยืนยันการลบข้อมูลนี้?');">
<input type="hidden" name="csrf_token" value="<?= $csrf_token ?>">
<input type="hidden" name="id" value="<?= $h['id'] ?>">
<button type="submit" class="btn btn-sm btn-outline-danger"><i class="fa-solid fa-trash"></i></button>
</form>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<?php
// เพิ่ม Select2 CSS & JS
$extraScripts = '
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/select2-bootstrap-5-theme@1.3.0/dist/select2-bootstrap-5-theme.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script>
$(document).ready(function() {
if($("#hierarchyTable tbody tr td").length > 1) {
$("#hierarchyTable").DataTable({
"language": {
"url": "//cdn.datatables.net/plug-ins/1.13.6/i18n/th.json"
}
});
}
$(".userSelect").select2({
theme: "bootstrap-5",
allowClear: true,
ajax: {
url: "'.BASE_URL.'/settings/search-user",
dataType: "json",
delay: 250,
data: function (params) {
return {
q: params.term
};
},
processResults: function (data) {
return {
results: data
};
},
cache: true
},
minimumInputLength: 2
});
});
</script>
';
?>
@@ -0,0 +1,136 @@
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0 text-gray-800">ตั้งค่าระบบ</h1>
</div>
<div class="row">
<!-- Roles Management Card -->
<div class="col-md-4 mb-4">
<div class="card shadow-sm border-0 h-100 rounded-4">
<div class="card-body text-center p-5 d-flex flex-column">
<i class="fa-solid fa-users-gear fa-4x text-info mb-3"></i>
<h4 class="card-title fw-bold">จัดการสิทธิ์ (Roles)</h4>
<p class="card-text text-muted mb-4">
กำหนดสิทธิ์ผู้ใช้งาน เช่น ผู้ดูแลระบบ, ผู้อนุมัติระดับ 1, 2
</p>
<a href="<?= BASE_URL ?>/roles" class="btn btn-outline-info px-4 mt-auto">
<i class="fa-solid fa-user-plus me-1"></i> จัดการสิทธิ์
</a>
</div>
</div>
</div>
<!-- PDF Template Setup Card -->
<div class="col-md-4 mb-4">
<div class="card shadow-sm border-0 h-100 rounded-4">
<div class="card-body text-center p-5 d-flex flex-column">
<i class="fa-solid fa-file-pdf fa-4x text-danger mb-3"></i>
<h4 class="card-title fw-bold">ฟอร์ม PDF ต้นฉบับ</h4>
<p class="card-text text-muted mb-4">
ออกแบบและจัดวางตำแหน่งข้อมูลบนฟอร์ม PDF ด้วยระบบลากวาง (Drag & Drop)
</p>
<a href="<?= BASE_URL ?>/settings/pdf-designer" class="btn btn-outline-danger px-4 mt-auto">
<i class="fa-solid fa-pen-ruler me-1"></i> เข้าสู่หน้าออกแบบ
</a>
</div>
</div>
</div>
<!-- Google Sheets Setup Card -->
<div class="col-md-4 mb-4">
<div class="card shadow-sm border-0 h-100 rounded-4">
<div class="card-body text-center p-5 d-flex flex-column">
<i class="fa-solid fa-table fa-4x text-success mb-3"></i>
<h4 class="card-title fw-bold">Google Sheets Integration</h4>
<p class="card-text text-muted mb-4">
ตั้งค่าการเชื่อมต่อ API ของ Google Sheets เพี่อซิงค์ข้อมูลลงฐานข้อมูล กำหนด Column Mapping และ Range ของข้อมูล
</p>
<a href="<?= BASE_URL ?>/settings/google-sheets" class="btn btn-outline-success px-4 mt-auto">
<i class="fa-solid fa-plug me-1"></i> ตั้งค่าการเชื่อมต่อ
</a>
</div>
</div>
</div>
<!-- Approval Hierarchy Card -->
<div class="col-md-4 mb-4">
<div class="card shadow-sm border-0 h-100 rounded-4">
<div class="card-body text-center p-5 d-flex flex-column">
<i class="fa-solid fa-sitemap fa-4x text-warning mb-3"></i>
<h4 class="card-title fw-bold">สายงานอนุมัติ</h4>
<p class="card-text text-muted mb-4">
ตั้งค่าผู้อนุมัติสำหรับพนักงานแต่ละคน เพื่อให้ระบบส่งเอกสารไปยังผู้อนุมัติได้โดยอัตโนมัติ
</p>
<a href="<?= BASE_URL ?>/settings/hierarchy" class="btn btn-outline-warning px-4 mt-auto">
<i class="fa-solid fa-users me-1"></i> ตั้งค่าผู้อนุมัติ
</a>
</div>
</div>
</div>
<!-- LINE Notify Card -->
<div class="col-md-4 mb-4">
<div class="card shadow-sm border-0 h-100 rounded-4">
<div class="card-body text-center p-5 d-flex flex-column">
<i class="fa-brands fa-line fa-4x text-success mb-3"></i>
<h4 class="card-title fw-bold">แจ้งเตือน (LINE)</h4>
<p class="card-text text-muted mb-4">
ตั้งค่า Token ของ LINE Notify เพื่อให้ระบบสามารถส่งข้อความแจ้งเตือนเมื่อมีคำขอหรือมีการอนุมัติ
</p>
<a href="<?= BASE_URL ?>/settings/line-notify" class="btn btn-outline-success px-4 mt-auto">
<i class="fa-solid fa-bell me-1"></i> ตั้งค่าแจ้งเตือน
</a>
</div>
</div>
</div>
<!-- Telegram Notify Card -->
<div class="col-md-4 mb-4">
<div class="card shadow-sm border-0 h-100 rounded-4">
<div class="card-body text-center p-5 d-flex flex-column">
<i class="fa-brands fa-telegram fa-4x text-info mb-3"></i>
<h4 class="card-title fw-bold">แจ้งเตือน (Telegram)</h4>
<p class="card-text text-muted mb-4">
เชื่อมต่อกับบอท Telegram ของคุณ เพื่อส่งข้อความแจ้งเตือนแบบเรียลไทม์
</p>
<a href="<?= BASE_URL ?>/settings/telegram-notify" class="btn btn-outline-info px-4 mt-auto">
<i class="fa-solid fa-paper-plane me-1"></i> ตั้งค่า Telegram
</a>
</div>
</div>
</div>
<!-- Appearance & Theme Setup Card -->
<div class="col-md-4 mb-4">
<div class="card shadow-sm border-0 h-100 rounded-4">
<div class="card-body text-center p-5 d-flex flex-column">
<i class="fa-solid fa-palette fa-4x text-primary mb-3"></i>
<h4 class="card-title fw-bold">ตั้งค่าความสวยงาม</h4>
<p class="card-text text-muted mb-4">
เปิดใช้งาน <strong>Premium Theme</strong> สำหรับระบบ (ดีไซน์ Glassmorphism + Animated Background)
</p>
<div class="mt-auto d-flex justify-content-center align-items-center">
<div class="form-check form-switch fs-4">
<input class="form-check-input cursor-pointer" type="checkbox" role="switch" id="premiumThemeToggle">
<label class="form-check-label fs-5 ms-2" for="premiumThemeToggle" style="cursor: pointer;">เปิดใช้งาน</label>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const themeToggle = document.getElementById('premiumThemeToggle');
// Set initial state from localStorage
if (localStorage.getItem('app_premium_theme') === 'true') {
themeToggle.checked = true;
}
// Listen for changes
themeToggle.addEventListener('change', function(e) {
if (typeof window.togglePremiumTheme === 'function') {
window.togglePremiumTheme(e.target.checked);
}
});
});
</script>
@@ -0,0 +1,65 @@
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0 text-gray-800">ตั้งค่า LINE Notify</h1>
<a href="<?= BASE_URL ?>/settings" class="btn btn-secondary"><i class="fa-solid fa-arrow-left me-1"></i> กลับ</a>
</div>
<div class="row">
<div class="col-lg-6">
<div class="card shadow border-0 mb-4">
<div class="card-header bg-white py-3">
<h6 class="m-0 font-weight-bold text-success"><i class="fa-brands fa-line me-2"></i>การเชื่อมต่อ LINE Notify</h6>
</div>
<div class="card-body">
<p class="text-muted">ระบบจะส่งการแจ้งเตือนไปยังผู้มีอำนาจพิจารณาเมื่อมีคำขอใหม่ และแจ้งเตือนผู้ขอเมื่อมีการอนุมัติ/ปฏิเสธ</p>
<form action="<?= BASE_URL ?>/settings/line-notify/save" method="POST">
<input type="hidden" name="csrf_token" value="<?= $csrf_token ?>">
<div class="mb-3">
<label class="form-label">LINE Notify Token <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="line_token" value="<?= htmlspecialchars($line_token ?? '') ?>" placeholder="กรอก Token ที่ได้จาก LINE Notify">
<div class="form-text">คุณสามารถรับ Token ได้จาก <a href="https://notify-bot.line.me/" target="_blank">LINE Notify</a></div>
</div>
<button type="submit" class="btn btn-success"><i class="fa-solid fa-save me-1"></i> บันทึกตั้งค่า</button>
<button type="button" class="btn btn-outline-primary ms-2" id="testLineBtn"><i class="fa-solid fa-paper-plane me-1"></i> ทดสอบส่งข้อความ</button>
</form>
</div>
</div>
</div>
</div>
<?php
$extraScripts = '
<script>
document.getElementById("testLineBtn").addEventListener("click", function() {
const btn = this;
btn.disabled = true;
btn.innerHTML = \'<i class="fa-solid fa-spinner fa-spin me-1"></i> กำลังทดสอบ...\';
fetch("' . BASE_URL . '/settings/line-notify/test", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: "csrf_token=' . $csrf_token . '"
})
.then(res => res.json())
.then(data => {
btn.disabled = false;
btn.innerHTML = \'<i class="fa-solid fa-paper-plane me-1"></i> ทดสอบส่งข้อความ\';
if (data.status === "success") {
alert(data.message);
} else {
alert("เกิดข้อผิดพลาด: " + data.message);
}
})
.catch(err => {
btn.disabled = false;
btn.innerHTML = \'<i class="fa-solid fa-paper-plane me-1"></i> ทดสอบส่งข้อความ\';
alert("Error: " + err.message);
});
});
</script>
';
?>
@@ -0,0 +1,419 @@
<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>
';
?>
@@ -0,0 +1,71 @@
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0 text-gray-800">ตั้งค่า Telegram Notify</h1>
<a href="<?= BASE_URL ?>/settings" class="btn btn-secondary"><i class="fa-solid fa-arrow-left me-1"></i> กลับ</a>
</div>
<div class="row">
<div class="col-lg-6">
<div class="card shadow border-0 mb-4">
<div class="card-header bg-white py-3">
<h6 class="m-0 font-weight-bold text-info"><i class="fa-brands fa-telegram me-2"></i>การเชื่อมต่อ Telegram Bot</h6>
</div>
<div class="card-body">
<p class="text-muted">ระบบจะส่งการแจ้งเตือนไปยังแชทที่ระบุเมื่อมีคำขอใหม่ หรือมีการพิจารณาอนุมัติ/ปฏิเสธ</p>
<form action="<?= BASE_URL ?>/settings/telegram-notify/save" method="POST">
<input type="hidden" name="csrf_token" value="<?= $csrf_token ?>">
<div class="mb-3">
<label class="form-label">Telegram Bot Token <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="bot_token" value="<?= htmlspecialchars($bot_token ?? '') ?>" placeholder="e.g. 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11">
<div class="form-text">รับได้จาก <a href="https://t.me/BotFather" target="_blank">@BotFather</a> ใน Telegram</div>
</div>
<div class="mb-4">
<label class="form-label">Chat ID <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="chat_id" value="<?= htmlspecialchars($chat_id ?? '') ?>" placeholder="e.g. 123456789 หรือ -100123456789">
<div class="form-text">รหัสห้องแชทที่จะให้บอทส่งข้อความไปหา</div>
</div>
<button type="submit" class="btn btn-info text-white"><i class="fa-solid fa-save me-1"></i> บันทึกตั้งค่า</button>
<button type="button" class="btn btn-outline-primary ms-2" id="testTelegramBtn"><i class="fa-solid fa-paper-plane me-1"></i> ทดสอบส่งข้อความ</button>
</form>
</div>
</div>
</div>
</div>
<?php
$extraScripts = '
<script>
document.getElementById("testTelegramBtn").addEventListener("click", function() {
const btn = this;
btn.disabled = true;
btn.innerHTML = \'<i class="fa-solid fa-spinner fa-spin me-1"></i> กำลังทดสอบ...\';
fetch("' . BASE_URL . '/settings/telegram-notify/test", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: "csrf_token=' . $csrf_token . '"
})
.then(res => res.json())
.then(data => {
btn.disabled = false;
btn.innerHTML = \'<i class="fa-solid fa-paper-plane me-1"></i> ทดสอบส่งข้อความ\';
if (data.status === "success") {
alert(data.message);
} else {
alert("เกิดข้อผิดพลาด: " + data.message);
}
})
.catch(err => {
btn.disabled = false;
btn.innerHTML = \'<i class="fa-solid fa-paper-plane me-1"></i> ทดสอบส่งข้อความ\';
alert("Error: " + err.message);
});
});
</script>
';
?>
@@ -0,0 +1,132 @@
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0 text-gray-800">พิจารณาอนุมัติ</h1>
</div>
<div class="card shadow border-0 rounded-4 mb-4">
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover align-middle" id="approvalsTable">
<thead class="table-light">
<tr>
<th>วันที่ขอ</th>
<th>เลขที่หนังสือ</th>
<th>เรื่อง</th>
<th>สถานที่</th>
<th>วันที่เดินทาง</th>
<th>สถานะ</th>
<th>จัดการ</th>
</tr>
</thead>
<tbody>
<?php if (!empty($approvals)): ?>
<?php foreach ($approvals as $row): ?>
<tr>
<td><?= date('d/m/Y', strtotime($row['created_at'])) ?></td>
<td><?= \App\Core\Security::escape($row['doc_number'] ?: '-') ?></td>
<td>
<strong><?= \App\Core\Security::escape($row['title']) ?></strong>
<div class="small text-muted text-truncate" style="max-width: 250px;">
<?= \App\Core\Security::escape($row['objective']) ?>
</div>
</td>
<td><?= \App\Core\Security::escape($row['location']) ?></td>
<td>
<?= date('d/m/Y', strtotime($row['start_date'])) ?>
- <?= date('d/m/Y', strtotime($row['end_date'])) ?>
</td>
<td>
<?php if ($row['req_status'] === 'Pending Cancel'): ?>
<span class="badge bg-danger"><i class="fa-solid fa-ban me-1"></i> ขอยกเลิก</span>
<?php elseif ($row['req_status'] === 'Pending Revise'): ?>
<span class="badge bg-warning text-dark"><i class="fa-solid fa-pen me-1"></i> ขอเปลี่ยนแปลง</span>
<?php else: ?>
<span class="badge bg-info text-dark"><i class="fa-solid fa-clock me-1"></i> รอพิจารณา</span>
<?php endif; ?>
</td>
<td>
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-secondary" title="พิมพ์ได้เมื่ออนุมัติแล้วเท่านั้น" disabled>
<i class="fa-solid fa-print"></i>
</button>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#approveModal<?= $row['approval_id'] ?>">
พิจารณา
</button>
</div>
</td>
</tr>
<!-- Modal for each approval -->
<div class="modal fade" id="approveModal<?= $row['approval_id'] ?>" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<form action="<?= BASE_URL ?>/trip/approvals/process" method="POST">
<input type="hidden" name="csrf_token" value="<?= $csrf_token ?>">
<input type="hidden" name="approval_id" value="<?= $row['approval_id'] ?>">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title">พิจารณาคำขอเดินทาง</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p><strong>เรื่อง:</strong> <?= \App\Core\Security::escape($row['title']) ?></p>
<p><strong>สถานที่:</strong> <?= \App\Core\Security::escape($row['location']) ?></p>
<p><strong>งบประมาณ:</strong> <?= number_format($row['budget'], 2) ?> บาท</p>
<?php if (!empty($row['doc_link'])): ?>
<p>
<a href="<?= \App\Core\Security::escape($row['doc_link']) ?>" target="_blank" class="btn btn-sm btn-outline-primary">
<i class="fa-solid fa-arrow-up-right-from-square me-1"></i> เปิดไฟล์เอกสาร
</a>
</p>
<?php endif; ?>
<?php if ($row['req_status'] === 'Pending Cancel'): ?>
<div class="alert alert-danger mt-3 mb-0">
<strong>เหตุผลที่ขอยกเลิก:</strong><br>
<?= nl2br(\App\Core\Security::escape($row['cancel_reason'])) ?>
</div>
<?php elseif ($row['req_status'] === 'Pending Revise'): ?>
<div class="alert alert-warning text-dark mt-3 mb-0">
<strong>รายละเอียดที่ขอเปลี่ยนแปลง:</strong><br>
<?= nl2br(\App\Core\Security::escape($row['revise_reason'])) ?>
</div>
<?php endif; ?>
<hr>
<div class="mb-3">
<label class="form-label">ความคิดเห็น (ถ้ามี)</label>
<textarea class="form-control" name="comments" rows="2" placeholder="ระบุเหตุผลการอนุมัติ/ไม่อนุมัติ"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="submit" name="action" value="reject" class="btn btn-danger">ไม่อนุมัติ</button>
<button type="submit" name="action" value="approve" class="btn btn-success"><i class="fa-solid fa-check me-1"></i> อนุมัติ</button>
</div>
</form>
</div>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
<?php
$extraScripts = '
<script>
$(document).ready(function() {
$("#approvalsTable").DataTable({
"language": {
"url": "//cdn.datatables.net/plug-ins/1.13.6/i18n/th.json",
"emptyTable": "ไม่มีรายการรออนุมัติ"
},
"order": [[0, "desc"]],
"pageLength": 10
});
});
</script>
';
?>
@@ -0,0 +1,592 @@
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0 text-gray-800">ขออนุมัติเดินทางไปราชการ/ประชุม</h1>
<a href="<?= BASE_URL ?>/" class="btn btn-outline-secondary shadow-sm"><i class="fa-solid fa-arrow-left me-1"></i> กลับ</a>
</div>
<div class="card shadow border-0 rounded-4 mb-5">
<div class="card-body p-4 p-md-5">
<form action="<?= BASE_URL ?>/trip/create" method="POST" id="tripForm">
<input type="hidden" name="csrf_token" value="<?= $csrf_token ?>">
<!-- ส่วนที่ 1: ข้อมูลหนังสือ -->
<h5 class="fw-bold mb-4 text-primary border-bottom pb-2"><i class="fa-solid fa-file-lines me-2"></i>อ้างถึงหนังสือ</h5>
<div class="row mb-4">
<div class="col-md-5 mb-3 mb-md-0">
<label class="form-label">เลขอ้างอิงหนังสือ</label>
<div class="input-group">
<select class="form-select" id="doc_year" style="max-width: 120px;">
<?php
$currentYearBE = date('Y') + 543;
echo '<option value="'.$currentYearBE.'">ปี '.$currentYearBE.'</option>';
echo '<option value="'.($currentYearBE - 1).'">ปี '.($currentYearBE - 1).'</option>';
?>
</select>
<input type="text" class="form-control" name="doc_number" id="doc_number" placeholder="เลขอ้างอิง (เช่น 123)">
<button class="btn btn-outline-primary" type="button" id="btnSearchDoc"><i class="fa-solid fa-magnifying-glass"></i> ค้นหา</button>
</div>
<div class="form-text text-muted small"><i class="fa-solid fa-circle-info"></i> ระบบจะค้นหาเลขอ้างอิงจากปีที่เลือก</div>
</div>
<div class="col-md-4 mb-3 mb-md-0">
<label class="form-label">เลขที่หนังสือ</label>
<input type="text" class="form-control" name="doc_no" id="doc_no" placeholder="เช่น ศธ 1234/567">
</div>
<div class="col-md-3">
<label class="form-label">ลงวันที่</label>
<input type="date" class="form-control" name="doc_date" id="doc_date">
</div>
</div>
<input type="hidden" name="doc_link" id="doc_link" value="">
<!-- ส่วนที่ 2: ข้อมูลการประชุม/ไปราชการ -->
<h5 class="fw-bold mb-4 text-primary border-bottom pb-2 mt-5"><i class="fa-solid fa-briefcase me-2"></i>รายละเอียดการเดินทาง</h5>
<div class="mb-4">
<label class="form-label text-danger">เรื่อง *</label>
<input type="text" class="form-control" name="title" id="title" required placeholder="หัวข้อการประชุมหรือเรื่องที่ไปราชการ">
</div>
<div class="row mb-4">
<div class="col-md-4 mb-3 mb-md-0">
<label class="form-label">ประเภทบุคลากร</label>
<select class="form-select" name="personnel_type">
<option value="ข้าราชการ">ข้าราชการ</option>
<option value="ลูกจ้างประจำ">ลูกจ้างประจำ</option>
<option value="พนักงานราชการ">พนักงานราชการ</option>
<option value="พนักงานกระทรวงฯ">พนักงานกระทรวงฯ</option>
<option value="ลูกจ้างชั่วคราว">ลูกจ้างชั่วคราว</option>
</select>
</div>
<div class="col-md-4 mb-3 mb-md-0">
<label class="form-label text-danger">วันที่เริ่มต้น *</label>
<input type="date" class="form-control" name="start_date" required>
</div>
<div class="col-md-4">
<label class="form-label text-danger">วันที่สิ้นสุด *</label>
<input type="date" class="form-control" name="end_date" required>
</div>
</div>
<div class="row mb-4">
<div class="col-md-6 mb-3 mb-md-0">
<label class="form-label text-danger">สถานที่ *</label>
<input type="text" class="form-control" name="location" list="locationList" required placeholder="สถานที่จัดงาน / จังหวัด">
<datalist id="locationList">
<?php foreach($locations as $loc): ?>
<option value="<?= htmlspecialchars($loc) ?>">
<?php endforeach; ?>
</datalist>
</div>
<div class="col-md-6">
<label class="form-label">ผู้จัด</label>
<input type="text" class="form-control" name="organizer" list="organizerList" placeholder="ระบุหน่วยงานที่จัด">
<datalist id="organizerList">
<?php foreach($organizers as $org): ?>
<option value="<?= htmlspecialchars($org) ?>">
<?php endforeach; ?>
</datalist>
</div>
</div>
<div class="mb-4">
<label class="form-label text-danger">วัตถุประสงค์ (เหตุผลที่ต้องไป) *</label>
<textarea class="form-control" name="objective" rows="2" required placeholder="ระบุเหตุผลและวัตถุประสงค์ในการเดินทาง"></textarea>
</div>
<!-- ส่วนที่ 3: กำหนดการเดินทาง (ไป-กลับ) -->
<h5 class="fw-bold mb-4 text-primary border-bottom pb-2 mt-5"><i class="fa-solid fa-route me-2"></i>กำหนดการเดินทาง</h5>
<!-- ขาไป -->
<div class="card bg-light border-0 mb-4">
<div class="card-body">
<h6 class="fw-bold mb-3">โดยเดินทางออกจาก</h6>
<div class="row g-3">
<div class="col-md-3">
<div class="form-check mb-2">
<input class="form-check-input" type="radio" name="depart_from" id="df1" value="สำนักงาน" checked>
<label class="form-check-label" for="df1">สำนักงาน</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" name="depart_from" id="df2" value="บ้านพัก">
<label class="form-check-label" for="df2">บ้านพัก</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" name="depart_from" id="df3" value="อื่นๆ">
<label class="form-check-label" for="df3">อื่นๆ (ระบุที่อยู่)</label>
</div>
</div>
<div class="col-md-5">
<label class="form-label small">ประเทศไทย เลขที่ / ตำบล</label>
<select class="form-select form-select-sm tambon-select" data-target="depart_address">
<option value="">-- เลือกตำบล --</option>
<option value="อ่างทอง">อ่างทอง</option>
<option value="ลิปะน้อย">ลิปะน้อย</option>
<option value="ตลิ่งงาม">ตลิ่งงาม</option>
<option value="หน้าเมือง">หน้าเมือง</option>
<option value="มะเร็ต">มะเร็ต</option>
<option value="บ่อผุด">บ่อผุด</option>
<option value="แม่น้ำ">แม่น้ำ</option>
<option value="อื่นๆ">อื่นๆ (ระบุเอง)</option>
</select>
<input type="text" class="form-control form-control-sm mt-2 d-none" name="depart_address" id="depart_address" placeholder="ระบุที่อยู่ / ตำบลที่ต้องการ">
</div>
<div class="col-md-4">
<label class="form-label small">วันที่และเวลาออกเดินทาง</label>
<input type="datetime-local" class="form-control form-control-sm" name="depart_datetime">
</div>
</div>
</div>
</div>
<!-- ขากลับ -->
<div class="card bg-light border-0 mb-4">
<div class="card-body">
<h6 class="fw-bold mb-3">และกลับถึง</h6>
<div class="row g-3">
<div class="col-md-3">
<div class="form-check mb-2">
<input class="form-check-input" type="radio" name="arrive_at" id="ar1" value="สำนักงาน" checked>
<label class="form-check-label" for="ar1">สำนักงาน</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" name="arrive_at" id="ar2" value="บ้านพัก">
<label class="form-check-label" for="ar2">บ้านพัก</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" name="arrive_at" id="ar3" value="อื่นๆ">
<label class="form-check-label" for="ar3">อื่นๆ (ระบุที่อยู่)</label>
</div>
</div>
<div class="col-md-5">
<label class="form-label small">ประเทศไทย เลขที่ / ตำบล</label>
<select class="form-select form-select-sm tambon-select" data-target="arrive_address">
<option value="">-- เลือกตำบล --</option>
<option value="อ่างทอง">อ่างทอง</option>
<option value="ลิปะน้อย">ลิปะน้อย</option>
<option value="ตลิ่งงาม">ตลิ่งงาม</option>
<option value="หน้าเมือง">หน้าเมือง</option>
<option value="มะเร็ต">มะเร็ต</option>
<option value="บ่อผุด">บ่อผุด</option>
<option value="แม่น้ำ">แม่น้ำ</option>
<option value="อื่นๆ">อื่นๆ (ระบุเอง)</option>
</select>
<input type="text" class="form-control form-control-sm mt-2 d-none" name="arrive_address" id="arrive_address" placeholder="ระบุที่อยู่ / ตำบลที่ต้องการ">
</div>
<div class="col-md-4">
<label class="form-label small">วันที่และเวลากลับถึง</label>
<input type="datetime-local" class="form-control form-control-sm" name="arrive_datetime">
</div>
</div>
</div>
</div>
<!-- ส่วนที่ 4: พาหนะและค่าใช้จ่าย -->
<h5 class="fw-bold mb-4 text-primary border-bottom pb-2 mt-5"><i class="fa-solid fa-car me-2"></i>พาหนะ และ แหล่งงบประมาณ</h5>
<div class="row mb-4">
<div class="col-md-6 mb-3 mb-md-0">
<label class="form-label">โดยสารพาหนะ</label>
<select class="form-select" name="vehicle_type">
<option value="">-- ระบุพาหนะ --</option>
<option value="เครื่องบิน">เครื่องบิน</option>
<option value="รถยนต์ของทางราชการ">รถยนต์ของทางราชการ</option>
<option value="รถโดยสารประจำทาง">รถโดยสารประจำทาง</option>
<option value="พาหนะส่วนตัว">พาหนะส่วนตัว</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label">ทะเบียนรถ (กรณีรถส่วนตัว/รถราชการ)</label>
<input type="text" class="form-control" name="vehicle_plate" placeholder="เช่น กข 1234 สมุย">
</div>
</div>
<div class="card bg-light border-0 mb-5">
<div class="card-body">
<h6 class="fw-bold mb-3">รายละเอียดการเบิกจ่าย</h6>
<div class="row mb-4">
<div class="col-md-5 mb-3 mb-md-0">
<label class="form-label">ขอเบิกค่าใช้จ่ายในการเดินทางจาก</label>
<select class="form-select" name="budget_source" id="budget_source">
<option value="เงินบำรุง รพ.">เงินบำรุง รพ.</option>
<option value="ผู้จัดสนับสนุนทั้งหมด">ผู้จัดสนับสนุนทั้งหมด (ไม่ขอเบิก)</option>
<option value="ผู้จัดสนับสนุนบางส่วน">ผู้จัดสนับสนุนบางส่วน</option>
</select>
</div>
<div class="col-md-4 mb-3 mb-md-0 d-none" id="organizer_support_container">
<label class="form-label text-danger">ระบุจำนวนเงินที่สนับสนุน (บาท) *</label>
<input type="number" step="0.01" min="0" class="form-control" name="organizer_support_amount" id="organizer_support_amount" value="0.00">
</div>
<div class="col-md-3">
<label class="form-label">รายละเอียดเพิ่มเติม (ถ้ามี)</label>
<input type="text" class="form-control" name="budget_remark" placeholder="เช่น เบิกเฉพาะค่าที่พัก">
</div>
</div>
<div id="expense_section">
<h6 class="fw-bold mb-3 border-top pt-3">รูปแบบการประมาณการค่าใช้จ่าย</h6>
<div class="mb-3">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="budget_type" id="budget_type_lump" value="lump_sum" checked>
<label class="form-check-label" for="budget_type_lump">แบบประมาณการรวม (กรอกแค่ยอดรวม)</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="budget_type" id="budget_type_detail" value="detailed">
<label class="form-check-label" for="budget_type_detail">แบบระบุรายละเอียด</label>
</div>
</div>
<!-- แบบประมาณการรวม -->
<div id="lump_sum_container" class="mb-3">
<label class="form-label">ประมาณการค่าใช้จ่ายรวม (บาท)</label>
<div class="input-group" style="max-width: 300px;">
<span class="input-group-text">฿</span>
<input type="number" step="0.01" min="0" class="form-control calc-total" name="budget" id="budget_lump_sum" value="0.00">
</div>
</div>
<!-- แบบระบุรายละเอียด -->
<div id="detailed_expense_container" class="d-none">
<div class="row">
<!-- ค่าที่พัก -->
<div class="col-12 mb-3">
<div class="d-flex justify-content-between align-items-center mb-2">
<label class="form-label mb-0 fw-bold"><i class="fa-solid fa-bed me-1"></i> ค่าที่พัก</label>
<button type="button" class="btn btn-sm btn-outline-primary" id="add_accommodation"><i class="fa-solid fa-plus"></i> เพิ่มที่พัก</button>
</div>
<div id="accommodations_list">
<!-- Items will be generated here -->
<div class="row g-2 align-items-center mb-2 accommodation-item">
<div class="col-md-5">
<div class="input-group input-group-sm">
<span class="input-group-text">จำนวนคืน</span>
<input type="number" min="0" step="1" name="acc_days[]" class="form-control acc-days calc-trigger" placeholder="0">
</div>
</div>
<div class="col-md-5">
<div class="input-group input-group-sm">
<span class="input-group-text">ราคา/คืน</span>
<input type="number" min="0" step="0.01" name="acc_prices[]" class="form-control acc-prices calc-trigger" placeholder="0.00">
<span class="input-group-text">บาท</span>
</div>
</div>
<div class="col-md-2 text-end">
<button type="button" class="btn btn-sm btn-outline-danger btn-remove-row" disabled><i class="fa-solid fa-trash"></i></button>
</div>
</div>
</div>
</div>
<!-- ค่าเบี้ยเลี้ยง -->
<div class="col-12 mb-3">
<div class="d-flex justify-content-between align-items-center mb-2">
<label class="form-label mb-0 fw-bold"><i class="fa-solid fa-utensils me-1"></i> ค่าเบี้ยเลี้ยง</label>
<button type="button" class="btn btn-sm btn-outline-primary" id="add_allowance"><i class="fa-solid fa-plus"></i> เพิ่มเบี้ยเลี้ยง</button>
</div>
<div id="allowances_list">
<!-- Items will be generated here -->
<div class="row g-2 align-items-center mb-2 allowance-item">
<div class="col-md-5">
<div class="input-group input-group-sm">
<span class="input-group-text">จำนวนวัน</span>
<input type="number" min="0" step="0.5" name="alw_days[]" class="form-control alw-days calc-trigger" placeholder="0">
</div>
</div>
<div class="col-md-5">
<div class="input-group input-group-sm">
<span class="input-group-text">อัตรา/วัน</span>
<input type="number" min="0" step="0.01" name="alw_prices[]" class="form-control alw-prices calc-trigger" placeholder="0.00">
<span class="input-group-text">บาท</span>
</div>
</div>
<div class="col-md-2 text-end">
<button type="button" class="btn btn-sm btn-outline-danger btn-remove-row" disabled><i class="fa-solid fa-trash"></i></button>
</div>
</div>
</div>
</div>
<!-- ค่าโดยสารและค่าลงทะเบียน -->
<div class="col-md-6 mb-3">
<label class="form-label fw-bold"><i class="fa-solid fa-ticket me-1"></i> ค่าโดยสารทั้งหมด</label>
<div class="input-group input-group-sm">
<input type="number" min="0" step="0.01" name="expense_transport" id="expense_transport" class="form-control calc-trigger" placeholder="0.00">
<span class="input-group-text">บาท</span>
</div>
</div>
<div class="col-md-6 mb-3">
<label class="form-label fw-bold"><i class="fa-solid fa-address-card me-1"></i> ค่าลงทะเบียน</label>
<div class="input-group input-group-sm">
<input type="number" min="0" step="0.01" name="expense_registration" id="expense_registration" class="form-control calc-trigger" placeholder="0.00">
<span class="input-group-text">บาท</span>
</div>
</div>
<!-- สรุปยอดรวม -->
<div class="col-12 mt-3 pt-3 border-top">
<div class="d-flex justify-content-end align-items-center">
<h5 class="mb-0 me-3">รวมเป็นเงินทั้งสิ้น:</h5>
<h4 class="mb-0 text-primary fw-bold" id="detailed_total_display">0.00</h4>
<span class="ms-2">บาท</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="text-end border-top pt-4">
<button type="reset" class="btn btn-light me-2 px-4">ล้างข้อมูล</button>
<button type="submit" class="btn btn-primary px-5 shadow"><i class="fa-solid fa-paper-plane me-1"></i> เสนอขออนุมัติ</button>
</div>
</form>
</div>
</div>
<?php
$extraScripts = '
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script>
// ฟังก์ชันแปลงวันที่รูปแบบไทย/ทั่วไป เป็น YYYY-MM-DD สำหรับ input[type="date"]
function parseDateToInputFormat(dateStr) {
if (!dateStr) return "";
// ถ้ามาเป็น YYYY-MM-DD อยู่แล้วก็คืนค่าได้เลย
if (/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) return dateStr;
// ลองแยกด้วย / หรือ -
var parts = dateStr.split(/[\/\-]/);
if (parts.length === 3) {
var d = parseInt(parts[0], 10);
var m = parseInt(parts[1], 10);
var y = parseInt(parts[2], 10);
// ถ้าปีเป็น 25xx ให้แปลงเป็น ค.ศ.
if (y > 2400) y -= 543;
// ถ้าปีมาแค่ 2 หลัก (เช่น 66) ถือว่าเป็น 2566
else if (y > 50 && y < 100) y = (y + 2500) - 543;
// ถ้า d > 31 แสดงว่ามาในรูปแบบ YYYY/MM/DD
if (d > 31) {
var temp = d;
d = y;
y = temp;
}
var mm = m < 10 ? "0" + m : m;
var dd = d < 10 ? "0" + d : d;
return y + "-" + mm + "-" + dd;
}
return ""; // ถ้าแปลงไม่ได้
}
$(document).ready(function() {
// จัดการ Select ตำบลเกาะสมุย
$(".tambon-select").on("change", function() {
var targetId = $(this).data("target");
var val = $(this).val();
if (val === "อื่นๆ") {
$("#" + targetId).removeClass("d-none").val("").focus();
} else {
$("#" + targetId).addClass("d-none").val(val);
}
});
$("#btnSearchDoc").on("click", function() {
var q = $("#doc_number").val().trim();
var year = $("#doc_year").val();
if (!q) {
Swal.fire("กรุณาระบุ", "โปรดกรอกเลขที่หนังสือที่ต้องการค้นหา", "warning");
return;
}
var btn = $(this);
var originalHtml = btn.html();
btn.html(\'<i class="fa-solid fa-spinner fa-spin"></i>\').prop("disabled", true);
$.ajax({
url: "' . BASE_URL . '/trip/search-docs",
type: "GET",
dataType: "json",
data: { q: q, year: year },
success: function(res) {
btn.html(originalHtml).prop("disabled", false);
if (res.results && res.results.length > 0) {
// ดึงรายการแรกที่ตรงที่สุด
var data = res.results[0];
if (data.title) {
$("#title").val(data.title);
$("#title").addClass("is-valid");
setTimeout(() => $("#title").removeClass("is-valid"), 2000);
}
if (data.doc_no) {
$("#doc_no").val(data.doc_no);
$("#doc_no").addClass("is-valid");
setTimeout(() => $("#doc_no").removeClass("is-valid"), 2000);
}
if (data.doc_link) {
$("#doc_link").val(data.doc_link);
}
if (data.doc_date) {
var parsedDate = parseDateToInputFormat(data.doc_date);
if (parsedDate) {
$("#doc_date").val(parsedDate);
$("#doc_date").addClass("is-valid");
setTimeout(() => $("#doc_date").removeClass("is-valid"), 2000);
} else {
// ถ้าแปลงอัตโนมัติไม่ได้
Swal.fire("แจ้งเตือน", "ดึงวันที่ได้คือ \'" + data.doc_date + "\' แต่ระบบไม่สามารถจัดรูปแบบอัตโนมัติได้ กรุณาเลือกวันที่ด้วยตนเอง", "info");
}
}
Swal.fire({
icon: "success",
title: "ดึงข้อมูลสำเร็จ",
text: "พบหนังสือเรื่อง: " + (data.title || "-"),
timer: 1500,
showConfirmButton: false
});
} else {
Swal.fire("ไม่พบข้อมูล", "ไม่พบเลขที่หนังสือ \'" + q + "\' ในระบบ", "error");
}
},
error: function() {
btn.html(originalHtml).prop("disabled", false);
Swal.fire("เกิดข้อผิดพลาด", "ไม่สามารถเชื่อมต่อระบบค้นหาได้", "error");
}
});
});
// --- Expense Logic ---
function toggleExpenseUI() {
var budgetSource = $("#budget_source").val();
if (budgetSource === "ผู้จัดสนับสนุนบางส่วน") {
$("#organizer_support_container").removeClass("d-none");
} else {
$("#organizer_support_container").addClass("d-none");
$("#organizer_support_amount").val("0.00");
}
if (budgetSource === "ผู้จัดสนับสนุนทั้งหมด") {
$("#expense_section").addClass("d-none");
// clear budgets
$("#budget_lump_sum").val("0.00");
} else {
$("#expense_section").removeClass("d-none");
var budgetType = $("input[name=\'budget_type\']:checked").val();
if (budgetType === "detailed") {
$("#lump_sum_container").addClass("d-none");
$("#detailed_expense_container").removeClass("d-none");
calculateDetailedTotal();
} else {
$("#lump_sum_container").removeClass("d-none");
$("#detailed_expense_container").addClass("d-none");
}
}
}
$("#budget_source, input[name=\'budget_type\']").on("change", toggleExpenseUI);
// Add Row functions
$("#add_accommodation").click(function() {
var template = `
<div class="row g-2 align-items-center mb-2 accommodation-item">
<div class="col-md-5">
<div class="input-group input-group-sm">
<span class="input-group-text">จำนวนคืน</span>
<input type="number" min="0" step="1" name="acc_days[]" class="form-control acc-days calc-trigger" placeholder="0">
</div>
</div>
<div class="col-md-5">
<div class="input-group input-group-sm">
<span class="input-group-text">ราคา/คืน</span>
<input type="number" min="0" step="0.01" name="acc_prices[]" class="form-control acc-prices calc-trigger" placeholder="0.00">
<span class="input-group-text">บาท</span>
</div>
</div>
<div class="col-md-2 text-end">
<button type="button" class="btn btn-sm btn-outline-danger btn-remove-row"><i class="fa-solid fa-trash"></i></button>
</div>
</div>`;
$("#accommodations_list").append(template);
updateRemoveButtons("#accommodations_list");
});
$("#add_allowance").click(function() {
var template = `
<div class="row g-2 align-items-center mb-2 allowance-item">
<div class="col-md-5">
<div class="input-group input-group-sm">
<span class="input-group-text">จำนวนวัน</span>
<input type="number" min="0" step="0.5" name="alw_days[]" class="form-control alw-days calc-trigger" placeholder="0">
</div>
</div>
<div class="col-md-5">
<div class="input-group input-group-sm">
<span class="input-group-text">อัตรา/วัน</span>
<input type="number" min="0" step="0.01" name="alw_prices[]" class="form-control alw-prices calc-trigger" placeholder="0.00">
<span class="input-group-text">บาท</span>
</div>
</div>
<div class="col-md-2 text-end">
<button type="button" class="btn btn-sm btn-outline-danger btn-remove-row"><i class="fa-solid fa-trash"></i></button>
</div>
</div>`;
$("#allowances_list").append(template);
updateRemoveButtons("#allowances_list");
});
function updateRemoveButtons(listId) {
var items = $(listId).find(".btn-remove-row");
if (items.length > 1) {
items.prop("disabled", false);
} else {
items.prop("disabled", true);
}
}
$(document).on("click", ".btn-remove-row", function() {
var list = $(this).closest("div[id$=\'_list\']");
$(this).closest(".row").remove();
updateRemoveButtons("#" + list.attr("id"));
calculateDetailedTotal();
});
function calculateDetailedTotal() {
var total = 0;
// Accommodations
$(".accommodation-item").each(function() {
var days = parseFloat($(this).find(".acc-days").val()) || 0;
var price = parseFloat($(this).find(".acc-prices").val()) || 0;
total += (days * price);
});
// Allowances
$(".allowance-item").each(function() {
var days = parseFloat($(this).find(".alw-days").val()) || 0;
var price = parseFloat($(this).find(".alw-prices").val()) || 0;
total += (days * price);
});
// Transport
var transport = parseFloat($("#expense_transport").val()) || 0;
total += transport;
// Registration
var registration = parseFloat($("#expense_registration").val()) || 0;
total += registration;
$("#detailed_total_display").text(total.toLocaleString("en-US", {minimumFractionDigits: 2, maximumFractionDigits: 2}));
// Also sync it to budget_lump_sum so the backend can just read \'budget\'
$("#budget_lump_sum").val(total.toFixed(2));
}
$(document).on("input", ".calc-trigger", calculateDetailedTotal);
// Initial setup
toggleExpenseUI();
});
</script>
';
$extraStyles = '';
?>
@@ -0,0 +1,667 @@
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0 text-gray-800">แก้ไขคำขอเดินทางไปราชการ/ประชุม</h1>
<a href="<?= BASE_URL ?>/" class="btn btn-outline-secondary shadow-sm"><i class="fa-solid fa-arrow-left me-1"></i> กลับ</a>
</div>
<div class="card shadow border-0 rounded-4 mb-5">
<div class="card-body p-4 p-md-5">
<form action="<?= BASE_URL ?>/trip/edit" method="POST" id="tripForm">
<input type="hidden" name="csrf_token" value="<?= $csrf_token ?>">
<input type="hidden" name="id" value="<?= $trip['id'] ?>">
<!-- ส่วนที่ 1: ข้อมูลหนังสือ -->
<h5 class="fw-bold mb-4 text-primary border-bottom pb-2"><i class="fa-solid fa-file-lines me-2"></i>อ้างถึงหนังสือ</h5>
<div class="row mb-4">
<div class="col-md-5 mb-3 mb-md-0">
<label class="form-label">เลขอ้างอิงหนังสือ</label>
<div class="input-group">
<select class="form-select" id="doc_year" style="max-width: 120px;">
<?php
$currentYearBE = date('Y') + 543;
echo '<option value="'.$currentYearBE.'">ปี '.$currentYearBE.'</option>';
echo '<option value="'.($currentYearBE - 1).'">ปี '.($currentYearBE - 1).'</option>';
?>
</select>
<input type="text" class="form-control" name="doc_number" id="doc_number" value="<?= htmlspecialchars($trip['doc_number'] ?? '') ?>" placeholder="เลขอ้างอิง (เช่น 123)">
<button class="btn btn-outline-primary" type="button" id="btnSearchDoc"><i class="fa-solid fa-magnifying-glass"></i> ค้นหา</button>
</div>
<div class="form-text text-muted small"><i class="fa-solid fa-circle-info"></i> ระบบจะค้นหาเลขอ้างอิงจากปีที่เลือก</div>
</div>
<div class="col-md-4 mb-3 mb-md-0">
<label class="form-label">เลขที่หนังสือ</label>
<input type="text" class="form-control" name="doc_no" id="doc_no" value="<?= htmlspecialchars($trip['doc_no'] ?? '') ?>" placeholder="เช่น ศธ 1234/567">
</div>
<div class="col-md-3">
<label class="form-label">ลงวันที่</label>
<input type="date" class="form-control" name="doc_date" id="doc_date" value="<?= htmlspecialchars($trip['doc_date'] ?? '') ?>">
</div>
</div>
<input type="hidden" name="doc_link" id="doc_link" value="<?= htmlspecialchars($trip['doc_link'] ?? '') ?>">
<!-- ส่วนที่ 2: ข้อมูลการประชุม/ไปราชการ -->
<h5 class="fw-bold mb-4 text-primary border-bottom pb-2 mt-5"><i class="fa-solid fa-briefcase me-2"></i>รายละเอียดการเดินทาง</h5>
<div class="mb-4">
<label class="form-label text-danger">เรื่อง *</label>
<input type="text" class="form-control" name="title" id="title" value="<?= htmlspecialchars($trip['title'] ?? '') ?>" required placeholder="หัวข้อการประชุมหรือเรื่องที่ไปราชการ">
</div>
<div class="row mb-4">
<div class="col-md-4 mb-3 mb-md-0">
<label class="form-label">ประเภทบุคลากร</label>
<select class="form-select" name="personnel_type">
<option value="ข้าราชการ" <?= ($trip['personnel_type'] ?? '') === 'ข้าราชการ' ? 'selected' : '' ?>>ข้าราชการ</option>
<option value="ลูกจ้างประจำ" <?= ($trip['personnel_type'] ?? '') === 'ลูกจ้างประจำ' ? 'selected' : '' ?>>ลูกจ้างประจำ</option>
<option value="พนักงานราชการ" <?= ($trip['personnel_type'] ?? '') === 'พนักงานราชการ' ? 'selected' : '' ?>>พนักงานราชการ</option>
<option value="พนักงานกระทรวงฯ" <?= ($trip['personnel_type'] ?? '') === 'พนักงานกระทรวงฯ' ? 'selected' : '' ?>>พนักงานกระทรวงฯ</option>
<option value="ลูกจ้างชั่วคราว" <?= ($trip['personnel_type'] ?? '') === 'ลูกจ้างชั่วคราว' ? 'selected' : '' ?>>ลูกจ้างชั่วคราว</option>
</select>
</div>
<div class="col-md-4 mb-3 mb-md-0">
<label class="form-label text-danger">วันที่เริ่มต้น *</label>
<input type="date" class="form-control" name="start_date" value="<?= htmlspecialchars($trip['start_date'] ?? '') ?>" required>
</div>
<div class="col-md-4">
<label class="form-label text-danger">วันที่สิ้นสุด *</label>
<input type="date" class="form-control" name="end_date" value="<?= htmlspecialchars($trip['end_date'] ?? '') ?>" required>
</div>
</div>
<div class="row mb-4">
<div class="col-md-6 mb-3 mb-md-0">
<label class="form-label text-danger">สถานที่ *</label>
<input type="text" class="form-control" name="location" list="locationList" value="<?= htmlspecialchars($trip['location'] ?? '') ?>" required placeholder="สถานที่จัดงาน / จังหวัด">
<datalist id="locationList">
<?php foreach($locations as $loc): ?>
<option value="<?= htmlspecialchars($loc) ?>">
<?php endforeach; ?>
</datalist>
</div>
<div class="col-md-6">
<label class="form-label">ผู้จัด</label>
<input type="text" class="form-control" name="organizer" list="organizerList" value="<?= htmlspecialchars($trip['organizer'] ?? '') ?>" placeholder="ระบุหน่วยงานที่จัด">
<datalist id="organizerList">
<?php foreach($organizers as $org): ?>
<option value="<?= htmlspecialchars($org) ?>">
<?php endforeach; ?>
</datalist>
</div>
</div>
<div class="mb-4">
<label class="form-label text-danger">วัตถุประสงค์ (เหตุผลที่ต้องไป) *</label>
<textarea class="form-control" name="objective" rows="2" required placeholder="ระบุเหตุผลและวัตถุประสงค์ในการเดินทาง"><?= htmlspecialchars($trip['objective'] ?? '') ?></textarea>
</div>
<!-- ส่วนที่ 3: กำหนดการเดินทาง (ไป-กลับ) -->
<h5 class="fw-bold mb-4 text-primary border-bottom pb-2 mt-5"><i class="fa-solid fa-route me-2"></i>กำหนดการเดินทาง</h5>
<!-- ขาไป -->
<div class="card bg-light border-0 mb-4">
<div class="card-body">
<h6 class="fw-bold mb-3">โดยเดินทางออกจาก</h6>
<div class="row g-3">
<div class="col-md-3">
<div class="form-check mb-2">
<input class="form-check-input" type="radio" name="depart_from" id="df1" value="สำนักงาน" <?= ($trip['depart_from'] ?? '') === 'สำนักงาน' ? 'checked' : '' ?>>
<label class="form-check-label" for="df1">สำนักงาน</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" name="depart_from" id="df2" value="บ้านพัก" <?= ($trip['depart_from'] ?? '') === 'บ้านพัก' ? 'checked' : '' ?>>
<label class="form-check-label" for="df2">บ้านพัก</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" name="depart_from" id="df3" value="อื่นๆ" <?= ($trip['depart_from'] ?? '') === 'อื่นๆ' ? 'checked' : '' ?>>
<label class="form-check-label" for="df3">อื่นๆ (ระบุที่อยู่)</label>
</div>
</div>
<div class="col-md-5">
<label class="form-label small">ประเทศไทย เลขที่ / ตำบล</label>
<?php
$dtambon = $trip['depart_address'] ?? '';
$isCustomDTambon = !in_array($dtambon, ['', 'อ่างทอง', 'ลิปะน้อย', 'ตลิ่งงาม', 'หน้าเมือง', 'มะเร็ต', 'บ่อผุด', 'แม่น้ำ']);
?>
<select class="form-select form-select-sm tambon-select" data-target="depart_address">
<option value="" <?= $dtambon == '' ? 'selected' : '' ?>>-- เลือกตำบล --</option>
<option value="อ่างทอง" <?= $dtambon == 'อ่างทอง' ? 'selected' : '' ?>>อ่างทอง</option>
<option value="ลิปะน้อย" <?= $dtambon == 'ลิปะน้อย' ? 'selected' : '' ?>>ลิปะน้อย</option>
<option value="ตลิ่งงาม" <?= $dtambon == 'ตลิ่งงาม' ? 'selected' : '' ?>>ตลิ่งงาม</option>
<option value="หน้าเมือง" <?= $dtambon == 'หน้าเมือง' ? 'selected' : '' ?>>หน้าเมือง</option>
<option value="มะเร็ต" <?= $dtambon == 'มะเร็ต' ? 'selected' : '' ?>>มะเร็ต</option>
<option value="บ่อผุด" <?= $dtambon == 'บ่อผุด' ? 'selected' : '' ?>>บ่อผุด</option>
<option value="แม่น้ำ" <?= $dtambon == 'แม่น้ำ' ? 'selected' : '' ?>>แม่น้ำ</option>
<option value="อื่นๆ" <?= $isCustomDTambon ? 'selected' : '' ?>>อื่นๆ (ระบุเอง)</option>
</select>
<input type="text" class="form-control form-control-sm mt-2 <?= $isCustomDTambon ? '' : 'd-none' ?>" name="depart_address" id="depart_address" value="<?= htmlspecialchars($dtambon) ?>" placeholder="ระบุที่อยู่ / ตำบลที่ต้องการ">
</div>
<div class="col-md-4">
<label class="form-label small">วันที่และเวลาออกเดินทาง</label>
<?php
$dt = $trip['depart_datetime'] ?? '';
if ($dt) {
$dt = date('Y-m-d\TH:i', strtotime($dt));
}
?>
<input type="datetime-local" class="form-control form-control-sm" name="depart_datetime" value="<?= $dt ?>">
</div>
</div>
</div>
</div>
<!-- ขากลับ -->
<div class="card bg-light border-0 mb-4">
<div class="card-body">
<h6 class="fw-bold mb-3">และกลับถึง</h6>
<div class="row g-3">
<div class="col-md-3">
<div class="form-check mb-2">
<input class="form-check-input" type="radio" name="arrive_at" id="ar1" value="สำนักงาน" <?= ($trip['arrive_at'] ?? '') === 'สำนักงาน' ? 'checked' : '' ?>>
<label class="form-check-label" for="ar1">สำนักงาน</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" name="arrive_at" id="ar2" value="บ้านพัก" <?= ($trip['arrive_at'] ?? '') === 'บ้านพัก' ? 'checked' : '' ?>>
<label class="form-check-label" for="ar2">บ้านพัก</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" name="arrive_at" id="ar3" value="อื่นๆ" <?= ($trip['arrive_at'] ?? '') === 'อื่นๆ' ? 'checked' : '' ?>>
<label class="form-check-label" for="ar3">อื่นๆ (ระบุที่อยู่)</label>
</div>
</div>
<div class="col-md-5">
<label class="form-label small">ประเทศไทย เลขที่ / ตำบล</label>
<?php
$atambon = $trip['arrive_address'] ?? '';
$isCustomATambon = !in_array($atambon, ['', 'อ่างทอง', 'ลิปะน้อย', 'ตลิ่งงาม', 'หน้าเมือง', 'มะเร็ต', 'บ่อผุด', 'แม่น้ำ']);
?>
<select class="form-select form-select-sm tambon-select" data-target="arrive_address">
<option value="" <?= $atambon == '' ? 'selected' : '' ?>>-- เลือกตำบล --</option>
<option value="อ่างทอง" <?= $atambon == 'อ่างทอง' ? 'selected' : '' ?>>อ่างทอง</option>
<option value="ลิปะน้อย" <?= $atambon == 'ลิปะน้อย' ? 'selected' : '' ?>>ลิปะน้อย</option>
<option value="ตลิ่งงาม" <?= $atambon == 'ตลิ่งงาม' ? 'selected' : '' ?>>ตลิ่งงาม</option>
<option value="หน้าเมือง" <?= $atambon == 'หน้าเมือง' ? 'selected' : '' ?>>หน้าเมือง</option>
<option value="มะเร็ต" <?= $atambon == 'มะเร็ต' ? 'selected' : '' ?>>มะเร็ต</option>
<option value="บ่อผุด" <?= $atambon == 'บ่อผุด' ? 'selected' : '' ?>>บ่อผุด</option>
<option value="แม่น้ำ" <?= $atambon == 'แม่น้ำ' ? 'selected' : '' ?>>แม่น้ำ</option>
<option value="อื่นๆ" <?= $isCustomATambon ? 'selected' : '' ?>>อื่นๆ (ระบุเอง)</option>
</select>
<input type="text" class="form-control form-control-sm mt-2 <?= $isCustomATambon ? '' : 'd-none' ?>" name="arrive_address" id="arrive_address" value="<?= htmlspecialchars($atambon) ?>" placeholder="ระบุที่อยู่ / ตำบลที่ต้องการ">
</div>
<div class="col-md-4">
<label class="form-label small">วันที่และเวลากลับถึง</label>
<?php
$at = $trip['arrive_datetime'] ?? '';
if ($at) {
$at = date('Y-m-d\TH:i', strtotime($at));
}
?>
<input type="datetime-local" class="form-control form-control-sm" name="arrive_datetime" value="<?= $at ?>">
</div>
</div>
</div>
</div>
<!-- ส่วนที่ 4: พาหนะและค่าใช้จ่าย -->
<h5 class="fw-bold mb-4 text-primary border-bottom pb-2 mt-5"><i class="fa-solid fa-car me-2"></i>พาหนะ และ แหล่งงบประมาณ</h5>
<div class="row mb-4">
<div class="col-md-6 mb-3 mb-md-0">
<label class="form-label">โดยสารพาหนะ</label>
<select class="form-select" name="vehicle_type">
<option value="">-- ระบุพาหนะ --</option>
<option value="เครื่องบิน" <?= ($trip['vehicle_type'] ?? '') === 'เครื่องบิน' ? 'selected' : '' ?>>เครื่องบิน</option>
<option value="รถยนต์ของทางราชการ" <?= ($trip['vehicle_type'] ?? '') === 'รถยนต์ของทางราชการ' ? 'selected' : '' ?>>รถยนต์ของทางราชการ</option>
<option value="รถโดยสารประจำทาง" <?= ($trip['vehicle_type'] ?? '') === 'รถโดยสารประจำทาง' ? 'selected' : '' ?>>รถโดยสารประจำทาง</option>
<option value="พาหนะส่วนตัว" <?= ($trip['vehicle_type'] ?? '') === 'พาหนะส่วนตัว' ? 'selected' : '' ?>>พาหนะส่วนตัว</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label">ทะเบียนรถ (กรณีรถส่วนตัว/รถราชการ)</label>
<input type="text" class="form-control" name="vehicle_plate" value="<?= htmlspecialchars($trip['vehicle_plate'] ?? '') ?>" placeholder="เช่น กข 1234 สมุย">
</div>
</div>
<?php
$budgetSource = $trip['budget_source'] ?? '';
$orgSupport = $trip['organizer_support_amount'] ?? '0.00';
$budgetType = $trip['budget_type'] ?? 'lump_sum';
$budgetLump = $trip['budget'] ?? '0.00';
$accItems = json_decode($trip['expense_accommodations'] ?? '[]', true) ?: [];
$alwItems = json_decode($trip['expense_allowances'] ?? '[]', true) ?: [];
$expTransport = $trip['expense_transport'] ?? '0.00';
$expRegistration = $trip['expense_registration'] ?? '0.00';
?>
<div class="card bg-light border-0 mb-5">
<div class="card-body">
<h6 class="fw-bold mb-3">รายละเอียดการเบิกจ่าย</h6>
<div class="row mb-4">
<div class="col-md-5 mb-3 mb-md-0">
<label class="form-label">ขอเบิกค่าใช้จ่ายในการเดินทางจาก</label>
<select class="form-select" name="budget_source" id="budget_source">
<option value="เงินบำรุง รพ." <?= $budgetSource === 'เงินบำรุง รพ.' ? 'selected' : '' ?>>เงินบำรุง รพ.</option>
<option value="ผู้จัดสนับสนุนทั้งหมด" <?= $budgetSource === 'ผู้จัดสนับสนุนทั้งหมด' ? 'selected' : '' ?>>ผู้จัดสนับสนุนทั้งหมด (ไม่ขอเบิก)</option>
<option value="ผู้จัดสนับสนุนบางส่วน" <?= $budgetSource === 'ผู้จัดสนับสนุนบางส่วน' ? 'selected' : '' ?>>ผู้จัดสนับสนุนบางส่วน</option>
</select>
</div>
<div class="col-md-4 mb-3 mb-md-0 <?= $budgetSource === 'ผู้จัดสนับสนุนบางส่วน' ? '' : 'd-none' ?>" id="organizer_support_container">
<label class="form-label text-danger">ระบุจำนวนเงินที่สนับสนุน (บาท) *</label>
<input type="number" step="0.01" min="0" class="form-control" name="organizer_support_amount" id="organizer_support_amount" value="<?= htmlspecialchars($orgSupport) ?>">
</div>
<div class="col-md-3">
<label class="form-label">รายละเอียดเพิ่มเติม (ถ้ามี)</label>
<input type="text" class="form-control" name="budget_remark" value="<?= htmlspecialchars($trip['budget_remark'] ?? '') ?>" placeholder="เช่น เบิกเฉพาะค่าที่พัก">
</div>
</div>
<div id="expense_section" class="<?= $budgetSource === 'ผู้จัดสนับสนุนทั้งหมด' ? 'd-none' : '' ?>">
<h6 class="fw-bold mb-3 border-top pt-3">รูปแบบการประมาณการค่าใช้จ่าย</h6>
<div class="mb-3">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="budget_type" id="budget_type_lump" value="lump_sum" <?= $budgetType !== 'detailed' ? 'checked' : '' ?>>
<label class="form-check-label" for="budget_type_lump">แบบประมาณการรวม (กรอกแค่ยอดรวม)</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="budget_type" id="budget_type_detail" value="detailed" <?= $budgetType === 'detailed' ? 'checked' : '' ?>>
<label class="form-check-label" for="budget_type_detail">แบบระบุรายละเอียด</label>
</div>
</div>
<!-- แบบประมาณการรวม -->
<div id="lump_sum_container" class="mb-3 <?= $budgetType === 'detailed' ? 'd-none' : '' ?>">
<label class="form-label">ประมาณการค่าใช้จ่ายรวม (บาท)</label>
<div class="input-group" style="max-width: 300px;">
<span class="input-group-text">฿</span>
<input type="number" step="0.01" min="0" class="form-control calc-total" name="budget" id="budget_lump_sum" value="<?= htmlspecialchars($budgetLump) ?>">
</div>
</div>
<!-- แบบระบุรายละเอียด -->
<div id="detailed_expense_container" class="<?= $budgetType === 'detailed' ? '' : 'd-none' ?>">
<div class="row">
<!-- ค่าที่พัก -->
<div class="col-12 mb-3">
<div class="d-flex justify-content-between align-items-center mb-2">
<label class="form-label mb-0 fw-bold"><i class="fa-solid fa-bed me-1"></i> ค่าที่พัก</label>
<button type="button" class="btn btn-sm btn-outline-primary" id="add_accommodation"><i class="fa-solid fa-plus"></i> เพิ่มที่พัก</button>
</div>
<div id="accommodations_list">
<?php if(empty($accItems)): ?>
<div class="row g-2 align-items-center mb-2 accommodation-item">
<div class="col-md-5">
<div class="input-group input-group-sm">
<span class="input-group-text">จำนวนคืน</span>
<input type="number" min="0" step="1" name="acc_days[]" class="form-control acc-days calc-trigger" placeholder="0">
</div>
</div>
<div class="col-md-5">
<div class="input-group input-group-sm">
<span class="input-group-text">ราคา/คืน</span>
<input type="number" min="0" step="0.01" name="acc_prices[]" class="form-control acc-prices calc-trigger" placeholder="0.00">
<span class="input-group-text">บาท</span>
</div>
</div>
<div class="col-md-2 text-end">
<button type="button" class="btn btn-sm btn-outline-danger btn-remove-row" disabled><i class="fa-solid fa-trash"></i></button>
</div>
</div>
<?php else: ?>
<?php foreach($accItems as $index => $acc): ?>
<div class="row g-2 align-items-center mb-2 accommodation-item">
<div class="col-md-5">
<div class="input-group input-group-sm">
<span class="input-group-text">จำนวนคืน</span>
<input type="number" min="0" step="1" name="acc_days[]" class="form-control acc-days calc-trigger" value="<?= htmlspecialchars($acc['days']) ?>" placeholder="0">
</div>
</div>
<div class="col-md-5">
<div class="input-group input-group-sm">
<span class="input-group-text">ราคา/คืน</span>
<input type="number" min="0" step="0.01" name="acc_prices[]" class="form-control acc-prices calc-trigger" value="<?= htmlspecialchars($acc['price']) ?>" placeholder="0.00">
<span class="input-group-text">บาท</span>
</div>
</div>
<div class="col-md-2 text-end">
<button type="button" class="btn btn-sm btn-outline-danger btn-remove-row" <?= count($accItems) > 1 ? '' : 'disabled' ?>><i class="fa-solid fa-trash"></i></button>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
<!-- ค่าเบี้ยเลี้ยง -->
<div class="col-12 mb-3">
<div class="d-flex justify-content-between align-items-center mb-2">
<label class="form-label mb-0 fw-bold"><i class="fa-solid fa-utensils me-1"></i> ค่าเบี้ยเลี้ยง</label>
<button type="button" class="btn btn-sm btn-outline-primary" id="add_allowance"><i class="fa-solid fa-plus"></i> เพิ่มเบี้ยเลี้ยง</button>
</div>
<div id="allowances_list">
<?php if(empty($alwItems)): ?>
<div class="row g-2 align-items-center mb-2 allowance-item">
<div class="col-md-5">
<div class="input-group input-group-sm">
<span class="input-group-text">จำนวนวัน</span>
<input type="number" min="0" step="0.5" name="alw_days[]" class="form-control alw-days calc-trigger" placeholder="0">
</div>
</div>
<div class="col-md-5">
<div class="input-group input-group-sm">
<span class="input-group-text">อัตรา/วัน</span>
<input type="number" min="0" step="0.01" name="alw_prices[]" class="form-control alw-prices calc-trigger" placeholder="0.00">
<span class="input-group-text">บาท</span>
</div>
</div>
<div class="col-md-2 text-end">
<button type="button" class="btn btn-sm btn-outline-danger btn-remove-row" disabled><i class="fa-solid fa-trash"></i></button>
</div>
</div>
<?php else: ?>
<?php foreach($alwItems as $index => $alw): ?>
<div class="row g-2 align-items-center mb-2 allowance-item">
<div class="col-md-5">
<div class="input-group input-group-sm">
<span class="input-group-text">จำนวนวัน</span>
<input type="number" min="0" step="0.5" name="alw_days[]" class="form-control alw-days calc-trigger" value="<?= htmlspecialchars($alw['days']) ?>" placeholder="0">
</div>
</div>
<div class="col-md-5">
<div class="input-group input-group-sm">
<span class="input-group-text">อัตรา/วัน</span>
<input type="number" min="0" step="0.01" name="alw_prices[]" class="form-control alw-prices calc-trigger" value="<?= htmlspecialchars($alw['price']) ?>" placeholder="0.00">
<span class="input-group-text">บาท</span>
</div>
</div>
<div class="col-md-2 text-end">
<button type="button" class="btn btn-sm btn-outline-danger btn-remove-row" <?= count($alwItems) > 1 ? '' : 'disabled' ?>><i class="fa-solid fa-trash"></i></button>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
<!-- ค่าโดยสารและค่าลงทะเบียน -->
<div class="col-md-6 mb-3">
<label class="form-label fw-bold"><i class="fa-solid fa-ticket me-1"></i> ค่าโดยสารทั้งหมด</label>
<div class="input-group input-group-sm">
<input type="number" min="0" step="0.01" name="expense_transport" id="expense_transport" class="form-control calc-trigger" value="<?= htmlspecialchars($expTransport) ?>" placeholder="0.00">
<span class="input-group-text">บาท</span>
</div>
</div>
<div class="col-md-6 mb-3">
<label class="form-label fw-bold"><i class="fa-solid fa-address-card me-1"></i> ค่าลงทะเบียน</label>
<div class="input-group input-group-sm">
<input type="number" min="0" step="0.01" name="expense_registration" id="expense_registration" class="form-control calc-trigger" value="<?= htmlspecialchars($expRegistration) ?>" placeholder="0.00">
<span class="input-group-text">บาท</span>
</div>
</div>
<!-- สรุปยอดรวม -->
<div class="col-12 mt-3 pt-3 border-top">
<div class="d-flex justify-content-end align-items-center">
<h5 class="mb-0 me-3">รวมเป็นเงินทั้งสิ้น:</h5>
<h4 class="mb-0 text-primary fw-bold" id="detailed_total_display">0.00</h4>
<span class="ms-2">บาท</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="d-flex justify-content-between border-top pt-4">
<button type="button" class="btn btn-danger px-4 shadow" id="btnDeleteTrip"><i class="fa-solid fa-trash me-1"></i> ลบคำขอนี้</button>
<button type="submit" class="btn btn-primary px-5 shadow"><i class="fa-solid fa-save me-1"></i> บันทึกการแก้ไข</button>
</div>
</form>
</div>
</div>
<?php
$extraScripts = '
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script>
function parseDateToInputFormat(dateStr) {
if (!dateStr) return "";
if (/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) return dateStr;
var parts = dateStr.split(/[\/\-]/);
if (parts.length === 3) {
var d = parseInt(parts[0], 10);
var m = parseInt(parts[1], 10);
var y = parseInt(parts[2], 10);
if (y > 2400) y -= 543;
else if (y > 50 && y < 100) y = (y + 2500) - 543;
if (d > 31) {
var temp = d;
d = y;
y = temp;
}
var mm = m < 10 ? "0" + m : m;
var dd = d < 10 ? "0" + d : d;
return y + "-" + mm + "-" + dd;
}
return "";
}
$(document).ready(function() {
$(".tambon-select").on("change", function() {
var targetId = $(this).data("target");
var val = $(this).val();
if (val === "อื่นๆ") {
$("#" + targetId).removeClass("d-none").focus();
if ($("#" + targetId).val() === "อื่นๆ") $("#" + targetId).val("");
} else {
$("#" + targetId).addClass("d-none").val(val);
}
});
$("#btnSearchDoc").on("click", function() {
var q = $("#doc_number").val().trim();
var year = $("#doc_year").val();
if (!q) {
Swal.fire("กรุณาระบุ", "โปรดกรอกเลขที่หนังสือที่ต้องการค้นหา", "warning");
return;
}
var btn = $(this);
var originalHtml = btn.html();
btn.html(\'<i class="fa-solid fa-spinner fa-spin"></i>\').prop("disabled", true);
$.ajax({
url: "' . BASE_URL . '/trip/search-docs",
type: "GET",
dataType: "json",
data: { q: q, year: year },
success: function(res) {
btn.html(originalHtml).prop("disabled", false);
if (res.results && res.results.length > 0) {
var data = res.results[0];
if (data.title) {
$("#title").val(data.title);
$("#title").addClass("is-valid");
setTimeout(() => $("#title").removeClass("is-valid"), 2000);
}
if (data.doc_no) {
$("#doc_no").val(data.doc_no);
$("#doc_no").addClass("is-valid");
setTimeout(() => $("#doc_no").removeClass("is-valid"), 2000);
}
if (data.doc_link) {
$("#doc_link").val(data.doc_link);
}
if (data.doc_date) {
var parsedDate = parseDateToInputFormat(data.doc_date);
if (parsedDate) {
$("#doc_date").val(parsedDate).addClass("is-valid");
setTimeout(() => $("#doc_date").removeClass("is-valid"), 2000);
}
}
Swal.fire({
icon: "success",
title: "ดึงข้อมูลสำเร็จ",
text: "อัปเดตข้อมูลจากระบบส่วนกลางเรียบร้อย",
timer: 1500,
showConfirmButton: false
});
} else {
Swal.fire("ไม่พบข้อมูล", "ไม่พบเลขที่หนังสือ \'" + q + "\' ในระบบ", "error");
}
},
error: function() {
btn.html(originalHtml).prop("disabled", false);
Swal.fire("เกิดข้อผิดพลาด", "ไม่สามารถเชื่อมต่อระบบค้นหาได้", "error");
}
});
});
$("#btnDeleteTrip").on("click", function() {
Swal.fire({
title: "ยืนยันการลบ?",
text: "คุณต้องการลบคำขอเดินทางนี้ใช่หรือไม่? การกระทำนี้ไม่สามารถกู้คืนได้",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#d33",
cancelButtonColor: "#6c757d",
confirmButtonText: "ใช่, ลบเลย!",
cancelButtonText: "ยกเลิก"
}).then((result) => {
if (result.isConfirmed) {
var form = $("<form action=\'" . BASE_URL . "/trip/delete\' method=\'POST\'>" +
"<input type=\'hidden\' name=\'csrf_token\' value=\'" . $csrf_token . "\'>" +
"<input type=\'hidden\' name=\'id\' value=\'" . $trip['id'] . "\'>" +
"</form>");
$("body").append(form);
form.submit();
}
});
});
// --- Expense Logic ---
function toggleExpenseUI() {
var budgetSource = $("#budget_source").val();
if (budgetSource === "ผู้จัดสนับสนุนบางส่วน") {
$("#organizer_support_container").removeClass("d-none");
} else {
$("#organizer_support_container").addClass("d-none");
$("#organizer_support_amount").val("0.00");
}
if (budgetSource === "ผู้จัดสนับสนุนทั้งหมด") {
$("#expense_section").addClass("d-none");
$("#budget_lump_sum").val("0.00");
} else {
$("#expense_section").removeClass("d-none");
var budgetType = $("input[name=\'budget_type\']:checked").val();
if (budgetType === "detailed") {
$("#lump_sum_container").addClass("d-none");
$("#detailed_expense_container").removeClass("d-none");
calculateDetailedTotal();
} else {
$("#lump_sum_container").removeClass("d-none");
$("#detailed_expense_container").addClass("d-none");
}
}
}
$("#budget_source, input[name=\'budget_type\']").on("change", toggleExpenseUI);
// Add Row functions
$("#add_accommodation").click(function() {
var template = `
<div class="row g-2 align-items-center mb-2 accommodation-item">
<div class="col-md-5">
<div class="input-group input-group-sm">
<span class="input-group-text">จำนวนคืน</span>
<input type="number" min="0" step="1" name="acc_days[]" class="form-control acc-days calc-trigger" placeholder="0">
</div>
</div>
<div class="col-md-5">
<div class="input-group input-group-sm">
<span class="input-group-text">ราคา/คืน</span>
<input type="number" min="0" step="0.01" name="acc_prices[]" class="form-control acc-prices calc-trigger" placeholder="0.00">
<span class="input-group-text">บาท</span>
</div>
</div>
<div class="col-md-2 text-end">
<button type="button" class="btn btn-sm btn-outline-danger btn-remove-row"><i class="fa-solid fa-trash"></i></button>
</div>
</div>`;
$("#accommodations_list").append(template);
updateRemoveButtons("#accommodations_list");
});
$("#add_allowance").click(function() {
var template = `
<div class="row g-2 align-items-center mb-2 allowance-item">
<div class="col-md-5">
<div class="input-group input-group-sm">
<span class="input-group-text">จำนวนวัน</span>
<input type="number" min="0" step="0.5" name="alw_days[]" class="form-control alw-days calc-trigger" placeholder="0">
</div>
</div>
<div class="col-md-5">
<div class="input-group input-group-sm">
<span class="input-group-text">อัตรา/วัน</span>
<input type="number" min="0" step="0.01" name="alw_prices[]" class="form-control alw-prices calc-trigger" placeholder="0.00">
<span class="input-group-text">บาท</span>
</div>
</div>
<div class="col-md-2 text-end">
<button type="button" class="btn btn-sm btn-outline-danger btn-remove-row"><i class="fa-solid fa-trash"></i></button>
</div>
</div>`;
$("#allowances_list").append(template);
updateRemoveButtons("#allowances_list");
});
function updateRemoveButtons(listId) {
var items = $(listId).find(".btn-remove-row");
if (items.length > 1) {
items.prop("disabled", false);
} else {
items.prop("disabled", true);
}
}
$(document).on("click", ".btn-remove-row", function() {
var list = $(this).closest("div[id$=\'_list\']");
$(this).closest(".row").remove();
updateRemoveButtons("#" + list.attr("id"));
calculateDetailedTotal();
});
function calculateDetailedTotal() {
var total = 0;
$(".accommodation-item").each(function() {
var days = parseFloat($(this).find(".acc-days").val()) || 0;
var price = parseFloat($(this).find(".acc-prices").val()) || 0;
total += (days * price);
});
$(".allowance-item").each(function() {
var days = parseFloat($(this).find(".alw-days").val()) || 0;
var price = parseFloat($(this).find(".alw-prices").val()) || 0;
total += (days * price);
});
var transport = parseFloat($("#expense_transport").val()) || 0;
total += transport;
var registration = parseFloat($("#expense_registration").val()) || 0;
total += registration;
$("#detailed_total_display").text(total.toLocaleString("en-US", {minimumFractionDigits: 2, maximumFractionDigits: 2}));
$("#budget_lump_sum").val(total.toFixed(2));
}
$(document).on("input", ".calc-trigger", calculateDetailedTotal);
// Initial setup
toggleExpenseUI();
if ($("input[name=\'budget_type\']:checked").val() === "detailed") {
calculateDetailedTotal();
}
});
</script>
';
$extraStyles = '';
?>