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,13 @@
<?php
// ฟังก์ชันสำหรับส่งคืนค่าเป็น JSON
function jsonResponse($success, $message, $data = [], $statusCode = 200) {
http_response_code($statusCode);
header('Content-Type: application/json');
echo json_encode([
'success' => $success,
'message' => $message,
'data' => $data
]);
exit();
}
?>
@@ -0,0 +1,16 @@
<?php
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
// เช็คว่าผู้ใช้ล็อกอินหรือยัง ถ้ายังให้เตะไปหน้า login
if (!isset($_SESSION['user_id'])) {
header("Location: login.php");
exit();
}
// ฟังก์ชันสำหรับเช็คว่าเป็นแอดมินหรือไม่
function isAdmin() {
return isset($_SESSION['role']) && $_SESSION['role'] === 'admin';
}
?>
@@ -0,0 +1,20 @@
<?php
$host = 'localhost';
$db = 'gso_cars';
$user = 'root';
$pass = '@Samui@10742'; // เปลี่ยนรหัสผ่านตรงนี้ให้ตรงกับเซิร์ฟเวอร์ของคุณ
$charset = 'utf8mb4';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
try {
$pdo = new PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
// ใน production ควรบันทึก error ลง log และไม่แสดงข้อความ error โดยตรง
die("Database connection failed: " . $e->getMessage());
}
@@ -0,0 +1,23 @@
<?php
// ข้อมูลการเชื่อมต่อฐานข้อมูลที่ 2 (hosoffice_2566)
// กรุณาแก้ไขข้อมูลด้านล่างนี้ให้ตรงกับเซิร์ฟเวอร์จริงของคุณ
$hr_host = '10.0.250.115'; // เปลี่ยนเป็น IP ของเซิร์ฟเวอร์ hosoffice_2566
$hr_db = 'hosoffice_2566';
$hr_user = 'hosoffice'; // เปลี่ยนเป็น Username ของคุณ
$hr_pass = 'hosoffice10742'; // เปลี่ยนเป็น Password ของคุณ
$hr_charset = 'utf8mb4';
$hr_dsn = "mysql:host=$hr_host;dbname=$hr_db;charset=$hr_charset";
$hr_options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
try {
$pdo_hr = new PDO($hr_dsn, $hr_user, $hr_pass, $hr_options);
} catch (\PDOException $e) {
// ใน production ไม่ควรแสดงข้อความ error ของ DB โดยตรง
// die("Database HR connection failed: " . $e->getMessage());
$pdo_hr = null; // หากเชื่อมต่อไม่ได้ให้ค่าเป็น null เพื่อจัดการ error ต่อใน API
}
@@ -0,0 +1,15 @@
<?php
$host = 'localhost'; // หรือ IP ของเซิร์ฟเวอร์ Intranet
$dbname = 'intranet';
$username = 'root'; // เปลี่ยนเป็น Username ที่ใช้งานจริง
$password = '@Samui@10742'; // เปลี่ยนเป็น Password ที่ใช้งานจริง
try {
$intranet_pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $username, $password);
$intranet_pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$intranet_pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
} catch (PDOException $e) {
// ระงับการแสดงข้อผิดพลาดทางหน้าเว็บเพื่อความปลอดภัย แต่ให้คืนค่า false หรือ null ไว้เพื่อตรวจสอบ
$intranet_pdo = null;
error_log("Connection failed (Intranet): " . $e->getMessage());
}
@@ -0,0 +1,31 @@
<?php require_once __DIR__ . '/vite.php'; ?>
<!DOCTYPE html>
<html lang="th" class="antialiased">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= $pageTitle ?? 'ระบบจัดการข้อมูลยานพาหนะ โรงพยาบาลเกาะสมุย' ?></title>
<link rel="manifest" href="public/manifest.json">
<meta name="theme-color" content="#0F6CBD">
<link rel="icon" type="image/png" href="public/images/logo.png">
<link rel="apple-touch-icon" href="public/images/logo.png">
<link href="https://fonts.googleapis.com/css2?family=Prompt:wght@300;400;500;600;700&family=Noto+Sans+Thai:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<!-- Vite Assets -->
<?= vite('src/js/app.js') ?>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<!-- Theme Script -->
<script>
if (localStorage.getItem('theme') === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
</script>
</head>
<body x-data="themeStore" class="font-sans transition-colors duration-300 <?= $bodyClass ?? 'bg-slate-50 dark:bg-slate-900 text-slate-800 dark:text-slate-200' ?>" <?= $bodyAttributes ?? '' ?>>
@@ -0,0 +1,24 @@
<?php
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
require_once __DIR__ . '/db.php';
function logActivity($action, $table_name = null, $record_id = null) {
global $pdo;
$user_id = $_SESSION['user_id'] ?? null;
$ip_address = $_SERVER['REMOTE_ADDR'] ?? null;
if ($ip_address === '::1') {
$ip_address = '127.0.0.1';
}
try {
$stmt = $pdo->prepare("INSERT INTO activity_logs (user_id, action, table_name, record_id, ip_address) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([$user_id, $action, $table_name, $record_id, $ip_address]);
} catch (PDOException $e) {
error_log("Failed to log activity: " . $e->getMessage());
}
}
?>
@@ -0,0 +1,93 @@
<?php
$fullName = $_SESSION['full_name'] ?? 'Admin User';
$roleName = ($_SESSION['role'] ?? '') === 'admin' ? 'ผู้ดูแลระบบ' : 'เจ้าหน้าที่';
$pageTitleDisplay = $pageTitleDisplay ?? 'ระบบจัดการข้อมูลยานพาหนะ';
if (!isset($_SESSION['user_avatar'])) {
$_SESSION['user_avatar'] = "https://ui-avatars.com/api/?name=" . urlencode($fullName) . "&background=0F6CBD&color=fff";
// ค้นหารูปจากฐานข้อมูล HR ด้วยชื่อ-สกุล
try {
require_once 'includes/db_hr.php';
if ($pdo_hr) {
// ลบคำนำหน้าชื่อถ้ามี เช่น นาย นาง นางสาว
$searchName = preg_replace('/^(นาย|นางสาว|นาง|ว่าที่ร\.ต\.|นพ\.|พญ\.)/', '', $fullName);
$nameParts = explode(' ', trim($searchName));
$fname = $nameParts[0] ?? '';
$lname = $nameParts[1] ?? '';
if (!empty($fname)) {
$stmt = $pdo_hr->prepare("SELECT HR_CID FROM hr_person WHERE HR_FNAME LIKE ? AND (HR_LNAME LIKE ? OR ? = '') AND HR_IMAGE IS NOT NULL LIMIT 1");
$stmt->execute(["%$fname%", "%$lname%", $lname]);
$hr_person = $stmt->fetch(PDO::FETCH_ASSOC);
if ($hr_person && !empty($hr_person['HR_CID'])) {
$_SESSION['user_avatar'] = "api/hr_image.php?cid=" . urlencode($hr_person['HR_CID']);
}
}
}
} catch (Exception $e) {
// Ignore error
}
}
$userAvatar = $_SESSION['user_avatar'];
?>
<header class="h-20 glass-card m-4 px-6 flex items-center justify-between z-20 border-slate-200 dark:border-slate-700/50 rounded-[16px] shrink-0">
<div class="flex items-center">
<button @click="toggleSidebar()" class="text-slate-500 hover:text-slate-900 dark:hover:text-white focus:outline-none hidden sm:block p-2 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors">
<i class="fa-solid fa-bars text-xl"></i>
</button>
<!-- Mobile Menu Button -->
<button class="text-slate-500 sm:hidden p-2">
<i class="fa-solid fa-bars text-xl"></i>
</button>
<!-- Breadcrumbs -->
<nav class="hidden md:flex ml-4" aria-label="Breadcrumb">
<ol class="inline-flex items-center space-x-1 md:space-x-3">
<li class="inline-flex items-center">
<a href="index.php" class="inline-flex items-center text-sm font-medium text-slate-700 hover:text-primary-600 dark:text-slate-400 dark:hover:text-white">
<i class="fa-solid fa-house mr-2"></i>
หน้าหลัก
</a>
</li>
<?php if(isset($breadcrumbs) && is_array($breadcrumbs)): ?>
<?php foreach($breadcrumbs as $breadcrumb): ?>
<li aria-current="page">
<div class="flex items-center">
<i class="fa-solid fa-chevron-right text-slate-400 mx-2 text-xs"></i>
<span class="text-sm font-medium text-slate-500 dark:text-slate-400"><?= htmlspecialchars($breadcrumb) ?></span>
</div>
</li>
<?php endforeach; ?>
<?php else: ?>
<li aria-current="page">
<div class="flex items-center">
<i class="fa-solid fa-chevron-right text-slate-400 mx-2 text-xs"></i>
<span class="text-sm font-medium text-slate-500 dark:text-slate-400"><?= htmlspecialchars($pageTitleDisplay) ?></span>
</div>
</li>
<?php endif; ?>
</ol>
</nav>
</div>
<div class="flex items-center space-x-4">
<!-- Dark Mode Toggle -->
<button @click="toggleTheme()" class="p-2 rounded-lg text-slate-500 hover:text-primary-600 hover:bg-primary-50 dark:hover:text-primary-400 dark:hover:bg-slate-800 transition-colors relative overflow-hidden group">
<i class="fa-solid fa-sun text-xl absolute transition-all duration-500 transform" :class="darkMode ? 'opacity-0 scale-50 -rotate-90' : 'opacity-100 scale-100 rotate-0'"></i>
<i class="fa-solid fa-moon text-xl transition-all duration-500 transform" :class="darkMode ? 'opacity-100 scale-100 rotate-0' : 'opacity-0 scale-50 rotate-90'"></i>
</button>
<!-- Profile Dropdown -->
<div class="flex items-center cursor-pointer pl-2 border-l border-slate-200 dark:border-slate-700">
<img class="w-9 h-9 rounded-full object-cover border-2 border-primary-100 dark:border-primary-900" src="<?= htmlspecialchars($userAvatar) ?>" alt="User avatar">
<div class="hidden md:block ml-3">
<p class="text-sm font-medium dark:text-white"><?= htmlspecialchars($fullName) ?></p>
<p class="text-xs text-slate-500 dark:text-slate-400"><?= htmlspecialchars($roleName) ?></p>
</div>
<i class="fa-solid fa-chevron-down text-xs ml-2 text-slate-400"></i>
</div>
</div>
</header>
@@ -0,0 +1,112 @@
<?php
require_once __DIR__ . '/db.php';
/**
* Send message via LINE Notify
*/
function sendLineNotify($token, $message) {
if (empty($token)) return false;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://notify-api.line.me/api/notify");
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "message=" . urlencode($message));
$headers = [
'Content-type: application/x-www-form-urlencoded',
'Authorization: Bearer ' . $token,
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
return $error;
}
$res = json_decode($result, true);
if ($res && isset($res['status']) && $res['status'] == 200) {
return true;
}
return $res['message'] ?? 'Unknown error';
}
/**
* Send message via Telegram Bot API
*/
function sendTelegramMessage($token, $chat_id, $message) {
if (empty($token) || empty($chat_id)) return false;
$url = "https://api.telegram.org/bot{$token}/sendMessage";
$data = [
'chat_id' => $chat_id,
'text' => $message,
'parse_mode' => 'HTML'
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$result = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
return $error;
}
$res = json_decode($result, true);
if ($res && isset($res['ok']) && $res['ok'] === true) {
return true;
}
return $res['description'] ?? 'Unknown error';
}
/**
* Main function to send notifications based on event settings
*
* @param string $eventType e.g., 'vehicle', 'driver', 'schedule', 'maintenance'
* @param string $message The message to send
*/
function notifyEvent($eventType, $message) {
global $pdo;
try {
// Fetch settings
$stmt = $pdo->query("SELECT setting_key, setting_value FROM settings");
$settings = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
$lineToken = $settings['line_notify_token'] ?? '';
$telegramToken = $settings['telegram_bot_token'] ?? '';
$telegramChatId = $settings['telegram_chat_id'] ?? '';
$notifyEventsStr = $settings['notify_events'] ?? '[]';
$notifyEvents = json_decode($notifyEventsStr, true) ?: [];
// Check if this event type is enabled
if (in_array($eventType, $notifyEvents)) {
// Send LINE
if (!empty($lineToken)) {
sendLineNotify($lineToken, $message);
}
// Send Telegram
if (!empty($telegramToken) && !empty($telegramChatId)) {
sendTelegramMessage($telegramToken, $telegramChatId, $message);
}
}
} catch (Exception $e) {
// Silently fail for notifications so it doesn't break main app flow
error_log("Notification Error: " . $e->getMessage());
}
}
@@ -0,0 +1,79 @@
<?php
// กำหนดหน้าปัจจุบันเพื่อทำ Active State ใน Sidebar
$currentPage = basename($_SERVER['PHP_SELF']);
?>
<aside :class="isExpanded ? 'w-64' : 'w-20'" class="glass-card hidden sm:flex flex-col m-4 mr-0 rounded-[16px] z-20 transition-all duration-300 ease-in-out border-slate-200 dark:border-slate-700/50">
<!-- Logo area -->
<div class="h-20 flex items-center justify-center border-b border-slate-200 dark:border-slate-700/50 px-4 shrink-0">
<img src="public/images/logo.png" alt="Logo" class="w-10 h-10 rounded-full flex-shrink-0 bg-white">
<span x-show="isExpanded" x-transition.opacity.duration.300ms class="ml-3 font-semibold text-lg truncate dark:text-white">รพ.เกาะสมุย</span>
</div>
<!-- Menu -->
<nav class="flex-1 overflow-y-auto py-4 space-y-2 px-3 custom-scrollbar">
<!-- หน้าหลัก (ภาพรวม) -->
<a href="index.php" class="flex items-center px-3 py-3 rounded-lg group transition-colors <?= $currentPage === 'index.php' ? 'text-primary-600 bg-primary-50 dark:bg-primary-900/20' : 'text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800/50' ?>">
<i class="fa-solid fa-chart-pie w-6 text-center text-lg <?= $currentPage !== 'index.php' ? 'group-hover:text-primary-500 transition-colors' : '' ?>"></i>
<span x-show="isExpanded" class="ml-3 font-medium <?= $currentPage !== 'index.php' ? 'group-hover:text-slate-900 dark:group-hover:text-white transition-colors' : '' ?>">ภาพรวม</span>
</a>
<!-- ยานพาหนะ -->
<a href="vehicles.php" class="flex items-center px-3 py-3 rounded-lg group transition-colors <?= $currentPage === 'vehicles.php' ? 'text-primary-600 bg-primary-50 dark:bg-primary-900/20' : 'text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800/50' ?>">
<i class="fa-solid fa-car w-6 text-center text-lg <?= $currentPage !== 'vehicles.php' ? 'group-hover:text-primary-500 transition-colors' : '' ?>"></i>
<span x-show="isExpanded" class="ml-3 font-medium <?= $currentPage !== 'vehicles.php' ? 'group-hover:text-slate-900 dark:group-hover:text-white transition-colors' : '' ?>">ยานพาหนะ</span>
</a>
<!-- พนักงานขับรถ -->
<a href="drivers.php" class="flex items-center px-3 py-3 rounded-lg group transition-colors <?= $currentPage === 'drivers.php' ? 'text-primary-600 bg-primary-50 dark:bg-primary-900/20' : 'text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800/50' ?>">
<i class="fa-solid fa-id-card w-6 text-center text-lg <?= $currentPage !== 'drivers.php' ? 'group-hover:text-primary-500 transition-colors' : '' ?>"></i>
<span x-show="isExpanded" class="ml-3 font-medium <?= $currentPage !== 'drivers.php' ? 'group-hover:text-slate-900 dark:group-hover:text-white transition-colors' : '' ?>">พนักงานขับรถ</span>
</a>
<!-- ตารางการเดินรถ -->
<a href="schedule.php" class="flex items-center px-3 py-3 rounded-lg group transition-colors <?= $currentPage === 'schedule.php' ? 'text-primary-600 bg-primary-50 dark:bg-primary-900/20' : 'text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800/50' ?>">
<i class="fa-regular fa-calendar-check w-6 text-center text-lg <?= $currentPage !== 'schedule.php' ? 'group-hover:text-primary-500 transition-colors' : '' ?>"></i>
<span x-show="isExpanded" class="ml-3 font-medium <?= $currentPage !== 'schedule.php' ? 'group-hover:text-slate-900 dark:group-hover:text-white transition-colors' : '' ?>">ตารางการเดินรถ</span>
</a>
<?php if (isset($_SESSION['role']) && $_SESSION['role'] === 'admin'): ?>
<!-- หมวดหมู่การตั้งค่าระบบ -->
<div x-data="{ settingsOpen: <?= in_array($currentPage, ['users.php', 'settings_notifications.php', 'logs.php']) ? 'true' : 'false' ?> }">
<button @click="settingsOpen = !settingsOpen; if(!isExpanded) toggleSidebar()"
class="w-full flex items-center justify-between px-3 py-3 rounded-lg group transition-colors <?= in_array($currentPage, ['users.php', 'settings_notifications.php', 'logs.php']) ? 'text-primary-600 bg-primary-50 dark:bg-primary-900/20' : 'text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800/50' ?>">
<div class="flex items-center">
<i class="fa-solid fa-gear w-6 text-center text-lg <?= !in_array($currentPage, ['users.php', 'settings_notifications.php', 'logs.php']) ? 'group-hover:text-primary-500 transition-colors' : '' ?>"></i>
<span x-show="isExpanded" class="ml-3 font-medium <?= !in_array($currentPage, ['users.php', 'settings_notifications.php', 'logs.php']) ? 'group-hover:text-slate-900 dark:group-hover:text-white transition-colors' : '' ?>">ตั้งค่าระบบ</span>
</div>
<i x-show="isExpanded" class="fa-solid fa-chevron-down text-xs transition-transform duration-300" :class="settingsOpen ? 'rotate-180' : ''"></i>
</button>
<!-- เมนูย่อย -->
<div x-show="isExpanded && settingsOpen" x-transition.opacity class="pl-11 pr-3 py-2 space-y-1">
<a href="users.php" class="block px-3 py-2 rounded-lg text-sm transition-colors <?= $currentPage === 'users.php' ? 'text-primary-600 font-medium bg-primary-50 dark:bg-primary-900/20' : 'text-slate-500 dark:text-slate-400 hover:text-slate-900 hover:bg-slate-50 dark:hover:text-white dark:hover:bg-slate-800/50' ?>">
<i class="fa-solid fa-users-gear mr-2 w-4"></i> ตั้งค่าผู้ใช้งาน
</a>
<a href="settings_notifications.php" class="block px-3 py-2 rounded-lg text-sm transition-colors <?= $currentPage === 'settings_notifications.php' ? 'text-primary-600 font-medium bg-primary-50 dark:bg-primary-900/20' : 'text-slate-500 dark:text-slate-400 hover:text-slate-900 hover:bg-slate-50 dark:hover:text-white dark:hover:bg-slate-800/50' ?>">
<i class="fa-solid fa-bell mr-2 w-4"></i> การแจ้งเตือน
</a>
<a href="logs.php" class="block px-3 py-2 rounded-lg text-sm transition-colors <?= $currentPage === 'logs.php' ? 'text-primary-600 font-medium bg-primary-50 dark:bg-primary-900/20' : 'text-slate-500 dark:text-slate-400 hover:text-slate-900 hover:bg-slate-50 dark:hover:text-white dark:hover:bg-slate-800/50' ?>">
<i class="fa-solid fa-list-check mr-2 w-4"></i> ประวัติการใช้งาน
</a>
</div>
</div>
<?php endif; ?>
<!-- คู่มือการใช้งาน -->
<a href="manual.php" class="flex items-center px-3 py-3 rounded-lg group transition-colors <?= $currentPage === 'manual.php' ? 'text-primary-600 bg-primary-50 dark:bg-primary-900/20' : 'text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800/50' ?>">
<i class="fa-solid fa-book w-6 text-center text-lg <?= $currentPage !== 'manual.php' ? 'group-hover:text-primary-500 transition-colors' : '' ?>"></i>
<span x-show="isExpanded" class="ml-3 font-medium <?= $currentPage !== 'manual.php' ? 'group-hover:text-slate-900 dark:group-hover:text-white transition-colors' : '' ?>">คู่มือการใช้งาน</span>
</a>
</nav>
<!-- Bottom Actions -->
<div class="p-4 border-t border-slate-200 dark:border-slate-700/50 shrink-0">
<a href="logout.php" class="flex items-center px-3 py-2 text-danger hover:bg-red-50 dark:hover:bg-red-900/20 rounded-lg transition-colors">
<i class="fa-solid fa-arrow-right-from-bracket w-6 text-center text-lg"></i>
<span x-show="isExpanded" class="ml-3 font-medium">ออกจากระบบ</span>
</a>
</div>
</aside>
@@ -0,0 +1,43 @@
<?php
// กำหนดว่า Environment ปัจจุบันเป็น Development หรือไม่
// (ควรตั้งค่าเป็น false เมื่อนำไปใช้งานบนเซิร์ฟเวอร์จริง)
define('IS_DEV', false);
define('VITE_HOST', 'http://localhost:5173');
function vite($entry = 'src/js/app.js') {
$html = '';
// ตั้งค่า Base URL ให้เป็น path สัมพัทธ์ (Relative Path) เพื่อรองรับการรันในโฟลเดอร์ย่อย (เช่น /intranet/.../)
$dist_url = 'dist/';
if (IS_DEV) {
$html .= '<script type="module" src="' . VITE_HOST . '/@vite/client"></script>';
$html .= '<script type="module" src="' . VITE_HOST . '/' . $entry . '"></script>';
} else {
// ในโหมด Production เราจะอ่านไฟล์จาก manifest.json ที่ถูก Build แล้ว
$manifestPath = __DIR__ . '/../dist/.vite/manifest.json';
if (file_exists($manifestPath)) {
$manifest = json_decode(file_get_contents($manifestPath), true);
if (isset($manifest[$entry])) {
$file = $manifest[$entry]['file'];
// ตรวจสอบว่ามีไฟล์ CSS ที่ผูกกับ JS ตัวนี้หรือไม่
if (isset($manifest[$entry]['css'])) {
foreach ($manifest[$entry]['css'] as $cssFile) {
$html .= '<link rel="stylesheet" href="' . $dist_url . $cssFile . '">';
}
}
// โหลดไฟล์ JS หลัก
$html .= '<script type="module" src="' . $dist_url . $file . '?v=' . time() . '"></script>';
}
} else {
$html .= '<!-- Vite Manifest Not Found! Please run `npm run build` -->';
}
}
return $html;
}
?>