Files
gravity/บริหารจัดการงานเปล/views/public/request.php
T
2026-09-16 23:20:08 +07:00

290 lines
16 KiB
PHP

<?php
// views/public/request.php
require_once dirname(__DIR__, 2) . '/models/Department.php';
require_once dirname(__DIR__, 2) . '/models/Setting.php';
$deptModel = new Department();
$departments = $deptModel->getAllActive();
$settingModel = new Setting();
$equipmentsJson = $settingModel->get('equipment_types');
$equipments = $equipmentsJson ? json_decode($equipmentsJson, true) : [
['id' => 'wheelchair', 'name' => 'รถนั่ง (Wheelchair)', 'icon' => 'fa-wheelchair'],
['id' => 'stretcher', 'name' => 'รถนอน (Stretcher)', 'icon' => 'fa-bed'],
['id' => 'bed', 'name' => 'เตียง (Bed)', 'icon' => 'fa-bed-pulse']
];
$prioritiesJson = $settingModel->get('job_priorities');
$priorities = $prioritiesJson ? json_decode($prioritiesJson, true) : [
['id' => 'normal', 'name' => 'ทั่วไป (Normal)', 'color' => 'blue'],
['id' => 'urgent', 'name' => 'ด่วน (Urgency)', 'color' => 'amber'],
['id' => 'emergency', 'name' => 'ฉุกเฉิน (Emergency)', 'color' => 'red']
];
// Get fixed origin from URL
$fixed_dept_id = isset($_GET['dept_id']) ? (int)$_GET['dept_id'] : 0;
$fixed_dept = null;
if ($fixed_dept_id > 0) {
foreach ($departments as $dept) {
if ($dept['id'] == $fixed_dept_id) {
$fixed_dept = $dept;
break;
}
}
}
?>
<div class="max-w-3xl mx-auto py-8">
<div class="mb-6 text-center">
<div class="w-16 h-16 bg-emerald-100 text-emerald-600 rounded-full flex items-center justify-center text-3xl mx-auto mb-4">
<i class="fa-solid fa-qrcode"></i>
</div>
<h2 class="text-2xl font-bold text-slate-800 dark:text-white mb-2">เรียกรถเข็น / เวรเปลด่วน</h2>
<?php if ($fixed_dept): ?>
<p class="text-lg text-emerald-600 dark:text-emerald-400 font-medium">📍 จุดรับผู้ป่วย: <?= escape($fixed_dept['name']) ?></p>
<?php else: ?>
<p class="text-red-500 font-medium">⚠️ ไม่พบจุดรับผู้ป่วย กรุณาสแกน QR Code ใหม่อีกครั้ง</p>
<?php endif; ?>
</div>
<?php if ($fixed_dept): ?>
<div class="glass-card p-6 md:p-8">
<form id="publicRequestForm">
<input type="hidden" name="action" value="create_public_job">
<input type="hidden" name="csrf_token" value="<?= generateCSRFToken() ?>">
<input type="hidden" name="from_department_id" value="<?= $fixed_dept['id'] ?>">
<h4 class="text-lg font-semibold text-emerald-600 dark:text-emerald-400 mb-4 border-b border-emerald-100 dark:border-emerald-900 pb-2">1. ข้อมูลผู้ป่วย</h4>
<div class="grid grid-cols-1 md:grid-cols-2 gap-5 mb-6">
<div>
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">HN (ถ้าทราบ)</label>
<input type="text" class="glass-input w-full px-4 py-3" name="patient_hn" placeholder="ระบุ HN">
</div>
<div>
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">ชื่อ-สกุลผู้ป่วย</label>
<input type="text" class="glass-input w-full px-4 py-3" name="patient_name" id="patient_name" placeholder="ชื่อ นามสกุล">
</div>
<div class="col-span-1 md:col-span-2">
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">หรือถ่ายรูปเพื่อความรวดเร็วในการระบุตัวตน</label>
<input type="file" name="patient_image" id="patient_image" accept="image/*" capture="environment" class="glass-input w-full px-4 py-2 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-emerald-50 file:text-emerald-700 hover:file:bg-emerald-100">
<p class="text-xs text-slate-500 mt-1">* กรุณากรอกชื่อ หรือ ถ่ายรูปอย่างใดอย่างหนึ่ง</p>
</div>
</div>
<h4 class="text-lg font-semibold text-emerald-600 dark:text-emerald-400 mb-4 border-b border-emerald-100 dark:border-emerald-900 pb-2">2. ปลายทางและอุปกรณ์</h4>
<div class="mb-5">
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">จุดส่งผู้ป่วย <span class="text-red-500">*</span></label>
<select class="glass-input w-full px-4 py-3 text-lg" name="to_department_id" id="to_department_id">
<option value="">-- เลือกจุดส่ง (ปลายทาง) --</option>
<?php foreach($departments as $dept): ?>
<?php if($dept['id'] != $fixed_dept['id']): ?>
<option value="<?= $dept['id'] ?>"><?= escape($dept['name']) ?></option>
<?php endif; ?>
<?php endforeach; ?>
<option value="custom">อื่นๆ (พิมพ์ระบุเอง)</option>
</select>
<div id="custom_to_department_div" class="hidden mt-3">
<input type="text" name="to_department_custom" id="to_department_custom" class="glass-input w-full px-4 py-3" placeholder="โปรดระบุจุดปลายทาง...">
</div>
<div class="mt-3 flex items-center bg-blue-50 dark:bg-blue-900/20 p-3 rounded-lg border border-blue-100 dark:border-blue-800">
<input type="checkbox" id="is_round_trip" name="is_round_trip" value="1" class="w-5 h-5 text-blue-600 rounded border-blue-300 focus:ring-blue-500 cursor-pointer">
<label for="is_round_trip" class="ml-3 text-base font-medium text-blue-800 dark:text-blue-300 cursor-pointer">
<i class="fa-solid fa-rotate-left me-1"></i> ไป-กลับ (รอรับกลับทันที)
</label>
</div>
</div>
<div class="mb-6">
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">ประเภทอุปกรณ์ <span class="text-red-500">*</span></label>
<div class="grid grid-cols-1 gap-3">
<?php foreach($equipments as $index => $eq): ?>
<label class="relative flex items-center p-4 border border-slate-200 dark:border-slate-700 rounded-xl cursor-pointer hover:bg-slate-50 dark:hover:bg-slate-800 transition-colors">
<input type="radio" name="equipment_type" value="<?= escape($eq['id']) ?>" class="w-5 h-5 text-emerald-600 border-gray-300 focus:ring-emerald-500 dark:bg-slate-700 dark:border-slate-600" <?= $index === 0 ? 'required checked' : '' ?>>
<span class="ml-3 flex flex-col">
<span class="text-base font-medium text-slate-900 dark:text-white flex items-center gap-2">
<i class="fa-solid <?= escape($eq['icon']) ?> text-emerald-500 text-xl w-6"></i> <?= escape($eq['name']) ?>
</span>
</span>
</label>
<?php endforeach; ?>
</div>
</div>
<div class="mb-5">
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">ระดับความฉุกเฉิน</label>
<select class="glass-input w-full px-4 py-3" name="priority" required>
<?php foreach($priorities as $index => $pri): ?>
<option value="<?= escape($pri['id']) ?>" class="text-<?= escape($pri['color']) ?>-600 font-medium" <?= $index === 0 ? 'selected' : '' ?>>
<?= escape($pri['name']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-5 flex items-center gap-2 bg-red-50 dark:bg-red-900/20 p-4 rounded-xl border border-red-200 dark:border-red-800">
<input type="checkbox" id="infection_control" name="infection_control" value="1" class="w-5 h-5 text-red-600 rounded border-red-300 focus:ring-red-500">
<label for="infection_control" class="text-base font-medium text-red-800 dark:text-red-300">
<i class="fa-solid fa-biohazard me-1"></i> ผู้ป่วยโรคติดต่อ / แยกกักโรค
</label>
</div>
<div class="mb-8">
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">หมายเหตุ (ถ้ามี)</label>
<textarea class="glass-input w-full px-4 py-3" name="notes" rows="2" placeholder="เช่น ผู้ป่วยให้ออกซิเจน, ระวังสายน้ำเกลือ"></textarea>
</div>
<div class="pt-4 border-t border-slate-200 dark:border-slate-700">
<button type="submit" class="btn-primary-glass w-full py-4 text-lg font-bold flex items-center justify-center">
<span class="text"><i class="fa-solid fa-paper-plane me-2"></i> ยืนยันการเรียกเวรเปล</span>
</button>
</div>
</form>
</div>
<?php endif; ?>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
$('#to_department_id').change(function() {
if ($(this).val() === 'custom') {
$('#custom_to_department_div').removeClass('hidden');
$('#to_department_custom').prop('required', true);
} else {
$('#custom_to_department_div').addClass('hidden');
$('#to_department_custom').prop('required', false).val('');
}
});
$('#publicRequestForm').submit(function(e) {
e.preventDefault();
// Validate at least one of name or image
const patientName = $('#patient_name').val().trim();
const fileInput = document.getElementById('patient_image');
const file = fileInput.files[0];
if (!patientName && !file) {
Swal.fire('ข้อมูลไม่ครบถ้วน', 'กรุณากรอกชื่อ-สกุลผู้ป่วย หรือถ่ายรูปอย่างใดอย่างหนึ่ง', 'warning');
return;
}
const toDept = $('#to_department_id').val();
if (!toDept) {
Swal.fire('ข้อมูลไม่ครบถ้วน', 'กรุณาเลือกหรือระบุจุดส่งปลายทาง', 'warning');
return;
}
const btn = $(this).find('button[type="submit"]');
const originalText = btn.html();
btn.addClass('btn-loading');
// Use FormData for file upload
const formData = new FormData(this);
// Client-side Image Compression function
const compressImage = (file) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = event => {
const img = new Image();
img.src = event.target.result;
img.onload = () => {
const canvas = document.createElement('canvas');
const MAX_WIDTH = 800;
const MAX_HEIGHT = 800;
let width = img.width;
let height = img.height;
if (width > height) {
if (width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
}
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
// Handle rotation if needed (simplified) and draw image
// Draw white background for transparent images
ctx.fillStyle = '#FFFFFF';
ctx.fillRect(0, 0, width, height);
ctx.drawImage(img, 0, 0, width, height);
canvas.toBlob((blob) => {
if(blob) {
resolve(new File([blob], 'compressed.jpg', { type: 'image/jpeg' }));
} else {
reject(new Error('Canvas to Blob failed'));
}
}, 'image/jpeg', 0.7); // 70% quality
};
img.onerror = error => reject(error);
};
reader.onerror = error => reject(error);
});
};
const submitForm = () => {
$.ajax({
url: 'api/jobs.php',
type: 'POST',
data: formData,
processData: false,
contentType: false,
success: function(response) {
if (response.status === 'success') {
Swal.fire({
icon: 'success',
title: 'เรียกเวรเปลสำเร็จ',
text: 'ระบบได้รับข้อมูลของคุณแล้ว หมายเลขงาน: ' + response.job_number,
confirmButtonText: 'ตกลง',
background: document.documentElement.classList.contains('dark') ? '#1e293b' : '#fff',
color: document.documentElement.classList.contains('dark') ? '#f1f5f9' : '#1e293b'
}).then(() => {
window.location.reload();
});
} else {
btn.removeClass('btn-loading').html(originalText);
Swal.fire('ผิดพลาด', response.message, 'error');
}
},
error: function(xhr) {
btn.removeClass('btn-loading').html(originalText);
let errorMsg = 'เกิดข้อผิดพลาดในการเชื่อมต่อ';
try {
let res = JSON.parse(xhr.responseText);
if (res.message) errorMsg = res.message;
} catch(e) {}
Swal.fire('ผิดพลาด', errorMsg, 'error');
}
});
};
if (file) {
compressImage(file).then(compressedFile => {
formData.set('patient_image', compressedFile);
submitForm();
}).catch(err => {
console.error('Image compression failed', err);
submitForm(); // proceed without compression if failed
});
} else {
submitForm();
}
});
});
</script>