191 lines
12 KiB
PHP
191 lines
12 KiB
PHP
<?php
|
|
session_start();
|
|
|
|
// ถ้าล็อกอินอยู่แล้ว ให้ไปหน้า dashboard ทันที
|
|
if (isset($_SESSION['user_id'])) {
|
|
header("Location: index.php");
|
|
exit();
|
|
}
|
|
|
|
$error = '';
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
require_once 'includes/db.php';
|
|
|
|
$username = trim($_POST['username'] ?? '');
|
|
$password = $_POST['password'] ?? '';
|
|
|
|
if (empty($username) || empty($password)) {
|
|
$error = 'กรุณากรอกข้อมูลให้ครบถ้วน';
|
|
} else {
|
|
$stmt = $pdo->prepare("SELECT * FROM users WHERE id_card = ? OR username = ?");
|
|
$stmt->execute([$username, $username]);
|
|
$user = $stmt->fetch();
|
|
|
|
if ($user && password_verify($password, $user['password'])) {
|
|
// รหัสผ่านถูกต้อง สร้าง Session
|
|
$_SESSION['user_id'] = $user['id'];
|
|
$_SESSION['username'] = $user['username'];
|
|
$_SESSION['full_name'] = $user['full_name'];
|
|
$_SESSION['role'] = $user['role'];
|
|
|
|
require_once 'includes/logger.php';
|
|
logActivity('Login', 'users', $user['id']);
|
|
|
|
// ส่ง JSON กลับไปให้ Alpine.js ทำงานต่อ
|
|
header('Content-Type: application/json');
|
|
echo json_encode(['success' => true]);
|
|
exit();
|
|
} else {
|
|
$error = 'เลขบัตรประชาชน/ชื่อผู้ใช้งาน หรือรหัสผ่านไม่ถูกต้อง';
|
|
}
|
|
}
|
|
|
|
// ส่ง Error กลับไป
|
|
if (!empty($error)) {
|
|
header('Content-Type: application/json');
|
|
echo json_encode(['success' => false, 'message' => $error]);
|
|
exit();
|
|
}
|
|
}
|
|
|
|
$pageTitle = 'เข้าสู่ระบบ | ระบบจัดการข้อมูลยานพาหนะ โรงพยาบาลเกาะสมุย';
|
|
$bodyClass = 'bg-slate-50 dark:bg-slate-900 min-h-screen relative overflow-hidden flex flex-col items-center justify-center';
|
|
$bodyAttributes = '';
|
|
require_once 'includes/header.php';
|
|
?>
|
|
|
|
<!-- Animated Soft Background -->
|
|
<div class="absolute inset-0 z-0 overflow-hidden pointer-events-none">
|
|
<!-- Animated Blobs -->
|
|
<div class="absolute top-[-10%] left-[-10%] w-[50vw] h-[50vw] rounded-full bg-primary-200/40 dark:bg-primary-900/30 blur-[100px] animate-blob mix-blend-multiply dark:mix-blend-screen"></div>
|
|
<div class="absolute top-[20%] right-[-10%] w-[40vw] h-[40vw] rounded-full bg-teal-200/40 dark:bg-teal-900/20 blur-[100px] animate-blob mix-blend-multiply dark:mix-blend-screen" style="animation-delay: 2s;"></div>
|
|
<div class="absolute bottom-[-20%] left-[20%] w-[60vw] h-[60vw] rounded-full bg-blue-300/30 dark:bg-blue-900/20 blur-[120px] animate-blob mix-blend-multiply dark:mix-blend-screen" style="animation-delay: 4s;"></div>
|
|
</div>
|
|
|
|
<!-- Main Content -->
|
|
<div class="relative z-10 w-full flex flex-col items-center justify-center min-h-screen p-4 sm:p-6 lg:p-8">
|
|
<!-- Logo Header -->
|
|
<div class="mb-8 text-center page-transition">
|
|
<img src="public/images/logo.png" alt="Logo" class="w-[120px] h-[120px] rounded-full object-cover border-4 border-white shadow-xl mx-auto mb-4 hover:scale-105 transition-transform duration-300 bg-white relative z-10">
|
|
<h1 class="text-3xl font-bold text-slate-800 dark:text-white tracking-tight drop-shadow-sm">โรงพยาบาลเกาะสมุย</h1>
|
|
<p class="text-lg text-slate-600 dark:text-slate-300 font-medium mt-1">ระบบจัดการข้อมูลยานพาหนะ-พนักงานขับรถ</p>
|
|
</div>
|
|
|
|
<!-- Login Card -->
|
|
<div class="w-full max-w-md page-transition" style="animation-delay: 0.1s;">
|
|
<div class="glass-card p-8 relative overflow-hidden group">
|
|
<!-- Inner Glow -->
|
|
<div class="absolute inset-0 bg-white/10 dark:bg-black/10 opacity-0 group-hover:opacity-100 transition-opacity duration-500 pointer-events-none"></div>
|
|
|
|
<h2 class="text-2xl font-semibold mb-6 text-center dark:text-white">เข้าสู่ระบบ / Login</h2>
|
|
|
|
<!-- Alpine Component สำหรับระบบ Login แบบไม่โหลดหน้าเว็บใหม่ -->
|
|
<form class="space-y-6"
|
|
x-data="{
|
|
isLoading: false,
|
|
isSuccess: false,
|
|
errorMsg: '',
|
|
submitForm() {
|
|
this.isLoading = true;
|
|
this.errorMsg = '';
|
|
|
|
let formData = new FormData(this.$refs.form);
|
|
|
|
fetch('login.php', {
|
|
method: 'POST',
|
|
body: formData
|
|
})
|
|
.then(res => res.json())
|
|
.then(data => {
|
|
if(data.success) {
|
|
this.isSuccess = true;
|
|
setTimeout(() => window.location.href='index.php', 1000);
|
|
} else {
|
|
this.isLoading = false;
|
|
this.errorMsg = data.message;
|
|
// สั่นกล่องข้อความเมื่อมี Error
|
|
this.$refs.errorBox.classList.add('animate-shake');
|
|
setTimeout(() => this.$refs.errorBox.classList.remove('animate-shake'), 500);
|
|
}
|
|
})
|
|
.catch(err => {
|
|
this.isLoading = false;
|
|
this.errorMsg = 'เกิดข้อผิดพลาดในการเชื่อมต่อเซิร์ฟเวอร์';
|
|
});
|
|
}
|
|
}"
|
|
x-ref="form"
|
|
@submit.prevent="submitForm">
|
|
|
|
<!-- Error Message Box -->
|
|
<div x-show="errorMsg" x-transition.opacity x-ref="errorBox" class="bg-danger/10 border border-danger/30 text-danger text-sm rounded-lg p-3 text-center mb-4 font-medium" style="display: none;">
|
|
<i class="fa-solid fa-triangle-exclamation mr-1"></i> <span x-text="errorMsg"></span>
|
|
</div>
|
|
|
|
<!-- Username -->
|
|
<div class="relative z-0 w-full mb-6 group">
|
|
<input type="text" name="username" id="username" class="glass-input block py-3 px-0 w-full text-sm text-gray-900 bg-transparent border-0 border-b-2 border-gray-300 appearance-none dark:text-white dark:border-gray-600 dark:focus:border-primary-500 focus:outline-none focus:ring-0 focus:border-primary-600 peer pl-8" placeholder=" " required />
|
|
<label for="username" class="peer-focus:font-medium absolute text-sm text-gray-500 dark:text-gray-400 duration-300 transform -translate-y-6 scale-75 top-3 -z-10 origin-[0] peer-focus:start-0 rtl:peer-focus:translate-x-1/4 rtl:peer-focus:left-auto peer-focus:text-primary-600 peer-focus:dark:text-primary-500 peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-6 pl-8">เลขบัตรประชาชน / ชื่อผู้ใช้งาน</label>
|
|
<div class="absolute inset-y-0 left-0 flex items-center pl-2 pointer-events-none">
|
|
<i class="fa-regular fa-user text-gray-400 peer-focus:text-primary-600 transition-colors"></i>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Password -->
|
|
<div class="relative z-0 w-full mb-6 group">
|
|
<input type="password" name="password" id="password" class="glass-input block py-3 px-0 w-full text-sm text-gray-900 bg-transparent border-0 border-b-2 border-gray-300 appearance-none dark:text-white dark:border-gray-600 dark:focus:border-primary-500 focus:outline-none focus:ring-0 focus:border-primary-600 peer pl-8" placeholder=" " required />
|
|
<label for="password" class="peer-focus:font-medium absolute text-sm text-gray-500 dark:text-gray-400 duration-300 transform -translate-y-6 scale-75 top-3 -z-10 origin-[0] peer-focus:start-0 rtl:peer-focus:translate-x-1/4 peer-focus:text-primary-600 peer-focus:dark:text-primary-500 peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-6 pl-8">รหัสผ่าน</label>
|
|
<div class="absolute inset-y-0 left-0 flex items-center pl-2 pointer-events-none">
|
|
<i class="fa-solid fa-lock text-gray-400 peer-focus:text-primary-600 transition-colors"></i>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-center justify-between">
|
|
<div class="flex items-start">
|
|
<div class="flex items-center h-5">
|
|
<input id="remember" type="checkbox" value="" class="w-4 h-4 border border-gray-300 rounded bg-gray-50 focus:ring-3 focus:ring-primary-300 dark:bg-gray-700 dark:border-gray-600 dark:focus:ring-primary-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800" />
|
|
</div>
|
|
<label for="remember" class="ms-2 text-sm font-medium text-gray-900 dark:text-gray-300 cursor-pointer">จดจำฉัน</label>
|
|
</div>
|
|
<a href="#" class="text-sm text-primary-600 hover:underline dark:text-primary-500">ลืมรหัสผ่าน?</a>
|
|
</div>
|
|
|
|
<button type="submit" :disabled="isLoading || isSuccess" class="btn-gradient w-full py-3 flex items-center justify-center space-x-2 relative overflow-hidden"
|
|
:class="{ 'opacity-80 cursor-not-allowed': isLoading || isSuccess }">
|
|
<span x-show="!isLoading && !isSuccess">เข้าสู่ระบบ</span>
|
|
<span x-show="isLoading" class="flex items-center" style="display: none;">
|
|
<svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
</svg>
|
|
กำลังตรวจสอบ...
|
|
</span>
|
|
<span x-show="isSuccess" class="flex items-center text-white" x-transition:enter="transition ease-out duration-300" x-transition:enter-start="opacity-0 scale-50" x-transition:enter-end="opacity-100 scale-100" style="display: none;">
|
|
<i class="fa-solid fa-check-circle mr-2"></i> เข้าสู่ระบบสำเร็จ
|
|
</span>
|
|
</button>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="mt-6 text-center text-sm text-slate-300">
|
|
<p>© 2026 Koh Samui Hospital. All rights reserved.</p>
|
|
<p class="mt-1 opacity-70">Version 1.0.0 (Production)</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Add animation for error shake -->
|
|
<style>
|
|
@keyframes shake {
|
|
0%, 100% { transform: translateX(0); }
|
|
10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
|
|
20%, 40%, 60%, 80% { transform: translateX(5px); }
|
|
}
|
|
.animate-shake {
|
|
animation: shake 0.5s;
|
|
}
|
|
</style>
|
|
|
|
<?php require_once 'includes/footer.php'; ?>
|