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,34 @@
<?php
// api/analytics.php
require_once dirname(__DIR__) . '/config/config.php';
require_once dirname(__DIR__) . '/config/database.php';
header('Content-Type: application/json');
// Need to be logged in
if (!isset($_SESSION['user_id'])) {
echo json_encode(['status' => 'error', 'message' => 'Unauthorized']);
exit;
}
$action = $_REQUEST['action'] ?? '';
// In a real application, these queries would join the `jobs` and `job_timelines` tables
// to calculate precise response times and SLAs.
if ($action === 'get_dashboard_stats') {
// Mock response for dashboard
$data = [
'avg_response_time' => 2.5,
'sla_compliance' => 94.2,
'total_jobs_today' => 128,
'trend' => [150, 140, 160, 180, 190, 120, 110],
'sla_breakdown' => [
'labels' => ['ER', 'OPD1', 'OPD2', 'IPD1', 'IPD2', 'X-Ray', 'OR'],
'passed' => [50, 45, 30, 40, 35, 60, 20],
'failed' => [5, 2, 1, 4, 2, 3, 0]
]
];
echo json_encode(['status' => 'success', 'data' => $data]);
} else {
echo json_encode(['status' => 'error', 'message' => 'Unknown action']);
}
@@ -0,0 +1,54 @@
<?php
// api/avatar.php
require_once dirname(__DIR__) . '/config/config.php';
require_once dirname(__DIR__) . '/config/database.php';
// Prevent caching to ensure we get the latest image if changed, though we might want to cache it eventually.
// Let's add standard caching headers for performance (e.g. cache for 1 day).
$cache_time = 86400;
header("Cache-Control: max-age=$cache_time, public");
$username = $_GET['username'] ?? '';
$name = $_GET['name'] ?? 'User';
$fallback_url = "https://ui-avatars.com/api/?name=" . urlencode($name) . "&background=random";
if (empty($username)) {
header("Location: $fallback_url");
exit;
}
$hos_pdo = Database::getHosInstance();
if (!$hos_pdo) {
header("Location: $fallback_url");
exit;
}
try {
$sql = "SELECT HR_IMAGE FROM hr_person WHERE HR_CID = ? AND HR_STATUS_ID='01'";
$stmt = $hos_pdo->prepare($sql);
$stmt->execute([$username]);
$person = $stmt->fetch();
if ($person && !empty($person['HR_IMAGE'])) {
// Output the BLOB image
// Try to determine mime type, or default to jpeg
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->buffer($person['HR_IMAGE']);
if ($mime === 'application/x-empty' || empty($mime)) {
$mime = 'image/jpeg';
}
header("Content-Type: $mime");
echo $person['HR_IMAGE'];
exit;
}
} catch (PDOException $e) {
// Silently fall back to UI Avatars on error
}
// If no image or error, redirect to fallback
header("Location: $fallback_url");
exit;
@@ -0,0 +1,64 @@
<?php
// api/chat.php
require_once dirname(__DIR__) . '/config/config.php';
require_once dirname(__DIR__) . '/config/database.php';
header('Content-Type: application/json');
if (!isset($_SESSION['user_id'])) {
echo json_encode(['status' => 'error', 'message' => 'Unauthorized']);
exit;
}
$action = $_REQUEST['action'] ?? '';
$conn = Database::getInstance();
if ($action === 'get_messages') {
$job_id = $_GET['job_id'] ?? '';
if (empty($job_id)) {
echo json_encode(['status' => 'error', 'message' => 'Job ID required']);
exit;
}
$query = "SELECT m.*, u.full_name, u.role
FROM job_messages m
JOIN users u ON m.user_id = u.id
WHERE m.job_id = :job_id
ORDER BY m.created_at ASC";
$stmt = $conn->prepare($query);
$stmt->bindParam(':job_id', $job_id);
$stmt->execute();
$messages = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode(['status' => 'success', 'data' => $messages]);
} elseif ($action === 'send_message') {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['status' => 'error', 'message' => 'Invalid method']);
exit;
}
$job_id = $_POST['job_id'] ?? '';
$message = trim($_POST['message'] ?? '');
$user_id = $_SESSION['user_id'];
if (empty($job_id) || empty($message)) {
echo json_encode(['status' => 'error', 'message' => 'ข้อมูลไม่ครบถ้วน']);
exit;
}
try {
$query = "INSERT INTO job_messages (job_id, user_id, message) VALUES (:job_id, :user_id, :message)";
$stmt = $conn->prepare($query);
$stmt->bindParam(':job_id', $job_id);
$stmt->bindParam(':user_id', $user_id);
$stmt->bindParam(':message', $message);
$stmt->execute();
echo json_encode(['status' => 'success']);
} catch (Exception $e) {
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
}
} else {
echo json_encode(['status' => 'error', 'message' => 'Invalid action']);
}
@@ -0,0 +1,67 @@
<?php
// api/dashboard.php
require_once dirname(__DIR__) . '/config/database.php';
require_once dirname(__DIR__) . '/models/Job.php';
header('Content-Type: application/json');
// Need to be logged in
session_start();
if (!isset($_SESSION['user_id'])) {
echo json_encode(['status' => 'error', 'message' => 'Unauthorized']);
exit;
}
$conn = Database::getInstance();
// 1. Fetch Stats
$stats_query = "
SELECT
COUNT(*) as total,
SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending,
SUM(CASE WHEN status IN ('assigned', 'in_progress', 'waiting_for_return') THEN 1 ELSE 0 END) as in_progress,
SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed
FROM jobs
WHERE DATE(created_at) = CURDATE()
";
$stmt = $conn->query($stats_query);
$stats = $stmt->fetch();
// 2. Fetch Latest Jobs (Limit 10)
$jobs_query = "
SELECT j.*,
fd.name as from_dept,
COALESCE(td.name, j.to_department_custom) as to_dept
FROM jobs j
LEFT JOIN departments fd ON j.from_department_id = fd.id
LEFT JOIN departments td ON j.to_department_id = td.id
ORDER BY j.created_at DESC
LIMIT 10
";
$stmt2 = $conn->query($jobs_query);
$jobs = $stmt2->fetchAll();
// 3. Fetch Online Staff
$staff_query = "
SELECT id, username, full_name, status
FROM users
WHERE role IN ('staff', 'nurse')
AND status != 'offline'
ORDER BY status DESC, username ASC
";
$stmt3 = $conn->query($staff_query);
$staff = $stmt3->fetchAll();
echo json_encode([
'status' => 'success',
'data' => [
'stats' => [
'total' => $stats['total'] ?? 0,
'pending' => $stats['pending'] ?? 0,
'in_progress' => $stats['in_progress'] ?? 0,
'completed' => $stats['completed'] ?? 0
],
'jobs' => $jobs,
'staff' => $staff
]
]);
@@ -0,0 +1,129 @@
<?php
// api/executive.php
session_start();
require_once dirname(__DIR__) . '/config/database.php';
require_once dirname(__DIR__) . '/models/Job.php';
header('Content-Type: application/json; charset=utf-8');
if (!isset($_SESSION['user_id'])) {
echo json_encode(['success' => false, 'message' => 'Unauthorized']);
exit;
}
$conn = Database::getInstance();
$period = $_GET['period'] ?? 'today';
try {
$start_date = '';
$end_date = date('Y-m-d') . ' 23:59:59';
if ($period === 'week') {
$start_date = date('Y-m-d', strtotime('-7 days')) . ' 00:00:00';
} elseif ($period === 'month') {
$start_date = date('Y-m-01') . ' 00:00:00';
} else { // today
$start_date = date('Y-m-d') . ' 00:00:00';
}
// 1. SLA & Times
$sla_target = 15;
$query_times = "SELECT
TIMESTAMPDIFF(MINUTE, created_at, accepted_at) as wait_time,
TIMESTAMPDIFF(MINUTE, accepted_at, completed_at) as service_time
FROM jobs
WHERE status = 'completed' AND created_at BETWEEN :start AND :end";
$stmt_times = $conn->prepare($query_times);
$stmt_times->bindParam(':start', $start_date);
$stmt_times->bindParam(':end', $end_date);
$stmt_times->execute();
$completed_jobs = $stmt_times->fetchAll(PDO::FETCH_ASSOC);
$total_wait = 0;
$total_service = 0;
$sla_met = 0;
foreach ($completed_jobs as $job) {
$w = max(0, (int)$job['wait_time']);
$s = max(0, (int)$job['service_time']);
$total_wait += $w;
$total_service += $s;
if ($w <= $sla_target) {
$sla_met++;
}
}
$completed_count = count($completed_jobs);
$avg_wait = $completed_count > 0 ? round($total_wait / $completed_count) : 0;
$avg_service = $completed_count > 0 ? round($total_service / $completed_count) : 0;
$sla_percent = $completed_count > 0 ? round(($sla_met / $completed_count) * 100) : 100;
// 2. Trend Data (7 days)
$trend_data = [];
$trend_labels = [];
for ($i = 6; $i >= 0; $i--) {
$d = date('Y-m-d', strtotime("-$i days"));
$thai_days = ['อา.', 'จ.', 'อ.', 'พ.', 'พฤ.', 'ศ.', 'ส.'];
$day_index = date('w', strtotime($d));
$trend_labels[] = $thai_days[$day_index];
$q = "SELECT COUNT(*) as cnt FROM jobs WHERE DATE(created_at) = :d";
$s = $conn->prepare($q);
$s->bindParam(':d', $d);
$s->execute();
$trend_data[] = $s->fetch(PDO::FETCH_ASSOC)['cnt'];
}
// 3. Department Workload
$query_dept = "SELECT d.name, COUNT(j.id) as count
FROM jobs j
JOIN departments d ON j.from_department_id = d.id
WHERE j.created_at BETWEEN :start AND :end
GROUP BY d.id
ORDER BY count DESC
LIMIT 5";
$stmt_dept = $conn->prepare($query_dept);
$stmt_dept->bindParam(':start', $start_date);
$stmt_dept->bindParam(':end', $end_date);
$stmt_dept->execute();
$dept_labels = [];
$dept_data = [];
while ($row = $stmt_dept->fetch(PDO::FETCH_ASSOC)) {
$name = mb_strlen($row['name'], 'UTF-8') > 15 ? mb_substr($row['name'], 0, 15, 'UTF-8') . '...' : $row['name'];
$dept_labels[] = $name;
$dept_data[] = (int)$row['count'];
}
$jobModel = new Job();
$staffPerformance = $jobModel->getStaffPerformance($period);
echo json_encode([
'success' => true,
'kpi' => [
'sla_percent' => $sla_percent,
'avg_wait_time' => $avg_wait,
'avg_service_time' => $avg_service
],
'charts' => [
'trend' => [
'labels' => $trend_labels,
'data' => $trend_data
],
'departments' => [
'labels' => $dept_labels,
'data' => $dept_data
]
],
'staff_performance' => $staffPerformance
]);
exit;
} catch (Exception $e) {
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
}
@@ -0,0 +1,71 @@
<?php
// api/feedback.php
require_once dirname(__DIR__) . '/config/config.php';
require_once dirname(__DIR__) . '/config/database.php';
header('Content-Type: application/json');
// Need to be logged in
if (!isset($_SESSION['user_id'])) {
echo json_encode(['status' => 'error', 'message' => 'Unauthorized']);
exit;
}
$action = $_POST['action'] ?? '';
if ($action === 'rate_job') {
// CSRF check
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
echo json_encode(['status' => 'error', 'message' => 'Invalid CSRF Token']);
exit;
}
$job_id = $_POST['job_id'] ?? '';
$rating = (int)($_POST['rating'] ?? 0);
$feedback = trim($_POST['feedback'] ?? '');
if (empty($job_id) || $rating < 1 || $rating > 5) {
echo json_encode(['status' => 'error', 'message' => 'ข้อมูลไม่ครบถ้วน']);
exit;
}
$conn = Database::getInstance();
// Check if job exists and belongs to requester
$checkQuery = "SELECT id, requester_id, status FROM jobs WHERE id = :job_id LIMIT 1";
$checkStmt = $conn->prepare($checkQuery);
$checkStmt->bindParam(':job_id', $job_id);
$checkStmt->execute();
if ($checkStmt->rowCount() === 0) {
echo json_encode(['status' => 'error', 'message' => 'ไม่พบข้อมูลงาน']);
exit;
}
$job = $checkStmt->fetch();
// if ($job['requester_id'] != $_SESSION['user_id']) {
// echo json_encode(['status' => 'error', 'message' => 'ไม่มีสิทธิ์ประเมินงานนี้']);
// exit;
// }
if ($job['status'] !== 'completed') {
echo json_encode(['status' => 'error', 'message' => 'สามารถประเมินได้เฉพาะงานที่เสร็จสิ้นแล้ว']);
exit;
}
try {
$query = "UPDATE jobs SET rating = :rating, feedback = :feedback WHERE id = :job_id";
$stmt = $conn->prepare($query);
$stmt->bindParam(':rating', $rating);
$stmt->bindParam(':feedback', $feedback);
$stmt->bindParam(':job_id', $job_id);
$stmt->execute();
echo json_encode(['status' => 'success']);
} catch (Exception $e) {
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
}
} else {
echo json_encode(['status' => 'error', 'message' => 'Invalid action']);
}
@@ -0,0 +1,116 @@
<?php
// api/hr.php
require_once dirname(__DIR__) . '/config/config.php';
require_once dirname(__DIR__) . '/config/database.php';
header('Content-Type: application/json');
// Check if user is logged in
if (!isset($_SESSION['user_id'])) {
echo json_encode(['status' => 'error', 'message' => 'Unauthorized']);
exit;
}
$queryParam = $_POST['query'] ?? $_POST['cid'] ?? $_GET['query'] ?? $_GET['cid'] ?? '';
if (empty($queryParam)) {
echo json_encode(['status' => 'error', 'message' => 'กรุณาระบุเลขบัตรประชาชน หรือ ชื่อ-สกุล']);
exit;
}
$hos_pdo = Database::getHosInstance();
if (!$hos_pdo) {
echo json_encode(['status' => 'error', 'message' => 'ไม่สามารถเชื่อมต่อฐานข้อมูล HR ได้']);
exit;
}
try {
$sql = "SELECT a.*,
b.HR_DEPARTMENT_SUB_SUB_NAME,
c.HR_LEVEL_NAME,
d.HR_PERSON_TYPE_NAME,
e.HR_PREFIX_NAME,
f.HR_POSITION_NAME
FROM hr_person a
LEFT OUTER JOIN hr_department_sub_sub b on a.HR_DEPARTMENT_SUB_SUB_ID = b.HR_DEPARTMENT_SUB_SUB_ID
LEFT OUTER JOIN hr_level c ON a.HR_LEVEL_ID = c.HR_LEVEL_ID
LEFT OUTER JOIN hr_person_type d ON a.HR_PERSON_TYPE_ID = d.HR_PERSON_TYPE_ID
LEFT OUTER JOIN hr_prefix e ON a.HR_PREFIX_ID=e.HR_PREFIX_ID
LEFT OUTER JOIN hr_position f ON a.HR_POSITION_ID=f.HR_POSITION_ID";
$is_cid = (is_numeric(trim($queryParam)) && strlen(trim($queryParam)) === 13);
if ($is_cid) {
$sql .= " WHERE a.HR_CID = ? AND a.HR_STATUS_ID='01'";
$stmt = $hos_pdo->prepare($sql);
$stmt->execute([trim($queryParam)]);
} else {
$terms = explode(' ', preg_replace('/\s+/', ' ', trim($queryParam)));
if (count($terms) > 1) {
$sql .= " WHERE a.HR_FNAME LIKE ? AND a.HR_LNAME LIKE ? AND a.HR_STATUS_ID='01' LIMIT 10";
$stmt = $hos_pdo->prepare($sql);
$stmt->execute(["%{$terms[0]}%", "%{$terms[1]}%"]);
} else {
$sql .= " WHERE (a.HR_FNAME LIKE ? OR a.HR_LNAME LIKE ?) AND a.HR_STATUS_ID='01' LIMIT 10";
$stmt = $hos_pdo->prepare($sql);
$stmt->execute(["%{$terms[0]}%", "%{$terms[0]}%"]);
}
}
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (count($results) > 0) {
$formatted_results = [];
foreach ($results as $person) {
$fullName = ($person['HR_PREFIX_NAME'] ?? '') . ($person['HR_FNAME'] ?? '') . ' ' . ($person['HR_LNAME'] ?? '');
$department = $person['HR_DEPARTMENT_SUB_SUB_NAME'] ?? 'ไม่ระบุ';
$position = ($person['HR_POSITION_NAME'] ?? '') . ' ' . ($person['HR_LEVEL_NAME'] ?? '');
$person_type = $person['HR_PERSON_TYPE_NAME'] ?? 'ไม่ระบุ';
$cid = $person['HR_CID'] ?? '';
// Calculate work duration
$work_duration = 'ไม่ระบุวันที่เริ่มงาน';
if (!empty($person['HR_STARTWORK_DATE'])) {
try {
$startDate = new DateTime($person['HR_STARTWORK_DATE']);
$currentDate = new DateTime();
if ($startDate <= $currentDate) {
$interval = $currentDate->diff($startDate);
$work_duration = $interval->format('%y ปี %m เดือน %d วัน');
}
} catch (Exception $e) {
// Keep default
}
}
$formatted_results[] = [
'cid' => $cid,
'full_name' => trim($fullName),
'department' => trim($department),
'position' => trim($position),
'person_type' => trim($person_type),
'work_duration' => $work_duration
];
}
if (count($formatted_results) === 1) {
echo json_encode([
'status' => 'success',
'message' => 'พบข้อมูลเจ้าหน้าที่',
'data' => $formatted_results[0]
]);
} else {
echo json_encode([
'status' => 'multiple',
'message' => 'พบรายชื่อมากกว่า 1 คน กรุณาเลือกรายการที่ถูกต้อง',
'data' => $formatted_results
]);
}
} else {
echo json_encode(['status' => 'error', 'message' => 'ไม่พบข้อมูลเจ้าหน้าที่ หรือไม่ได้อยู่ในสถานะปฏิบัติงาน']);
}
} catch (PDOException $e) {
echo json_encode(['status' => 'error', 'message' => 'เกิดข้อผิดพลาดในการสืบค้นข้อมูล: ' . $e->getMessage()]);
}
@@ -0,0 +1,427 @@
<?php
// api/jobs.php
require_once dirname(__DIR__) . '/config/config.php';
require_once dirname(__DIR__) . '/models/Patient.php';
require_once dirname(__DIR__) . '/models/Job.php';
require_once dirname(__DIR__) . '/config/LineBot.php';
require_once dirname(__DIR__) . '/config/Dispatcher.php';
header('Content-Type: application/json');
$action = $_REQUEST['action'] ?? '';
// Check for post_max_size violation (which clears $_POST and $_FILES)
if ($_SERVER['REQUEST_METHOD'] === 'POST' && empty($_POST) && empty($_FILES) && isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] > 0) {
echo json_encode(['status' => 'error', 'message' => 'ไฟล์รูปภาพมีขนาดใหญ่เกินกว่าที่เซิร์ฟเวอร์จะรับได้ (เกินขีดจำกัด post_max_size) กรุณาลดขนาดไฟล์ก่อนอัปโหลด']);
exit;
}
// Need to be logged in (Except for public job creation)
if (!isset($_SESSION['user_id']) && $action !== 'create_public_job') {
echo json_encode(['status' => 'error', 'message' => 'Unauthorized']);
exit;
}
if ($action === 'search_patient') {
$hn = $_GET['hn'] ?? '';
if (empty($hn)) {
echo json_encode(['status' => 'error', 'message' => 'Missing HN']);
exit;
}
$patient = Patient::searchByHN($hn);
if ($patient) {
echo json_encode(['status' => 'success', 'data' => $patient]);
} else {
echo json_encode(['status' => 'error', 'message' => 'Patient not found']);
}
} elseif ($action === 'create_job') {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['status' => 'error', 'message' => 'Invalid method']);
exit;
}
// CSRF check
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
echo json_encode(['status' => 'error', 'message' => 'Invalid CSRF Token']);
exit;
}
$data = [
'patient_hn' => $_POST['patient_hn'] ?? '',
'patient_name' => $_POST['patient_name'] ?? '',
'from_department_id' => $_POST['from_department_id'] ?? '',
'to_department_id' => $_POST['to_department_id'] ?? '',
'equipment_type' => $_POST['equipment_type'] ?? 'wheelchair',
'priority' => $_POST['priority'] ?? 'normal',
'notes' => $_POST['notes'] ?? '',
'requester_id' => $_SESSION['user_id'],
'infection_control' => isset($_POST['infection_control']) ? 1 : 0,
'is_scheduled' => isset($_POST['is_scheduled']) ? (int)$_POST['is_scheduled'] : 0,
'scheduled_time' => $_POST['scheduled_time'] ?? null,
'is_round_trip' => isset($_POST['is_round_trip']) ? 1 : 0
];
if (empty($data['patient_hn']) || empty($data['from_department_id']) || empty($data['to_department_id'])) {
echo json_encode(['status' => 'error', 'message' => 'ข้อมูลไม่ครบถ้วน']);
exit;
}
$jobModel = new Job();
$job_number = $jobModel->create($data);
if ($job_number) {
require_once dirname(__DIR__) . '/models/Setting.php';
require_once dirname(__DIR__) . '/config/TelegramBot.php';
$settingModel = new Setting();
$auto_dispatch = $settingModel->get('auto_dispatch_enabled', '0');
$msg = "🚨 มีงานใหม่!\nหมายเลข: {$job_number}\nผู้ป่วย: {$data['patient_name']}\nอุปกรณ์: {$data['equipment_type']}";
// Trigger LINE Notification
$lineBot = new LineBot();
$lineBot->sendGroupMessage($msg, $job_number); // will return false if no token
// Trigger Telegram Notification
$telegramBot = new TelegramBot();
$telegramBot->sendGroupMessage($msg, $job_number);
// Smart Auto Dispatch (If enabled)
if ($auto_dispatch === '1') {
$dispatcher = new Dispatcher();
// Actually pass the job_number / ID to dispatcher
// Wait, Dispatcher takes job_id. job_number is just a string (e.g. JOB2024...).
// Let's assume jobModel->create() returns the inserted ID, or we need to find the ID.
// Oh, previously $job_number = $jobModel->create($data) actually returned job_number.
// Let's fetch the actual job_id to pass to autoDispatch.
$jobInfo = $jobModel->getByJobNumber($job_number);
if ($jobInfo) {
$dispatcher->autoDispatch($jobInfo['id']);
}
}
echo json_encode(['status' => 'success', 'job_number' => $job_number]);
} else {
echo json_encode(['status' => 'error', 'message' => 'เกิดข้อผิดพลาดในการบันทึกข้อมูล']);
}
} elseif ($action === 'create_public_job') {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['status' => 'error', 'message' => 'Invalid method']);
exit;
}
// CSRF check
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
echo json_encode(['status' => 'error', 'message' => 'Invalid CSRF Token']);
exit;
}
// Assign to a default admin user ID or get the first available admin
$jobModel = new Job();
$db = Database::getInstance();
$stmt = $db->query("SELECT id FROM users WHERE role = 'admin' LIMIT 1");
$admin = $stmt->fetch();
$requester_id = $admin ? $admin['id'] : 1;
$to_department_id = $_POST['to_department_id'] ?? '';
$to_department_custom = null;
if ($to_department_id === 'custom') {
$to_department_id = null;
$to_department_custom = trim($_POST['to_department_custom'] ?? '');
}
$patient_name = trim($_POST['patient_name'] ?? '');
// Handle Image Upload with Compression
$patient_image_path = null;
if (isset($_FILES['patient_image']) && $_FILES['patient_image']['error'] === UPLOAD_ERR_OK) {
$uploadDir = dirname(__DIR__) . '/uploads/patients/';
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0777, true);
}
$fileExt = strtolower(pathinfo($_FILES['patient_image']['name'], PATHINFO_EXTENSION));
$allowedExt = ['jpg', 'jpeg', 'png', 'webp'];
if (in_array($fileExt, $allowedExt)) {
// Force save as JPG for better compression of photos
$fileName = uniqid('img_') . '_' . time() . '.jpg';
$destPath = $uploadDir . $fileName;
$sourcePath = $_FILES['patient_image']['tmp_name'];
// Image compression and resize logic (Max 800px, 75% quality)
$info = getimagesize($sourcePath);
if ($info !== false && function_exists('imagecreatefromjpeg')) {
$image = null;
if ($info['mime'] == 'image/jpeg') $image = imagecreatefromjpeg($sourcePath);
elseif ($info['mime'] == 'image/png') $image = imagecreatefrompng($sourcePath);
elseif ($info['mime'] == 'image/webp' && function_exists('imagecreatefromwebp')) $image = imagecreatefromwebp($sourcePath);
elseif ($info['mime'] == 'image/gif') $image = imagecreatefromgif($sourcePath);
if ($image !== null) {
$maxWidth = 800;
$width = $info[0];
$height = $info[1];
if ($width > $maxWidth || $height > $maxWidth) {
$ratio = $width / $height;
if ($ratio > 1) {
$newWidth = $maxWidth;
$newHeight = $maxWidth / $ratio;
} else {
$newWidth = $maxWidth * $ratio;
$newHeight = $maxWidth;
}
$newImage = imagecreatetruecolor($newWidth, $newHeight);
// Convert white background for transparent images
$white = imagecolorallocate($newImage, 255, 255, 255);
imagefill($newImage, 0, 0, $white);
imagecopyresampled($newImage, $image, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
$image = $newImage;
}
// Save as JPEG
if (imagejpeg($image, $destPath, 75)) {
$patient_image_path = 'uploads/patients/' . $fileName;
}
imagedestroy($image);
} else {
if (move_uploaded_file($sourcePath, $destPath)) {
$patient_image_path = 'uploads/patients/' . $fileName;
}
}
} else {
// Fallback if getimagesize fails, GD missing, or extension is allowed (rare)
if (move_uploaded_file($sourcePath, $destPath)) {
$patient_image_path = 'uploads/patients/' . $fileName;
}
}
}
}
if (empty($patient_name) && empty($patient_image_path)) {
echo json_encode(['status' => 'error', 'message' => 'กรุณาระบุชื่อผู้ป่วยหรือถ่ายรูปอย่างน้อยหนึ่งอย่าง']);
exit;
}
if (empty($_POST['from_department_id']) || (empty($to_department_id) && empty($to_department_custom))) {
echo json_encode(['status' => 'error', 'message' => 'ข้อมูลจุดรับส่งไม่ครบถ้วน']);
exit;
}
$data = [
'patient_hn' => $_POST['patient_hn'] ?? '',
'patient_name' => $patient_name,
'patient_image' => $patient_image_path,
'from_department_id' => $_POST['from_department_id'] ?? '',
'to_department_id' => $to_department_id,
'to_department_custom' => $to_department_custom,
'equipment_type' => $_POST['equipment_type'] ?? 'wheelchair',
'priority' => $_POST['priority'] ?? 'normal',
'notes' => ($_POST['notes'] ?? '') . "\n[เรียกผ่าน QR Code จุดรับผู้ป่วย]",
'requester_id' => $requester_id,
'infection_control' => isset($_POST['infection_control']) ? 1 : 0,
'is_scheduled' => 0,
'scheduled_time' => null,
'is_round_trip' => isset($_POST['is_round_trip']) ? 1 : 0
];
try {
$job_number = $jobModel->create($data);
if ($job_number) {
require_once dirname(__DIR__) . '/models/Setting.php';
require_once dirname(__DIR__) . '/config/TelegramBot.php';
$settingModel = new Setting();
$auto_dispatch = $settingModel->get('auto_dispatch_enabled', '0');
$display_name = empty($data['patient_name']) ? 'ไม่ระบุชื่อ (ดูรูปในระบบ)' : $data['patient_name'];
$display_to = empty($data['to_department_id']) ? $data['to_department_custom'] : "แผนกปลายทาง (ID: {$data['to_department_id']})";
$msg = "🚨 แสกนเรียกจากจุดรับ!\nหมายเลข: {$job_number}\nผู้ป่วย: {$display_name}\nปลายทาง: {$display_to}\nอุปกรณ์: {$data['equipment_type']}";
// Trigger LINE Notification
$lineBot = new LineBot();
$lineBot->sendGroupMessage($msg, $job_number);
// Trigger Telegram Notification
$telegramBot = new TelegramBot();
$telegramBot->sendGroupMessage($msg, $job_number);
// Smart Auto Dispatch (If enabled)
if ($auto_dispatch === '1') {
$dispatcher = new Dispatcher();
$jobInfo = $jobModel->getByJobNumber($job_number);
if ($jobInfo) {
$dispatcher->autoDispatch($jobInfo['id']);
}
}
echo json_encode(['status' => 'success', 'job_number' => $job_number]);
} else {
echo json_encode(['status' => 'error', 'message' => 'เกิดข้อผิดพลาดในการบันทึกข้อมูล']);
}
} catch (Throwable $e) {
echo json_encode(['status' => 'error', 'message' => 'เกิดข้อผิดพลาด: ' . $e->getMessage() . ' (Line: ' . $e->getLine() . ')']);
}
} elseif ($action === 'save_signature') {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['status' => 'error', 'message' => 'Invalid method']);
exit;
}
$job_id = $_POST['job_id'] ?? '';
$signature_data = $_POST['signature'] ?? '';
if (empty($job_id) || empty($signature_data)) {
echo json_encode(['status' => 'error', 'message' => 'Missing data']);
exit;
}
// Decode Base64 image
list($type, $signature_data) = explode(';', $signature_data);
list(, $signature_data) = explode(',', $signature_data);
$signature_data = base64_decode($signature_data);
$filename = "sig_" . time() . "_" . uniqid() . ".png";
$filepath = dirname(__DIR__) . "/uploads/signatures/" . $filename;
if (file_put_contents($filepath, $signature_data)) {
// Update jobs table with signature_path and set status to completed
$jobModel = new Job();
// Since we have job_number from client, we need job_id
$jobInfo = $jobModel->getByJobNumber($job_id);
if ($jobInfo) {
$jobModel->updateStatus($jobInfo['id'], 'completed', $_SESSION['user_id']);
// Add a quick direct SQL to update signature path
$db = Database::getInstance();
$stmt = $db->prepare("UPDATE jobs SET notes = CONCAT(IFNULL(notes,''), '\n[Signature: ', :sig, ']') WHERE id = :id");
$stmt->execute([':sig' => $filename, ':id' => $jobInfo['id']]);
}
echo json_encode(['status' => 'success', 'file' => $filename]);
} else {
echo json_encode(['status' => 'error', 'message' => 'Failed to save signature']);
}
} elseif ($action === 'get_active_job') {
$jobModel = new Job();
$activeJob = $jobModel->getActiveJobByStaff($_SESSION['user_id']);
if ($activeJob) {
require_once dirname(__DIR__) . '/models/Setting.php';
$settingModel = new Setting();
$equipments = json_decode($settingModel->get('equipment_types') ?: '[]', true);
$priorities = json_decode($settingModel->get('job_priorities') ?: '[]', true);
// Defaults
$activeJob['equipment_name'] = $activeJob['equipment_type'];
$activeJob['equipment_icon'] = 'fa-wheelchair';
$activeJob['priority_name'] = $activeJob['priority'];
$activeJob['priority_color'] = 'blue';
// Match equipment
foreach ($equipments as $eq) {
if ($eq['id'] === $activeJob['equipment_type']) {
$activeJob['equipment_name'] = $eq['name'];
$activeJob['equipment_icon'] = $eq['icon'];
break;
}
}
// Match priority
foreach ($priorities as $pri) {
if ($pri['id'] === $activeJob['priority']) {
$activeJob['priority_name'] = $pri['name'];
$activeJob['priority_color'] = $pri['color'];
break;
}
}
echo json_encode(['status' => 'success', 'data' => $activeJob]);
} else {
echo json_encode(['status' => 'error', 'message' => 'No active job']);
}
} elseif ($action === 'update_status') {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['status' => 'error', 'message' => 'Invalid method']);
exit;
}
$job_id = $_POST['job_id'] ?? '';
$new_status = $_POST['status'] ?? '';
if (empty($job_id) || empty($new_status)) {
echo json_encode(['status' => 'error', 'message' => 'Missing data']);
exit;
}
$jobModel = new Job();
$jobInfo = $jobModel->getByJobNumber($job_id);
if ($jobInfo) {
if ($jobModel->updateStatus($jobInfo['id'], $new_status, $_SESSION['user_id'])) {
echo json_encode(['status' => 'success', 'message' => 'Status updated']);
} else {
echo json_encode(['status' => 'error', 'message' => 'Failed to update status']);
}
} else {
echo json_encode(['status' => 'error', 'message' => 'Job not found']);
}
} elseif ($action === 'assign_job') {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['status' => 'error', 'message' => 'Invalid method']);
exit;
}
$job_id = $_POST['job_id'] ?? '';
if (empty($job_id)) {
echo json_encode(['status' => 'error', 'message' => 'Missing data']);
exit;
}
$jobModel = new Job();
$jobInfo = $jobModel->getByJobNumber($job_id);
if ($jobInfo && $jobInfo['status'] === 'pending') {
$db = Database::getInstance();
$stmt = $db->prepare("UPDATE jobs SET status = 'assigned', assigned_to = :user_id WHERE id = :id");
$stmt->bindParam(':user_id', $_SESSION['user_id']);
$stmt->bindParam(':id', $jobInfo['id']);
if ($stmt->execute()) {
echo json_encode(['status' => 'success', 'message' => 'รับงานสำเร็จ']);
} else {
echo json_encode(['status' => 'error', 'message' => 'ไม่สามารถรับงานได้']);
}
} else {
echo json_encode(['status' => 'error', 'message' => 'งานนี้ถูกรับไปแล้วหรือไม่พบงาน']);
}
} elseif ($action === 'cancel_job') {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['status' => 'error', 'message' => 'Invalid method']);
exit;
}
$job_id = $_POST['job_id'] ?? '';
$reason = $_POST['reason'] ?? '';
if (empty($job_id) || empty($reason)) {
echo json_encode(['status' => 'error', 'message' => 'Missing data']);
exit;
}
$jobModel = new Job();
$jobInfo = $jobModel->getByJobNumber($job_id);
if ($jobInfo) {
if ($jobModel->cancelJob($jobInfo['id'], $reason, $_SESSION['user_id'])) {
echo json_encode(['status' => 'success', 'message' => 'ยกเลิกงานสำเร็จ']);
} else {
echo json_encode(['status' => 'error', 'message' => 'ไม่สามารถยกเลิกงานได้']);
}
} else {
echo json_encode(['status' => 'error', 'message' => 'Job not found']);
}
} else {
echo json_encode(['status' => 'error', 'message' => 'Unknown action']);
}
@@ -0,0 +1,63 @@
<?php
// api/location.php
require_once dirname(__DIR__) . '/config/config.php';
require_once dirname(__DIR__) . '/config/database.php';
header('Content-Type: application/json');
if (!isset($_SESSION['user_id'])) {
echo json_encode(['status' => 'error', 'message' => 'Unauthorized']);
exit;
}
$action = $_REQUEST['action'] ?? '';
if ($action === 'update_location') {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['status' => 'error', 'message' => 'Invalid method']);
exit;
}
$lat = $_POST['lat'] ?? null;
$lng = $_POST['lng'] ?? null;
$user_id = $_SESSION['user_id'];
if ($lat && $lng) {
$db = Database::getInstance();
// Upsert location (Insert or Update if exists)
$query = "INSERT INTO user_locations (user_id, latitude, longitude)
VALUES (:user_id, :lat, :lng)
ON DUPLICATE KEY UPDATE
latitude = :lat2, longitude = :lng2, last_updated = CURRENT_TIMESTAMP";
$stmt = $db->prepare($query);
$stmt->bindParam(':user_id', $user_id);
$stmt->bindParam(':lat', $lat);
$stmt->bindParam(':lng', $lng);
$stmt->bindParam(':lat2', $lat);
$stmt->bindParam(':lng2', $lng);
if ($stmt->execute()) {
echo json_encode(['status' => 'success']);
} else {
echo json_encode(['status' => 'error', 'message' => 'DB update failed']);
}
} else {
echo json_encode(['status' => 'error', 'message' => 'Missing coords']);
}
} elseif ($action === 'get_locations') {
// API for the map view to get all staff locations
$db = Database::getInstance();
$query = "SELECT l.latitude, l.longitude, l.last_updated, u.full_name, u.status
FROM user_locations l
JOIN users u ON l.user_id = u.id
WHERE l.last_updated >= NOW() - INTERVAL 5 MINUTE";
$stmt = $db->prepare($query);
$stmt->execute();
$locations = $stmt->fetchAll();
echo json_encode(['status' => 'success', 'data' => $locations]);
} else {
echo json_encode(['status' => 'error', 'message' => 'Unknown action']);
}
@@ -0,0 +1,104 @@
<?php
// api/maps.php
require_once dirname(__DIR__) . '/config/config.php';
require_once dirname(__DIR__) . '/models/HospitalMap.php';
header('Content-Type: application/json');
if (!isset($_SESSION['user_id'])) {
echo json_encode(['status' => 'error', 'message' => 'Unauthorized']);
exit;
}
$action = $_REQUEST['action'] ?? '';
$mapModel = new HospitalMap();
if ($action === 'list') {
$status = $_GET['status'] ?? null;
$maps = $mapModel->getAll($status);
echo json_encode(['status' => 'success', 'data' => $maps]);
} elseif ($action === 'upload') {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['status' => 'error', 'message' => 'Invalid method']);
exit;
}
$name = $_POST['name'] ?? '';
$building = $_POST['building'] ?? '';
$floor = $_POST['floor'] ?? '';
$location = $_POST['transport_center_location'] ?? '';
$status = $_POST['status'] ?? 'active';
if (empty($name) || empty($building) || empty($floor)) {
echo json_encode(['status' => 'error', 'message' => 'กรุณากรอกข้อมูลให้ครบถ้วน']);
exit;
}
if (!isset($_FILES['map_image']) || $_FILES['map_image']['error'] !== UPLOAD_ERR_OK) {
echo json_encode(['status' => 'error', 'message' => 'กรุณาอัปโหลดไฟล์รูปภาพแผนผัง']);
exit;
}
// Process file upload
$file = $_FILES['map_image'];
$allowed_types = ['image/jpeg', 'image/png', 'image/webp'];
if (!in_array($file['type'], $allowed_types)) {
echo json_encode(['status' => 'error', 'message' => 'รองรับเฉพาะไฟล์รูปภาพ (JPG, PNG, WEBP) เท่านั้น']);
exit;
}
$upload_dir = dirname(__DIR__) . '/public/assets/img/maps/';
if (!is_dir($upload_dir)) {
mkdir($upload_dir, 0755, true);
}
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
$filename = 'map_' . time() . '_' . rand(1000, 9999) . '.' . $ext;
$target_path = $upload_dir . $filename;
if (move_uploaded_file($file['tmp_name'], $target_path)) {
$db_path = 'public/assets/img/maps/' . $filename;
$data = [
'name' => $name,
'building' => $building,
'floor' => $floor,
'image_path' => $db_path,
'transport_center_location' => $location,
'status' => $status
];
if ($mapModel->create($data)) {
echo json_encode(['status' => 'success', 'message' => 'อัปโหลดแผนผังเรียบร้อยแล้ว']);
} else {
// Delete file if DB insert fails
unlink($target_path);
echo json_encode(['status' => 'error', 'message' => 'เกิดข้อผิดพลาดในการบันทึกข้อมูล']);
}
} else {
echo json_encode(['status' => 'error', 'message' => 'ไม่สามารถอัปโหลดไฟล์ได้']);
}
} elseif ($action === 'delete') {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['status' => 'error', 'message' => 'Invalid method']);
exit;
}
$id = $_POST['id'] ?? '';
if (empty($id)) {
echo json_encode(['status' => 'error', 'message' => 'ID is required']);
exit;
}
if ($mapModel->delete($id)) {
echo json_encode(['status' => 'success', 'message' => 'ลบแผนผังเรียบร้อยแล้ว']);
} else {
echo json_encode(['status' => 'error', 'message' => 'ไม่สามารถลบแผนผังได้']);
}
} else {
echo json_encode(['status' => 'error', 'message' => 'Invalid action']);
}
@@ -0,0 +1,42 @@
<?php
// api/settings.php
require_once dirname(__DIR__) . '/config/config.php';
require_once dirname(__DIR__) . '/models/Setting.php';
header('Content-Type: application/json');
// Only allow Admin or Manager
if (!isset($_SESSION['user_id']) || !in_array($_SESSION['role'], ['admin', 'manager'])) {
echo json_encode(['status' => 'error', 'message' => 'Unauthorized']);
exit;
}
$action = $_REQUEST['action'] ?? '';
if ($action === 'save') {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['status' => 'error', 'message' => 'Invalid method']);
exit;
}
// CSRF Check
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
echo json_encode(['status' => 'error', 'message' => 'Invalid CSRF Token']);
exit;
}
$settingsData = $_POST['settings'] ?? [];
if (!empty($settingsData) && is_array($settingsData)) {
$settingModel = new Setting();
if ($settingModel->updateBulk($settingsData)) {
echo json_encode(['status' => 'success', 'message' => 'บันทึกการตั้งค่าเรียบร้อย']);
} else {
echo json_encode(['status' => 'error', 'message' => 'ไม่สามารถบันทึกข้อมูลลงฐานข้อมูลได้']);
}
} else {
echo json_encode(['status' => 'error', 'message' => 'ไม่มีข้อมูลให้บันทึก']);
}
} else {
echo json_encode(['status' => 'error', 'message' => 'Unknown action']);
}
@@ -0,0 +1,171 @@
<?php
// api/users.php
require_once dirname(__DIR__) . '/config/config.php';
require_once dirname(__DIR__) . '/models/User.php';
header('Content-Type: application/json');
$action = $_REQUEST['action'] ?? '';
if ($action === 'login') {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Validate CSRF
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
echo json_encode(['status' => 'error', 'message' => 'Invalid CSRF token']);
exit;
}
$username = trim($_POST['username'] ?? '');
$password = trim($_POST['password'] ?? '');
if (empty($username) || empty($password)) {
echo json_encode(['status' => 'error', 'message' => 'กรุณากรอกชื่อผู้ใช้งานและรหัสผ่าน']);
exit;
}
$userModel = new User();
if ($userModel->login($username, $password)) {
// Set session variables
$_SESSION['user_id'] = $userModel->id;
$_SESSION['username'] = $userModel->username;
$_SESSION['full_name'] = $userModel->full_name;
$_SESSION['role'] = $userModel->role;
$_SESSION['department_id'] = $userModel->department_id;
echo json_encode(['status' => 'success', 'message' => 'เข้าสู่ระบบสำเร็จ']);
} else {
echo json_encode(['status' => 'error', 'message' => 'ชื่อผู้ใช้งานหรือรหัสผ่านไม่ถูกต้อง']);
}
} else {
echo json_encode(['status' => 'error', 'message' => 'Method not allowed']);
}
} elseif ($action === 'logout') {
if (isset($_SESSION['user_id'])) {
$userModel = new User();
$userModel->updateStatus($_SESSION['user_id'], 'offline');
}
// Destroy session
session_unset();
session_destroy();
// Redirect to login page
header("Location: ../index.php?page=login");
exit;
} elseif ($action === 'add' && isset($_SESSION['role']) && $_SESSION['role'] === 'admin') {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
echo json_encode(['status' => 'error', 'message' => 'Invalid CSRF token']);
exit;
}
$username = trim($_POST['username'] ?? '');
$password = trim($_POST['password'] ?? '');
$full_name = trim($_POST['full_name'] ?? '');
$role = trim($_POST['role'] ?? '');
$department_id = !empty($_POST['department_id']) ? $_POST['department_id'] : null;
if (empty($username) || empty($password) || empty($full_name) || empty($role)) {
echo json_encode(['status' => 'error', 'message' => 'กรุณากรอกข้อมูลให้ครบถ้วน']);
exit;
}
$userModel = new User();
try {
if ($userModel->add($username, $password, $full_name, $role, $department_id)) {
echo json_encode(['status' => 'success', 'message' => 'เพิ่มเจ้าหน้าที่เรียบร้อยแล้ว']);
} else {
echo json_encode(['status' => 'error', 'message' => 'ไม่สามารถเพิ่มเจ้าหน้าที่ได้']);
}
} catch (PDOException $e) {
echo json_encode(['status' => 'error', 'message' => 'เกิดข้อผิดพลาด: ' . $e->getMessage()]);
}
}
} elseif ($action === 'edit' && isset($_SESSION['role']) && $_SESSION['role'] === 'admin') {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
echo json_encode(['status' => 'error', 'message' => 'Invalid CSRF token']);
exit;
}
$id = $_POST['id'] ?? '';
$full_name = trim($_POST['full_name'] ?? '');
$role = trim($_POST['role'] ?? '');
$department_id = !empty($_POST['department_id']) ? $_POST['department_id'] : null;
if (empty($id) || empty($full_name) || empty($role)) {
echo json_encode(['status' => 'error', 'message' => 'กรุณากรอกข้อมูลให้ครบถ้วน']);
exit;
}
$userModel = new User();
try {
if ($userModel->update($id, $full_name, $role, $department_id)) {
echo json_encode(['status' => 'success', 'message' => 'แก้ไขข้อมูลเจ้าหน้าที่เรียบร้อยแล้ว']);
} else {
echo json_encode(['status' => 'error', 'message' => 'ไม่สามารถแก้ไขข้อมูลได้']);
}
} catch (PDOException $e) {
echo json_encode(['status' => 'error', 'message' => 'เกิดข้อผิดพลาด: ' . $e->getMessage()]);
}
}
} elseif ($action === 'edit_password' && isset($_SESSION['role']) && $_SESSION['role'] === 'admin') {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
echo json_encode(['status' => 'error', 'message' => 'Invalid CSRF token']);
exit;
}
$id = $_POST['id'] ?? '';
$password = trim($_POST['password'] ?? '');
if (empty($id) || empty($password)) {
echo json_encode(['status' => 'error', 'message' => 'กรุณากรอกรหัสผ่านใหม่']);
exit;
}
$userModel = new User();
try {
if ($userModel->updatePassword($id, $password)) {
echo json_encode(['status' => 'success', 'message' => 'เปลี่ยนรหัสผ่านเรียบร้อยแล้ว']);
} else {
echo json_encode(['status' => 'error', 'message' => 'ไม่สามารถเปลี่ยนรหัสผ่านได้']);
}
} catch (PDOException $e) {
echo json_encode(['status' => 'error', 'message' => 'เกิดข้อผิดพลาด: ' . $e->getMessage()]);
}
}
} elseif ($action === 'delete' && isset($_SESSION['role']) && $_SESSION['role'] === 'admin') {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
echo json_encode(['status' => 'error', 'message' => 'Invalid CSRF token']);
exit;
}
$id = $_POST['id'] ?? '';
if (empty($id)) {
echo json_encode(['status' => 'error', 'message' => 'ไม่พบรหัสผู้ใช้งาน']);
exit;
}
// Prevent self-deletion
if ($id == $_SESSION['user_id']) {
echo json_encode(['status' => 'error', 'message' => 'ไม่สามารถลบบัญชีของตัวเองได้']);
exit;
}
$userModel = new User();
try {
if ($userModel->delete($id)) {
echo json_encode(['status' => 'success', 'message' => 'ลบเจ้าหน้าที่เรียบร้อยแล้ว']);
} else {
echo json_encode(['status' => 'error', 'message' => 'ไม่สามารถลบเจ้าหน้าที่ได้']);
}
} catch (PDOException $e) {
echo json_encode(['status' => 'error', 'message' => 'ไม่สามารถลบได้เนื่องจากมีการผูกกับงานอื่นอยู่']);
}
}
} else {
echo json_encode(['status' => 'error', 'message' => 'Invalid action']);
}