Initial commit - TPU Survey System with Google Forms & Certificate Generator

This commit is contained in:
pongpon pitisuk
2026-09-12 11:56:34 +07:00
commit 72eb7cd0c8
355 changed files with 117012 additions and 0 deletions
+214
View File
@@ -0,0 +1,214 @@
<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ตรวจสอบเกียรติบัตร - TPU Survey</title>
<meta name="description" content="หน้าบริการสาธารณะสำหรับตรวจสอบความถูกต้องของเกียรติบัตรจากคณะนวัตกรรมดิจิทัลเทคโนโลยี มหาวิทยาลัยตาปี">
<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=Noto+Sans+Thai:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
'thai': ['"Noto Sans Thai"', 'sans-serif']
},
colors: {
'primary': { 50:'#eff6ff',100:'#dbeafe',200:'#bfdbfe',300:'#93c5fd',400:'#60a5fa',500:'#3b82f6',600:'#2563eb',700:'#1d4ed8',800:'#1e40af',900:'#1e3a8a' },
'accent': { 50:'#fffbeb',100:'#fef3c7',200:'#fde68a',300:'#fcd34d',400:'#fbbf24',500:'#f59e0b',600:'#d97706',700:'#b45309',800:'#92400e',900:'#78350f' }
}
}
}
}
</script>
<link rel="stylesheet" href="css/style.css?v=6">
<style>
body {
background: linear-gradient(135deg, #1e3a8a 0%, #1e40af 50%, #1d4ed8 100%);
font-family: 'Noto Sans Thai', sans-serif;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.verify-card {
width: 100%;
max-width: 640px;
background: #ffffff;
border-radius: 24px;
padding: 40px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.25);
border: 1px solid rgba(255, 255, 255, 0.2);
position: relative;
overflow: hidden;
animation: slideUp 0.6s ease-out;
}
@keyframes slideUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.result-box {
display: none;
margin-top: 24px;
border-radius: 16px;
padding: 24px;
animation: fadeIn 0.4s ease;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
</style>
</head>
<body class="font-thai">
<div class="verify-card">
<div class="h-1.5 bg-gradient-to-r from-yellow-300 via-yellow-400 to-yellow-500 absolute top-0 left-0 right-0"></div>
<div class="text-center mb-32">
<img src="pic/logo.png" alt="TPU Logo" class="mx-auto h-24 w-auto mb-4 drop-shadow-md">
<h1 class="text-2xl font-bold mb-1" style="font-size: 1.6rem; color: #1e3a8a;">ระบบตรวจสอบความถูกต้องเกียรติบัตร</h1>
<p class="text-sm text-blue-900 font-bold">คณะนวัตกรรมดิจิทัลเทคโนโลยี</p>
<p class="text-xs text-gray-500 font-medium">มหาวิทยาลัยตาปี (Tapi University)</p>
</div>
<form id="verifyForm" onsubmit="handleVerify(event)">
<div class="form-group mb-20">
<label class="form-label" style="font-weight: 700; color: #1e3a8a; font-size: 1rem; margin-bottom: 8px;">รหัสตรวจสอบเกียรติบัตร (Certificate Code)</label>
<div class="flex gap-12">
<input type="text" id="certCodeInput" class="form-input flex-1" placeholder="ตัวอย่าง: TPU-2569-0016" required
style="border-color: #cbd5e1; border-width: 2px; font-weight: 600; text-transform: uppercase;">
<button type="submit" id="verifyBtn" class="btn btn-primary" style="min-width: 140px; border-radius: 8px;">
🔍 ตรวจสอบ
</button>
</div>
</div>
</form>
<!-- Loading state -->
<div id="loadingState" class="hidden text-center py-20">
<div class="inline-block animate-spin rounded-full h-32 w-32 border-b-2 border-navy-700" style="width: 40px; height: 40px; border-width: 3px; border-color: transparent; border-bottom-color: #2563eb;"></div>
<p class="mt-12 text-sm text-navy-800 font-bold">กำลังค้นหาข้อมูลในระบบ...</p>
</div>
<!-- Result Box: Success -->
<div id="resultSuccess" class="result-box bg-emerald-50 border-l-4 border-emerald-500" style="display: none; background-color: #f0fdf4; border-left: 5px solid #10b981;">
<div class="flex items-center gap-16 mb-16">
<div class="w-40 h-40 rounded-full flex items-center justify-center text-white font-bold" style="width: 36px; height: 36px; background-color: #10b981; font-size: 1.2rem;">✓</div>
<div>
<h3 class="text-emerald-800 font-extrabold text-lg" style="color: #065f46; font-size: 1.15rem;">เกียรติบัตรของแท้ (Verified Certificate)</h3>
<p class="text-xs text-emerald-600 font-medium" style="color: #047857;">รหัสอ้างอิงตรงกับข้อมูลในฐานข้อมูลระบบ</p>
</div>
</div>
<hr class="border-emerald-200 my-12" style="border-color: #a7f3d0;">
<div class="space-y-12 text-sm text-gray-800">
<div class="flex justify-between py-4 border-b border-dashed border-emerald-100" style="border-color: #d1fae5;">
<span class="text-gray-500 font-bold">ชื่อผู้เข้าร่วมโครงการ:</span>
<span class="font-extrabold text-navy-900" id="resRecipientName" style="color: #1e3a8a; font-size: 1.05rem;">-</span>
</div>
<div class="flex justify-between py-4 border-b border-dashed border-emerald-100" style="border-color: #d1fae5;">
<span class="text-gray-500 font-bold">ชื่อหลักสูตร / โครงการ:</span>
<span class="font-extrabold text-right" id="resCourseTitle" style="color: #1e293b; max-width: 70%;">-</span>
</div>
<div class="flex justify-between py-4 border-b border-dashed border-emerald-100" style="border-color: #d1fae5;">
<span class="text-gray-500 font-bold">วันที่ตอบสำเร็จ:</span>
<span class="font-bold text-gray-800" id="resIssueDate">-</span>
</div>
<div class="flex justify-between py-4">
<span class="text-gray-500 font-bold">รหัสยืนยัน:</span>
<span class="font-bold text-gray-500 font-mono" id="resCode">-</span>
</div>
</div>
</div>
<!-- Result Box: Error -->
<div id="resultError" class="result-box bg-rose-50 border-l-4 border-rose-500" style="display: none; background-color: #fff1f2; border-left: 5px solid #f43f5e;">
<div class="flex items-center gap-16">
<div class="w-40 h-40 rounded-full flex items-center justify-center text-white font-bold" style="width: 36px; height: 36px; background-color: #f43f5e; font-size: 1.2rem;">✕</div>
<div>
<h3 class="text-rose-800 font-bold text-lg" style="color: #9f1239; font-size: 1.15rem;">ไม่พบข้อมูลเกียรติบัตร</h3>
<p class="text-xs text-rose-600 font-medium" id="errorMessage" style="color: #be123c;">ไม่พบรหัสเกียรติบัตรนี้ในระบบ หรือพิมพ์ผิด</p>
</div>
</div>
</div>
</div>
<script>
// Check for code in URL query string (e.g. verify.html?code=TPU-2569-0016)
document.addEventListener('DOMContentLoaded', () => {
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');
if (code) {
document.getElementById('certCodeInput').value = code;
handleVerification(code);
}
});
function handleVerify(e) {
e.preventDefault();
const code = document.getElementById('certCodeInput').value.trim();
handleVerification(code);
}
async function handleVerification(code) {
const btn = document.getElementById('verifyBtn');
const loader = document.getElementById('loadingState');
const successBox = document.getElementById('resultSuccess');
const errorBox = document.getElementById('resultError');
// Reset states
successBox.style.display = 'none';
errorBox.style.display = 'none';
loader.classList.remove('hidden');
btn.disabled = true;
try {
const response = await fetch('api/verify.php?code=' + encodeURIComponent(code));
const data = await response.json();
loader.classList.add('hidden');
if (data.success) {
document.getElementById('resRecipientName').textContent = data.recipient_name;
document.getElementById('resCourseTitle').textContent = data.course_title;
document.getElementById('resIssueDate').textContent = formatDate(data.issue_date);
document.getElementById('resCode').textContent = data.code;
successBox.style.display = 'block';
} else {
document.getElementById('errorMessage').textContent = data.error || 'เกิดข้อผิดพลาดในการตรวจสอบ';
errorBox.style.display = 'block';
}
} catch (err) {
loader.classList.add('hidden');
document.getElementById('errorMessage').textContent = 'เกิดข้อผิดพลาดในการเชื่อมต่อเซิร์ฟเวอร์';
errorBox.style.display = 'block';
} finally {
btn.disabled = false;
}
}
function formatDate(dateStr) {
if (!dateStr) return '-';
try {
// dateStr formats: 2026-05-29 11:35:09
const parts = dateStr.split(' ')[0].split('-');
const y = parseInt(parts[0]) + 543; // แปลงเป็น พ.ศ.
const m = parseInt(parts[1]);
const d = parseInt(parts[2]);
const thaiMonths = [
'มกราคม', 'กุมภาพันธ์', 'มีนาคม', 'เมษายน', 'พฤษภาคม', 'มิถุนายน',
'กรกฎาคม', 'สิงหาคม', 'กันยายน', 'ตุลาคม', 'พฤศจิกายน', 'ธันวาคม'
];
return d + ' ' + thaiMonths[m - 1] + ' ' + y;
} catch (e) {
return dateStr;
}
}
</script>
</body>
</html>