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
+277
View File
@@ -0,0 +1,277 @@
<?php
require_once 'header.php';
require_once '../gdrive.php';
$action = $_GET['action'] ?? 'list';
$folder_id = getSetting($pdo, 'google_drive_folder_id');
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['add_competition'])) {
$title = $_POST['title'];
$year_th = $_POST['year_th'];
$rank_result = $_POST['rank_result'];
$details = $_POST['details'];
$authors_str = $_POST['authors']; // comma separated
$stmt = $pdo->prepare("INSERT INTO competitions (title, details, rank_result, year_th) VALUES (?, ?, ?, ?)");
$stmt->execute([$title, $details, $rank_result, $year_th]);
$competition_id = $pdo->lastInsertId();
// Handle authors
$authors = array_filter(array_map('trim', explode(',', $authors_str)));
foreach ($authors as $author) {
$stmt = $pdo->prepare("INSERT INTO competition_authors (competition_id, author_name) VALUES (?, ?)");
$stmt->execute([$competition_id, $author]);
}
// Handle file uploads
if (!empty($_FILES['attachments']['name'][0])) {
foreach ($_FILES['attachments']['name'] as $key => $name) {
if ($_FILES['attachments']['error'][$key] == 0) {
$tmp_name = $_FILES['attachments']['tmp_name'][$key];
$gdrive_file_id = uploadFileToDrive($tmp_name, $name, $folder_id);
if ($gdrive_file_id) {
$stmt = $pdo->prepare("INSERT INTO competition_attachments (competition_id, file_name, gdrive_file_id) VALUES (?, ?, ?)");
$stmt->execute([$competition_id, $name, $gdrive_file_id]);
}
}
}
}
logActivity($pdo, 'CREATE_COMPETITION', "เพิ่มผลงาน: $title");
header("Location: competitions.php");
exit;
}
if (isset($_POST['edit_competition'])) {
$id = $_POST['id'];
$title = $_POST['title'];
$year_th = $_POST['year_th'];
$rank_result = $_POST['rank_result'];
$details = $_POST['details'];
$authors_str = $_POST['authors'];
$stmt = $pdo->prepare("UPDATE competitions SET title = ?, details = ?, rank_result = ?, year_th = ? WHERE id = ?");
$stmt->execute([$title, $details, $rank_result, $year_th, $id]);
// Update authors (delete all and re-insert)
$stmt = $pdo->prepare("DELETE FROM competition_authors WHERE competition_id = ?");
$stmt->execute([$id]);
$authors = array_filter(array_map('trim', explode(',', $authors_str)));
foreach ($authors as $author) {
$stmt = $pdo->prepare("INSERT INTO competition_authors (competition_id, author_name) VALUES (?, ?)");
$stmt->execute([$id, $author]);
}
// Handle new file uploads
if (!empty($_FILES['attachments']['name'][0])) {
foreach ($_FILES['attachments']['name'] as $key => $name) {
if ($_FILES['attachments']['error'][$key] == 0) {
$tmp_name = $_FILES['attachments']['tmp_name'][$key];
$gdrive_file_id = uploadFileToDrive($tmp_name, $name, $folder_id);
if ($gdrive_file_id) {
$stmt = $pdo->prepare("INSERT INTO competition_attachments (competition_id, file_name, gdrive_file_id) VALUES (?, ?, ?)");
$stmt->execute([$id, $name, $gdrive_file_id]);
}
}
}
}
logActivity($pdo, 'UPDATE_COMPETITION', "แก้ไขผลงาน: $title");
header("Location: competitions.php");
exit;
}
}
if ($action === 'delete_attachment' && isset($_GET['id'])) {
$id = $_GET['id'];
$stmt = $pdo->prepare("SELECT * FROM competition_attachments WHERE id = ?");
$stmt->execute([$id]);
$attachment = $stmt->fetch();
if ($attachment) {
deleteFileFromDrive($attachment['gdrive_file_id']);
$stmt = $pdo->prepare("DELETE FROM competition_attachments WHERE id = ?");
$stmt->execute([$id]);
logActivity($pdo, 'DELETE_COMPETITION_FILE', "ลบไฟล์แนบผลงาน: " . $attachment['file_name']);
}
header("Location: competitions.php?action=edit&id=" . $attachment['competition_id']);
exit;
}
if ($action === 'delete' && isset($_GET['id'])) {
$id = $_GET['id'];
$stmt = $pdo->prepare("SELECT title FROM competitions WHERE id = ?");
$stmt->execute([$id]);
$comp = $stmt->fetch();
if ($comp) {
// Delete all attachments from GDrive
$stmt = $pdo->prepare("SELECT * FROM competition_attachments WHERE competition_id = ?");
$stmt->execute([$id]);
$attachments = $stmt->fetchAll();
foreach ($attachments as $attachment) {
deleteFileFromDrive($attachment['gdrive_file_id']);
}
$stmt = $pdo->prepare("DELETE FROM competitions WHERE id = ?");
$stmt->execute([$id]);
logActivity($pdo, 'DELETE_COMPETITION', "ลบผลงาน: " . $comp['title']);
}
header("Location: competitions.php");
exit;
}
?>
<div class="mb-8 flex justify-between items-center">
<h1 class="text-3xl font-bold text-gray-900">จัดการผลงานประกวด</h1>
<?php if ($action === 'list'): ?>
<a href="competitions.php?action=add" class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-md font-medium transition-colors">
+ เพิ่มผลงานใหม่
</a>
<?php else: ?>
<a href="competitions.php" class="bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded-md font-medium transition-colors">
กลับหน้ารายการ
</a>
<?php endif; ?>
</div>
<?php if ($action === 'list'): ?>
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
<table class="datatable w-full text-left border-collapse">
<thead>
<tr>
<th class="border-b py-3 px-4 bg-gray-50">ปี (พ.ศ.)</th>
<th class="border-b py-3 px-4 bg-gray-50">ชื่อผลงาน</th>
<th class="border-b py-3 px-4 bg-gray-50">รางวัล</th>
<th class="border-b py-3 px-4 bg-gray-50">ผู้จัดทำ</th>
<th class="border-b py-3 px-4 bg-gray-50">ไฟล์แนบ</th>
<th class="border-b py-3 px-4 bg-gray-50">จัดการ</th>
</tr>
</thead>
<tbody>
<?php
$stmt = $pdo->query("
SELECT c.*,
(SELECT GROUP_CONCAT(author_name SEPARATOR ', ') FROM competition_authors WHERE competition_id = c.id) as authors,
(SELECT COUNT(*) FROM competition_attachments WHERE competition_id = c.id) as file_count
FROM competitions c
ORDER BY c.year_th DESC, c.id DESC
");
while ($row = $stmt->fetch()):
?>
<tr class="hover:bg-gray-50">
<td class="border-b py-3 px-4 text-center"><?= $row['year_th'] ?></td>
<td class="border-b py-3 px-4"><?= htmlspecialchars((string)$row['title']) ?></td>
<td class="border-b py-3 px-4">
<span class="inline-block px-2 py-1 bg-yellow-100 text-yellow-800 text-xs rounded-md">
<?= htmlspecialchars((string)$row['rank_result']) ?>
</span>
</td>
<td class="border-b py-3 px-4 text-sm"><?= htmlspecialchars((string)$row['authors']) ?></td>
<td class="border-b py-3 px-4 text-center"><?= $row['file_count'] ?></td>
<td class="border-b py-3 px-4">
<a href="competitions.php?action=edit&id=<?= $row['id'] ?>" class="text-blue-600 hover:underline mr-3">แก้ไข</a>
<a href="competitions.php?action=delete&id=<?= $row['id'] ?>" class="text-red-600 hover:underline" onclick="return confirm('ยืนยันการลบข้อมูลนี้? การลบจะลบไฟล์ใน Google Drive ด้วย')">ลบ</a>
</td>
</tr>
<?php endwhile; ?>
</tbody>
</table>
</div>
<?php elseif ($action === 'add' || $action === 'edit'):
$comp = null;
$attachments = [];
$authors_str = '';
if ($action === 'edit' && isset($_GET['id'])) {
$stmt = $pdo->prepare("SELECT * FROM competitions WHERE id = ?");
$stmt->execute([$_GET['id']]);
$comp = $stmt->fetch();
$stmt = $pdo->prepare("SELECT * FROM competition_attachments WHERE competition_id = ?");
$stmt->execute([$_GET['id']]);
$attachments = $stmt->fetchAll();
$stmt = $pdo->prepare("SELECT GROUP_CONCAT(author_name SEPARATOR ', ') FROM competition_authors WHERE competition_id = ?");
$stmt->execute([$_GET['id']]);
$authors_str = $stmt->fetchColumn();
}
?>
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
<form action="competitions.php" method="POST" enctype="multipart/form-data" id="compForm">
<?php if ($comp): ?>
<input type="hidden" name="edit_competition" value="1">
<input type="hidden" name="id" value="<?= $comp['id'] ?>">
<?php else: ?>
<input type="hidden" name="add_competition" value="1">
<?php endif; ?>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
<div class="md:col-span-2">
<label class="block text-sm font-medium text-gray-700 mb-2">ชื่อผลงาน</label>
<input type="text" name="title" required class="appearance-none border border-gray-300 rounded-md w-full py-2 px-3 text-gray-700 focus:outline-none focus:ring-2 focus:ring-green-500" value="<?= $comp ? htmlspecialchars((string)$comp['title']) : '' ?>">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">ปี (พ.ศ.)</label>
<input type="number" name="year_th" required class="appearance-none border border-gray-300 rounded-md w-full py-2 px-3 text-gray-700 focus:outline-none focus:ring-2 focus:ring-green-500" value="<?= $comp ? $comp['year_th'] : (date('Y') + 543) ?>">
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">รางวัลที่ได้รับ (เช่น รางวัลที่ 1, ชมเชย)</label>
<input type="text" name="rank_result" required class="appearance-none border border-gray-300 rounded-md w-full py-2 px-3 text-gray-700 focus:outline-none focus:ring-2 focus:ring-green-500" value="<?= $comp ? htmlspecialchars((string)$comp['rank_result']) : '' ?>">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">รายชื่อผู้จัดทำ (คั่นด้วยเครื่องหมายจุลภาค , )</label>
<input type="text" name="authors" class="appearance-none border border-gray-300 rounded-md w-full py-2 px-3 text-gray-700 focus:outline-none focus:ring-2 focus:ring-green-500" value="<?= htmlspecialchars((string)$authors_str) ?>" placeholder="นายเอ, นายบี, นางสาวซี">
</div>
</div>
<div class="mb-6">
<label class="block text-sm font-medium text-gray-700 mb-2">รายละเอียด</label>
<input type="hidden" name="details" id="detailsInput">
<div id="editor" style="height: 200px;"><?= $comp ? $comp['details'] : '' ?></div>
</div>
<div class="mb-6">
<label class="block text-sm font-medium text-gray-700 mb-2">อัปโหลดไฟล์แนบ (PDF)</label>
<input type="file" name="attachments[]" multiple accept=".pdf" class="appearance-none border border-gray-300 rounded-md w-full py-2 px-3 text-gray-700 focus:outline-none focus:ring-2 focus:ring-green-500">
<?php if (!empty($attachments)): ?>
<div class="mt-4">
<h4 class="text-sm font-medium text-gray-700 mb-2">ไฟล์แนบปัจจุบัน</h4>
<ul class="space-y-2">
<?php foreach ($attachments as $file): ?>
<li class="flex items-center justify-between bg-gray-50 p-3 rounded border">
<span class="text-gray-700"><?= htmlspecialchars((string)$file['file_name']) ?></span>
<a href="competitions.php?action=delete_attachment&id=<?= $file['id'] ?>" class="text-red-500 hover:text-red-700 text-sm" onclick="return confirm('ยืนยันการลบไฟล์นี้จากระบบและ Google Drive?')">ลบไฟล์</a>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
</div>
<div>
<button type="submit" class="bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-6 rounded focus:outline-none transition-colors">
<?= $comp ? 'บันทึกการแก้ไข' : 'เพิ่มผลงาน' ?>
</button>
</div>
</form>
</div>
<script>
var quill = new Quill('#editor', {
theme: 'snow'
});
document.getElementById('compForm').onsubmit = function() {
document.getElementById('detailsInput').value = quill.root.innerHTML;
};
</script>
<?php endif; ?>
<?php require_once 'footer.php'; ?>
+75
View File
@@ -0,0 +1,75 @@
<?php
require_once 'header.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['insert_dummy'])) {
for ($i = 1; $i <= 10; $i++) {
// Meeting Dummy
$stmt = $pdo->prepare("INSERT INTO meeting_minutes (title, meeting_date, details) VALUES (?, ?, ?)");
$stmt->execute(["การประชุมคณะกรรมการ P4Q ครั้งที่ $i/2569", date('Y-m-d', strtotime("-$i days")), "<p>รายละเอียดการประชุมครั้งที่ $i</p>"]);
// Competition Dummy
$year = 2569 - ($i % 3);
$stmt = $pdo->prepare("INSERT INTO competitions (title, details, rank_result, year_th) VALUES (?, ?, ?, ?)");
$stmt->execute(["ผลงานพัฒนาคุณภาพ เรื่องที่ $i", "<p>รายละเอียดผลงานพัฒนาคุณภาพเรื่องที่ $i</p>", "รางวัลที่ " . rand(1, 3), $year]);
$comp_id = $pdo->lastInsertId();
// Authors Dummy
$stmt = $pdo->prepare("INSERT INTO competition_authors (competition_id, author_name) VALUES (?, ?)");
$stmt->execute([$comp_id, "นายแพทย์ทดสอบ คนที่ $i"]);
}
logActivity($pdo, 'INSERT_DUMMY', "เพิ่มข้อมูลตัวอย่าง 10 รายการ");
$success = "เพิ่มข้อมูลตัวอย่าง 10 รายการสำเร็จ";
}
if (isset($_POST['clear_dummy'])) {
// We will just clear all tables except settings
$pdo->query("SET FOREIGN_KEY_CHECKS = 0;");
$pdo->query("TRUNCATE TABLE meeting_attachments;");
$pdo->query("TRUNCATE TABLE meeting_minutes;");
$pdo->query("TRUNCATE TABLE competition_attachments;");
$pdo->query("TRUNCATE TABLE competition_authors;");
$pdo->query("TRUNCATE TABLE competitions;");
$pdo->query("SET FOREIGN_KEY_CHECKS = 1;");
logActivity($pdo, 'CLEAR_DUMMY', "ล้างข้อมูลทั้งหมด");
$success = "ล้างข้อมูลทั้งหมดสำเร็จ";
}
}
?>
<div class="mb-8">
<h1 class="text-3xl font-bold text-gray-900">จัดการข้อมูลตัวอย่าง</h1>
</div>
<?php if (!empty($success)): ?>
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative mb-4" role="alert">
<span class="block sm:inline"><?= $success ?></span>
</div>
<?php endif; ?>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6 text-center">
<h2 class="text-xl font-bold mb-4 text-blue-600">เพิ่มข้อมูลตัวอย่าง</h2>
<p class="text-gray-600 mb-6">สร้างข้อมูลบันทึกการประชุม 10 รายการ และผลงานประกวด 10 รายการ</p>
<form action="" method="POST">
<input type="hidden" name="insert_dummy" value="1">
<button type="submit" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded w-full">
สร้างข้อมูลตัวอย่าง
</button>
</form>
</div>
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6 text-center">
<h2 class="text-xl font-bold mb-4 text-red-600">ล้างข้อมูลทั้งหมด</h2>
<p class="text-gray-600 mb-6">ลบข้อมูลบันทึกการประชุม ผลงาน และไฟล์แนบทั้งหมดในระบบ</p>
<form action="" method="POST" onsubmit="return confirm('ยืนยันการล้างข้อมูลทั้งหมด? ข้อมูลจะไม่สามารถกู้คืนได้');">
<input type="hidden" name="clear_dummy" value="1">
<button type="submit" class="bg-red-600 hover:bg-red-700 text-white font-bold py-2 px-4 rounded w-full">
ล้างข้อมูล
</button>
</form>
</div>
</div>
<?php require_once 'footer.php'; ?>
+23
View File
@@ -0,0 +1,23 @@
<?php // admin/footer.php ?>
<?php if ($current_page !== 'login.php'): ?>
</div>
</div>
</div>
<?php endif; ?>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.quilljs.com/1.3.6/quill.min.js"></script>
<script>
$(document).ready(function() {
if ($('.datatable').length) {
$('.datatable').DataTable({
"language": {
"url": "//cdn.datatables.net/plug-ins/1.13.6/i18n/th.json"
}
});
}
});
</script>
</body>
</html>
+57
View File
@@ -0,0 +1,57 @@
<?php
// admin/header.php
session_start();
require_once __DIR__ . '/../config.php';
require_once __DIR__ . '/../db.php';
// Check auth
$current_page = basename($_SERVER['PHP_SELF']);
if ($current_page !== 'login.php' && empty($_SESSION['admin_logged_in'])) {
header("Location: login.php");
exit;
}
?>
<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>P4Q Admin Panel</title>
<link rel="icon" type="image/png" href="../logo.png">
<link href="https://fonts.googleapis.com/css2?family=Sarabun:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<!-- DataTables -->
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css">
<!-- Quill.js for Text Editor -->
<link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">
<!-- SweetAlert2 -->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<style>
body { font-family: 'Sarabun', sans-serif; background-color: #f3f4f6; }
.glass { background: rgba(255, 255, 255, 0.7); backdrop-filter: blur(10px); border: 1px solid rgba(255, 255, 255, 0.3); }
</style>
</head>
<body class="text-gray-800">
<?php if ($current_page !== 'login.php'): ?>
<div class="flex h-screen overflow-hidden">
<!-- Sidebar -->
<aside class="w-64 bg-white shadow-md flex-shrink-0">
<div class="p-6 text-center">
<img src="../logo.png" alt="Logo" class="h-16 mx-auto mb-2" onerror="this.src='https://via.placeholder.com/64'">
<h1 class="text-xl font-bold text-green-700">P4Q Admin</h1>
</div>
<nav class="mt-6">
<a href="index.php" class="block px-6 py-3 hover:bg-gray-100 <?= $current_page == 'index.php' ? 'bg-gray-100 font-semibold' : '' ?>">ภาพรวมระบบ (Dashboard)</a>
<a href="meetings.php" class="block px-6 py-3 hover:bg-gray-100 <?= $current_page == 'meetings.php' ? 'bg-gray-100 font-semibold' : '' ?>">บันทึกการประชุม</a>
<a href="competitions.php" class="block px-6 py-3 hover:bg-gray-100 <?= $current_page == 'competitions.php' ? 'bg-gray-100 font-semibold' : '' ?>">ผลงานประกวด</a>
<a href="settings.php" class="block px-6 py-3 hover:bg-gray-100 <?= $current_page == 'settings.php' ? 'bg-gray-100 font-semibold' : '' ?>">ตั้งค่า Google Drive</a>
<a href="logs.php" class="block px-6 py-3 hover:bg-gray-100 <?= $current_page == 'logs.php' ? 'bg-gray-100 font-semibold' : '' ?>">ประวัติการทำงาน</a>
<a href="dummy.php" class="block px-6 py-3 hover:bg-gray-100 text-yellow-600 <?= $current_page == 'dummy.php' ? 'bg-gray-100 font-semibold' : '' ?>">จัดการข้อมูลตัวอย่าง</a>
<a href="logout.php" class="block px-6 py-3 hover:bg-gray-100 text-red-600">ออกจากระบบ</a>
</nav>
</aside>
<!-- Main Content -->
<div class="flex-1 overflow-y-auto p-8">
<div class="max-w-6xl mx-auto">
<?php endif; ?>
+55
View File
@@ -0,0 +1,55 @@
<?php
require_once 'header.php';
$total_meetings = $pdo ? $pdo->query("SELECT COUNT(*) FROM meeting_minutes")->fetchColumn() : 0;
$total_competitions = $pdo ? $pdo->query("SELECT COUNT(*) FROM competitions")->fetchColumn() : 0;
$total_logs = $pdo ? $pdo->query("SELECT COUNT(*) FROM activity_logs")->fetchColumn() : 0;
?>
<div class="mb-8">
<h1 class="text-3xl font-bold text-gray-900">ภาพรวมระบบ (Dashboard)</h1>
<p class="text-gray-600 mt-2">ยินดีต้อนรับเข้าสู่ระบบจัดการข้อมูล P4Q</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6 flex items-center space-x-4">
<div class="p-3 bg-blue-100 text-blue-600 rounded-full">
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9a2 2 0 00-2-2h-2m-4-3H9M7 16h6M7 8h6v4H7V8z"></path></svg>
</div>
<div>
<p class="text-sm text-gray-500 font-medium">บันทึกการประชุมทั้งหมด</p>
<p class="text-2xl font-bold text-gray-900"><?= number_format((float)$total_meetings) ?> รายการ</p>
</div>
</div>
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6 flex items-center space-x-4">
<div class="p-3 bg-green-100 text-green-600 rounded-full">
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z"></path></svg>
</div>
<div>
<p class="text-sm text-gray-500 font-medium">ผลงานประกวดทั้งหมด</p>
<p class="text-2xl font-bold text-gray-900"><?= number_format((float)$total_competitions) ?> รายการ</p>
</div>
</div>
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6 flex items-center space-x-4">
<div class="p-3 bg-purple-100 text-purple-600 rounded-full">
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
</div>
<div>
<p class="text-sm text-gray-500 font-medium">ประวัติการทำงาน</p>
<p class="text-2xl font-bold text-gray-900"><?= number_format((float)$total_logs) ?> รายการ</p>
</div>
</div>
</div>
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
<h2 class="text-lg font-bold text-gray-800 mb-4">ข้อมูลเบื้องต้น</h2>
<ul class="list-disc pl-5 space-y-2 text-gray-600">
<li>เพื่อความปลอดภัย รหัสผ่านหลังบ้านจะถูกกำหนดไว้ในไฟล์ <code>config.php</code></li>
<li>ไฟล์ที่อัปโหลดจะถูกส่งไปยัง Google Drive ตาม Folder ID ที่ตั้งค่าไว้ในเมนู <a href="settings.php" class="text-blue-500 underline">ตั้งค่า Google Drive</a></li>
<li>หากมีการลบข้อมูล ไฟล์ใน Google Drive ก็จะถูกลบออกด้วย</li>
</ul>
</div>
<?php require_once 'footer.php'; ?>
+46
View File
@@ -0,0 +1,46 @@
<?php
session_start();
require_once __DIR__ . '/../config.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$password = $_POST['password'] ?? '';
if ($password === ADMIN_PASSWORD) {
$_SESSION['admin_logged_in'] = true;
header("Location: index.php");
exit;
} else {
$error = "รหัสผ่านไม่ถูกต้อง";
}
}
?>
<?php require_once 'header.php'; ?>
<div class="min-h-screen flex items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8 bg-[url('https://www.transparenttextures.com/patterns/cubes.png')]">
<div class="max-w-md w-full space-y-8 glass p-10 rounded-2xl shadow-xl">
<div>
<img class="mx-auto h-24 w-auto" src="../logo.png" alt="Logo" onerror="this.src='https://via.placeholder.com/150'">
<h2 class="mt-6 text-center text-3xl font-extrabold text-gray-900">
เข้าสู่ระบบจัดการ P4Q
</h2>
</div>
<form class="mt-8 space-y-6" action="login.php" method="POST">
<input type="hidden" name="remember" value="true">
<div class="rounded-md shadow-sm -space-y-px">
<div>
<label for="password" class="sr-only">รหัสผ่าน</label>
<input id="password" name="password" type="password" required class="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-md focus:outline-none focus:ring-green-500 focus:border-green-500 focus:z-10 sm:text-sm" placeholder="กรอกรหัสผ่านเพื่อเข้าใช้งาน">
</div>
</div>
<?php if (!empty($error)): ?>
<div class="text-red-500 text-sm text-center font-medium"><?= $error ?></div>
<?php endif; ?>
<div>
<button type="submit" class="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 transition-all">
เข้าสู่ระบบ
</button>
</div>
</form>
</div>
</div>
<?php require_once 'footer.php'; ?>
+5
View File
@@ -0,0 +1,5 @@
<?php
session_start();
session_destroy();
header("Location: login.php");
exit;
+38
View File
@@ -0,0 +1,38 @@
<?php
require_once 'header.php';
$stmt = $pdo->prepare("SELECT * FROM activity_logs ORDER BY created_at DESC");
$stmt->execute();
$logs = $stmt->fetchAll();
?>
<div class="mb-8">
<h1 class="text-3xl font-bold text-gray-900">ประวัติการทำงาน</h1>
</div>
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
<table class="datatable w-full text-left border-collapse">
<thead>
<tr>
<th class="border-b py-3 px-4 bg-gray-50">เวลา</th>
<th class="border-b py-3 px-4 bg-gray-50">ประเภทการทำงาน</th>
<th class="border-b py-3 px-4 bg-gray-50">รายละเอียด</th>
</tr>
</thead>
<tbody>
<?php foreach ($logs as $log): ?>
<tr class="hover:bg-gray-50">
<td class="border-b py-3 px-4"><?= date('d/m/Y H:i:s', strtotime($log['created_at'])) ?></td>
<td class="border-b py-3 px-4">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
<?= htmlspecialchars((string)$log['action_type']) ?>
</span>
</td>
<td class="border-b py-3 px-4"><?= htmlspecialchars((string)$log['action_details']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php require_once 'footer.php'; ?>
+232
View File
@@ -0,0 +1,232 @@
<?php
require_once 'header.php';
require_once '../gdrive.php';
$action = $_GET['action'] ?? 'list';
$folder_id = getSetting($pdo, 'google_drive_folder_id');
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['add_meeting'])) {
$title = $_POST['title'];
$meeting_date = $_POST['meeting_date'];
$details = $_POST['details'];
$stmt = $pdo->prepare("INSERT INTO meeting_minutes (title, meeting_date, details) VALUES (?, ?, ?)");
$stmt->execute([$title, $meeting_date, $details]);
$meeting_id = $pdo->lastInsertId();
// Handle file uploads
if (!empty($_FILES['attachments']['name'][0])) {
foreach ($_FILES['attachments']['name'] as $key => $name) {
if ($_FILES['attachments']['error'][$key] == 0) {
$tmp_name = $_FILES['attachments']['tmp_name'][$key];
$gdrive_file_id = uploadFileToDrive($tmp_name, $name, $folder_id);
if ($gdrive_file_id) {
$stmt = $pdo->prepare("INSERT INTO meeting_attachments (meeting_id, file_name, gdrive_file_id) VALUES (?, ?, ?)");
$stmt->execute([$meeting_id, $name, $gdrive_file_id]);
}
}
}
}
logActivity($pdo, 'CREATE_MEETING', "เพิ่มบันทึกการประชุม: $title");
header("Location: meetings.php");
exit;
}
if (isset($_POST['edit_meeting'])) {
$id = $_POST['id'];
$title = $_POST['title'];
$meeting_date = $_POST['meeting_date'];
$details = $_POST['details'];
$stmt = $pdo->prepare("UPDATE meeting_minutes SET title = ?, meeting_date = ?, details = ? WHERE id = ?");
$stmt->execute([$title, $meeting_date, $details, $id]);
// Handle new file uploads
if (!empty($_FILES['attachments']['name'][0])) {
foreach ($_FILES['attachments']['name'] as $key => $name) {
if ($_FILES['attachments']['error'][$key] == 0) {
$tmp_name = $_FILES['attachments']['tmp_name'][$key];
$gdrive_file_id = uploadFileToDrive($tmp_name, $name, $folder_id);
if ($gdrive_file_id) {
$stmt = $pdo->prepare("INSERT INTO meeting_attachments (meeting_id, file_name, gdrive_file_id) VALUES (?, ?, ?)");
$stmt->execute([$id, $name, $gdrive_file_id]);
}
}
}
}
logActivity($pdo, 'UPDATE_MEETING', "แก้ไขบันทึกการประชุม: $title");
header("Location: meetings.php");
exit;
}
}
if ($action === 'delete_attachment' && isset($_GET['id'])) {
$id = $_GET['id'];
$stmt = $pdo->prepare("SELECT * FROM meeting_attachments WHERE id = ?");
$stmt->execute([$id]);
$attachment = $stmt->fetch();
if ($attachment) {
deleteFileFromDrive($attachment['gdrive_file_id']);
$stmt = $pdo->prepare("DELETE FROM meeting_attachments WHERE id = ?");
$stmt->execute([$id]);
logActivity($pdo, 'DELETE_MEETING_FILE', "ลบไฟล์แนบการประชุม: " . $attachment['file_name']);
}
header("Location: meetings.php?action=edit&id=" . $attachment['meeting_id']);
exit;
}
if ($action === 'delete' && isset($_GET['id'])) {
$id = $_GET['id'];
// Get meeting info
$stmt = $pdo->prepare("SELECT title FROM meeting_minutes WHERE id = ?");
$stmt->execute([$id]);
$meeting = $stmt->fetch();
if ($meeting) {
// Delete all attachments from GDrive
$stmt = $pdo->prepare("SELECT * FROM meeting_attachments WHERE meeting_id = ?");
$stmt->execute([$id]);
$attachments = $stmt->fetchAll();
foreach ($attachments as $attachment) {
deleteFileFromDrive($attachment['gdrive_file_id']);
}
$stmt = $pdo->prepare("DELETE FROM meeting_minutes WHERE id = ?");
$stmt->execute([$id]);
logActivity($pdo, 'DELETE_MEETING', "ลบบันทึกการประชุม: " . $meeting['title']);
}
header("Location: meetings.php");
exit;
}
?>
<div class="mb-8 flex justify-between items-center">
<h1 class="text-3xl font-bold text-gray-900">จัดการบันทึกการประชุม</h1>
<?php if ($action === 'list'): ?>
<a href="meetings.php?action=add" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md font-medium transition-colors">
+ เพิ่มบันทึกการประชุม
</a>
<?php else: ?>
<a href="meetings.php" class="bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded-md font-medium transition-colors">
กลับหน้ารายการ
</a>
<?php endif; ?>
</div>
<?php if ($action === 'list'): ?>
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
<table class="datatable w-full text-left border-collapse">
<thead>
<tr>
<th class="border-b py-3 px-4 bg-gray-50">วันที่ประชุม</th>
<th class="border-b py-3 px-4 bg-gray-50">เรื่อง</th>
<th class="border-b py-3 px-4 bg-gray-50">จำนวนไฟล์แนบ</th>
<th class="border-b py-3 px-4 bg-gray-50">จัดการ</th>
</tr>
</thead>
<tbody>
<?php
$stmt = $pdo->query("
SELECT m.*, COUNT(a.id) as file_count
FROM meeting_minutes m
LEFT JOIN meeting_attachments a ON m.id = a.meeting_id
GROUP BY m.id
ORDER BY m.meeting_date DESC
");
while ($row = $stmt->fetch()):
?>
<tr class="hover:bg-gray-50">
<td class="border-b py-3 px-4"><?= date('d/m/Y', strtotime($row['meeting_date'])) ?></td>
<td class="border-b py-3 px-4"><?= htmlspecialchars((string)$row['title']) ?></td>
<td class="border-b py-3 px-4"><?= $row['file_count'] ?> ไฟล์</td>
<td class="border-b py-3 px-4">
<a href="meetings.php?action=edit&id=<?= $row['id'] ?>" class="text-blue-600 hover:underline mr-3">แก้ไข</a>
<a href="meetings.php?action=delete&id=<?= $row['id'] ?>" class="text-red-600 hover:underline" onclick="return confirm('ยืนยันการลบข้อมูลนี้? การลบจะลบไฟล์ใน Google Drive ด้วย')">ลบ</a>
</td>
</tr>
<?php endwhile; ?>
</tbody>
</table>
</div>
<?php elseif ($action === 'add' || $action === 'edit'):
$meeting = null;
$attachments = [];
if ($action === 'edit' && isset($_GET['id'])) {
$stmt = $pdo->prepare("SELECT * FROM meeting_minutes WHERE id = ?");
$stmt->execute([$_GET['id']]);
$meeting = $stmt->fetch();
$stmt = $pdo->prepare("SELECT * FROM meeting_attachments WHERE meeting_id = ?");
$stmt->execute([$_GET['id']]);
$attachments = $stmt->fetchAll();
}
?>
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
<form action="meetings.php" method="POST" enctype="multipart/form-data" id="meetingForm">
<?php if ($meeting): ?>
<input type="hidden" name="edit_meeting" value="1">
<input type="hidden" name="id" value="<?= $meeting['id'] ?>">
<?php else: ?>
<input type="hidden" name="add_meeting" value="1">
<?php endif; ?>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">วันที่ประชุม</label>
<input type="date" name="meeting_date" required class="appearance-none border border-gray-300 rounded-md w-full py-2 px-3 text-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500" value="<?= $meeting ? $meeting['meeting_date'] : date('Y-m-d') ?>">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">เรื่อง</label>
<input type="text" name="title" required class="appearance-none border border-gray-300 rounded-md w-full py-2 px-3 text-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500" value="<?= $meeting ? htmlspecialchars((string)$meeting['title']) : '' ?>">
</div>
</div>
<div class="mb-6">
<label class="block text-sm font-medium text-gray-700 mb-2">รายละเอียด</label>
<input type="hidden" name="details" id="detailsInput">
<div id="editor" style="height: 200px;"><?= $meeting ? $meeting['details'] : '' ?></div>
</div>
<div class="mb-6">
<label class="block text-sm font-medium text-gray-700 mb-2">อัปโหลดไฟล์แนบ (PDF)</label>
<input type="file" name="attachments[]" multiple accept=".pdf" class="appearance-none border border-gray-300 rounded-md w-full py-2 px-3 text-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500">
<?php if (!empty($attachments)): ?>
<div class="mt-4">
<h4 class="text-sm font-medium text-gray-700 mb-2">ไฟล์แนบปัจจุบัน</h4>
<ul class="space-y-2">
<?php foreach ($attachments as $file): ?>
<li class="flex items-center justify-between bg-gray-50 p-3 rounded border">
<span class="text-gray-700"><?= htmlspecialchars((string)$file['file_name']) ?></span>
<a href="meetings.php?action=delete_attachment&id=<?= $file['id'] ?>" class="text-red-500 hover:text-red-700 text-sm" onclick="return confirm('ยืนยันการลบไฟล์นี้จากระบบและ Google Drive?')">ลบไฟล์</a>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
</div>
<div>
<button type="submit" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-6 rounded focus:outline-none transition-colors">
<?= $meeting ? 'บันทึกการแก้ไข' : 'เพิ่มข้อมูล' ?>
</button>
</div>
</form>
</div>
<script>
var quill = new Quill('#editor', {
theme: 'snow'
});
document.getElementById('meetingForm').onsubmit = function() {
document.getElementById('detailsInput').value = quill.root.innerHTML;
};
</script>
<?php endif; ?>
<?php require_once 'footer.php'; ?>
+53
View File
@@ -0,0 +1,53 @@
<?php
require_once 'header.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$folder_id = $_POST['google_drive_folder_id'] ?? '';
// Check if exists
$stmt = $pdo->prepare("SELECT COUNT(*) FROM settings WHERE setting_key = 'google_drive_folder_id'");
$stmt->execute();
$exists = $stmt->fetchColumn();
if ($exists) {
$stmt = $pdo->prepare("UPDATE settings SET setting_value = ? WHERE setting_key = 'google_drive_folder_id'");
$stmt->execute([$folder_id]);
} else {
$stmt = $pdo->prepare("INSERT INTO settings (setting_key, setting_value) VALUES ('google_drive_folder_id', ?)");
$stmt->execute([$folder_id]);
}
logActivity($pdo, 'UPDATE_SETTINGS', "อัปเดต Google Drive Folder ID");
$success = "บันทึกการตั้งค่าเรียบร้อยแล้ว";
}
$current_folder_id = getSetting($pdo, 'google_drive_folder_id');
?>
<div class="mb-8">
<h1 class="text-3xl font-bold text-gray-900">ตั้งค่าระบบ</h1>
</div>
<?php if (!empty($success)): ?>
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative mb-4" role="alert">
<span class="block sm:inline"><?= $success ?></span>
</div>
<?php endif; ?>
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6 max-w-2xl">
<form action="" method="POST">
<div class="mb-4">
<label for="google_drive_folder_id" class="block text-sm font-medium text-gray-700 mb-2">Google Drive Folder ID</label>
<input type="text" id="google_drive_folder_id" name="google_drive_folder_id" value="<?= htmlspecialchars((string)$current_folder_id) ?>" class="appearance-none border border-gray-300 rounded-md w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:ring-2 focus:ring-green-500" placeholder="เช่น 1A2b3C4d5E6f7G8h9I0j">
<p class="text-sm text-gray-500 mt-2">หมายเหตุ: ต้องแชร์โฟลเดอร์ใน Google Drive ให้กับอีเมล Service Account ของคุณด้วย เพื่อให้ระบบสามารถอัปโหลดไฟล์เข้าไปได้</p>
</div>
<div class="mt-6">
<button type="submit" class="bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline transition-colors">
บันทึกการตั้งค่า
</button>
</div>
</form>
</div>
<?php require_once 'footer.php'; ?>