335 lines
24 KiB
PHP
335 lines
24 KiB
PHP
<?php
|
|
require_once 'includes/auth.php';
|
|
require_once 'includes/db.php';
|
|
|
|
$pageTitle = 'ตรวจสภาพรถยนต์ | ระบบจัดการข้อมูลยานพาหนะ โรงพยาบาลเกาะสมุย';
|
|
$pageTitleDisplay = 'ตรวจสภาพรถยนต์ประจำวัน';
|
|
$breadcrumbs = ['ตรวจสภาพรถยนต์'];
|
|
require_once 'includes/header.php';
|
|
|
|
// ดึงข้อมูลรถยนต์สำหรับการเลือก
|
|
$stmt = $pdo->query("SELECT id, license_plate, type, brand, model FROM vehicles ORDER BY license_plate ASC");
|
|
$vehicles = $stmt->fetchAll();
|
|
|
|
$defaultCid = isset($_GET['cid']) ? $_GET['cid'] : '1840400002613';
|
|
?>
|
|
|
|
<!-- Floating Background -->
|
|
<div class="fixed top-0 left-0 w-full h-full overflow-hidden -z-10 pointer-events-none">
|
|
<div class="absolute top-[-10%] left-[-10%] w-[40%] h-[40%] bg-primary-500/10 rounded-full blur-[100px]"></div>
|
|
<div class="absolute bottom-[-10%] right-[-10%] w-[40%] h-[40%] bg-secondary/10 rounded-full blur-[100px]"></div>
|
|
</div>
|
|
|
|
<!-- Layout Wrapper -->
|
|
<div class="flex h-screen overflow-hidden" x-data="inspectionForm()">
|
|
|
|
<!-- Sidebar -->
|
|
<?php include 'includes/sidebar.php'; ?>
|
|
|
|
<!-- Main Content -->
|
|
<main class="flex-1 flex flex-col min-w-0 overflow-hidden relative z-10">
|
|
<!-- Top Navbar -->
|
|
<?php include 'includes/navbar.php'; ?>
|
|
|
|
<!-- Dashboard Content -->
|
|
<div class="flex-1 overflow-y-auto p-4 md:p-6 custom-scrollbar page-transition">
|
|
|
|
<div class="max-w-4xl mx-auto glass-card p-6 md:p-8">
|
|
<!-- Header part -->
|
|
<div class="text-center mb-8 border-b border-slate-200 dark:border-slate-700 pb-6">
|
|
<h1 class="text-2xl md:text-3xl font-bold dark:text-white mb-2">แบบรายงานตรวจสภาพรถยนต์ราชการ</h1>
|
|
<p class="text-lg text-slate-700 dark:text-slate-300">หน่วยงานยานพาหนะ โรงพยาบาลเกาะสมุย กระทรวงสาธารณสุข</p>
|
|
<p class="text-md text-primary-600 dark:text-primary-400 font-medium italic mt-2">"บริการมีน้ำใจ ปลอดภัย ทันเวลา"</p>
|
|
</div>
|
|
|
|
<form @submit.prevent="submitForm" class="space-y-6">
|
|
|
|
<!-- General Info Section -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 p-5 bg-slate-50/50 dark:bg-slate-800/50 rounded-xl border border-slate-200 dark:border-slate-700">
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">เลขประจำตัวประชาชน (ผู้ตรวจ) <span class="text-danger">*</span></label>
|
|
<div class="relative">
|
|
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
|
<i class="fa-solid fa-id-card text-slate-400"></i>
|
|
</div>
|
|
<input type="text" x-model="form.inspector_cid" required class="glass-input block w-full pl-10 p-2.5 text-sm font-semibold text-primary-700" placeholder="เลขบัตรประชาชน 13 หลัก">
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">รถยนต์หมายเลขทะเบียน <span class="text-danger">*</span></label>
|
|
<select x-model="form.vehicle_id" required class="glass-input block w-full p-2.5 text-sm">
|
|
<option value="">-- เลือกรถยนต์ --</option>
|
|
<?php foreach($vehicles as $v): ?>
|
|
<option value="<?= $v['id'] ?>"><?= htmlspecialchars($v['license_plate'] . ' (' . $v['brand'] . ' ' . $v['model'] . ')') ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
|
|
<div x-init="initDatepicker($refs.dateInput)">
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">ประจำวันที่ <span class="text-danger">*</span></label>
|
|
<input type="text" x-ref="dateInput" required class="glass-input block w-full p-2.5 text-sm" placeholder="เลือกวันที่">
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">เวลา (น.) <span class="text-danger">*</span></label>
|
|
<input type="time" x-model="form.inspection_time" required class="glass-input block w-full p-2.5 text-sm">
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Inspection Table -->
|
|
<div class="overflow-x-auto border border-slate-200 dark:border-slate-700 rounded-xl shadow-sm">
|
|
<table class="w-full text-sm text-left text-slate-600 dark:text-slate-400">
|
|
<thead class="text-xs text-slate-700 uppercase bg-slate-100 dark:bg-slate-800 dark:text-slate-300">
|
|
<tr>
|
|
<th scope="col" class="sticky left-0 z-20 bg-slate-100 dark:bg-slate-800 px-3 py-3 text-center whitespace-nowrap border-r border-slate-200 dark:border-slate-700 w-[60px] min-w-[60px] shadow-[1px_0_0_0_#e2e8f0] dark:shadow-[1px_0_0_0_#334155]">ลำดับที่</th>
|
|
<th scope="col" class="sticky left-[60px] z-20 bg-slate-100 dark:bg-slate-800 px-4 py-3 text-center whitespace-nowrap border-r border-slate-200 dark:border-slate-700 min-w-[200px] shadow-[1px_0_0_0_#e2e8f0] dark:shadow-[1px_0_0_0_#334155]">รายงานสภาพรถยนต์</th>
|
|
<th scope="col" class="px-3 py-3 text-center whitespace-nowrap border-r border-slate-200 dark:border-slate-700 w-20">ปกติ</th>
|
|
<th scope="col" class="px-3 py-3 text-center whitespace-nowrap border-r border-slate-200 dark:border-slate-700 w-20">ไม่ปกติ</th>
|
|
<th scope="col" class="px-4 py-3 text-center whitespace-nowrap border-r border-slate-200 dark:border-slate-700 min-w-[150px]">ไม่ปกติเนื่องจาก</th>
|
|
<th scope="col" class="px-4 py-3 text-center whitespace-nowrap min-w-[150px]">หมายเหตุ</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<template x-for="(item, index) in inspectionItems" :key="index">
|
|
<tr class="group bg-white dark:bg-slate-900 border-b border-slate-200 dark:border-slate-700 hover:bg-slate-50 dark:hover:bg-slate-800/50 transition-colors">
|
|
<td class="sticky left-0 z-10 bg-white dark:bg-slate-900 group-hover:bg-slate-50 dark:group-hover:bg-slate-800/50 px-3 py-3 text-center border-r border-slate-200 dark:border-slate-700 font-medium shadow-[1px_0_0_0_#e2e8f0] dark:shadow-[1px_0_0_0_#334155]" x-text="index + 1"></td>
|
|
<td class="sticky left-[60px] z-10 bg-white dark:bg-slate-900 group-hover:bg-slate-50 dark:group-hover:bg-slate-800/50 px-4 py-3 border-r border-slate-200 dark:border-slate-700 font-medium text-slate-800 dark:text-slate-200 shadow-[1px_0_0_0_#e2e8f0] dark:shadow-[1px_0_0_0_#334155]" x-text="item.name"></td>
|
|
|
|
<!-- Normal Radio -->
|
|
<td class="px-3 py-3 text-center border-r border-slate-200 dark:border-slate-700">
|
|
<div class="flex items-center justify-center">
|
|
<input type="radio" :name="'status_'+index" value="normal" x-model="inspectionItems[index].status" @change="inspectionItems[index].reason = ''" class="w-5 h-5 cursor-pointer" style="appearance: auto; -webkit-appearance: auto; accent-color: #2563eb;">
|
|
</div>
|
|
</td>
|
|
|
|
<!-- Abnormal Radio -->
|
|
<td class="px-3 py-3 text-center border-r border-slate-200 dark:border-slate-700">
|
|
<div class="flex items-center justify-center">
|
|
<input type="radio" :name="'status_'+index" value="abnormal" x-model="inspectionItems[index].status" class="w-5 h-5 cursor-pointer" style="appearance: auto; -webkit-appearance: auto; accent-color: #dc2626;">
|
|
</div>
|
|
</td>
|
|
|
|
<!-- Reason -->
|
|
<td class="px-3 py-2 border-r border-slate-200 dark:border-slate-700">
|
|
<input type="text" x-model="inspectionItems[index].reason" :disabled="inspectionItems[index].status !== 'abnormal'" :required="inspectionItems[index].status === 'abnormal'" class="glass-input block w-full p-1.5 text-xs disabled:opacity-50 disabled:bg-slate-100 dark:disabled:bg-slate-800" placeholder="ระบุสาเหตุ...">
|
|
</td>
|
|
|
|
<!-- Remark -->
|
|
<td class="px-3 py-2">
|
|
<input type="text" x-model="inspectionItems[index].remark" class="glass-input block w-full p-1.5 text-xs" placeholder="หมายเหตุเพิ่มเติม">
|
|
</td>
|
|
</tr>
|
|
</template>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Additional Details -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div class="bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700 rounded-xl p-4 flex flex-col justify-center shadow-sm">
|
|
<label class="flex items-center justify-between text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
|
|
<span>12. เลขไมล์ประจำวันก่อนนำรถออกใช้บริการ</span>
|
|
<span class="text-xs text-slate-500">กิโลเมตร</span>
|
|
</label>
|
|
<input type="number" x-model="form.mileage" min="0" step="1" required class="glass-input block w-full p-2.5 text-sm font-medium" placeholder="ระบุเลขไมล์">
|
|
</div>
|
|
|
|
<div class="bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700 rounded-xl p-4 flex flex-col justify-center shadow-sm">
|
|
<label class="flex items-center justify-between text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
|
|
<span>13. น้ำมันเชื้อเพลิงเหลือในถังประจำวันประมาณ</span>
|
|
<span class="text-xs text-slate-500">ลิตร</span>
|
|
</label>
|
|
<input type="number" x-model="form.fuel_level" min="0" step="0.1" required class="glass-input block w-full p-2.5 text-sm font-medium" placeholder="ระบุปริมาณน้ำมัน">
|
|
</div>
|
|
|
|
<div class="md:col-span-2 bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700 rounded-xl p-4 shadow-sm">
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">14. รายการอื่นๆ</label>
|
|
<textarea x-model="form.other_items" rows="3" class="glass-input block w-full p-2.5 text-sm" placeholder="ระบุรายการตรวจเช็คอื่นๆ (ถ้ามี)"></textarea>
|
|
</div>
|
|
|
|
<!-- New Status Field -->
|
|
<div class="md:col-span-2 bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700 rounded-xl p-4 shadow-sm mt-2">
|
|
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-3">15. สรุปสถานะรถยนต์หลังการตรวจสอบ <span class="text-danger">*</span></label>
|
|
<div class="flex items-center space-x-6">
|
|
<label class="flex items-center cursor-pointer">
|
|
<input type="radio" x-model="form.vehicle_status" value="available" required class="w-5 h-5 text-success border-slate-300 focus:ring-success dark:border-slate-600 dark:bg-slate-700 accent-success">
|
|
<span class="ml-2 text-sm text-slate-700 dark:text-slate-300 font-medium">พร้อมใช้งาน</span>
|
|
</label>
|
|
<label class="flex items-center cursor-pointer">
|
|
<input type="radio" x-model="form.vehicle_status" value="maintenance" required class="w-5 h-5 text-danger border-slate-300 focus:ring-danger dark:border-slate-600 dark:bg-slate-700 accent-danger">
|
|
<span class="ml-2 text-sm text-slate-700 dark:text-slate-300 font-medium">ไม่พร้อมใช้งาน / ส่งซ่อม</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Submit Button -->
|
|
<div class="flex justify-end pt-4 border-t border-slate-200 dark:border-slate-700 mt-6">
|
|
<button type="button" @click="resetForm" class="px-5 py-2.5 text-sm font-medium text-slate-700 bg-white border border-slate-300 rounded-xl hover:bg-slate-50 mr-3 dark:bg-slate-800 dark:text-slate-300 dark:border-slate-600 dark:hover:bg-slate-700 transition-colors">
|
|
ล้างข้อมูล
|
|
</button>
|
|
<button type="submit" :disabled="isSubmitting" class="btn-gradient px-6 py-2.5 text-sm font-medium flex items-center shadow-lg shadow-primary-500/30 hover:shadow-primary-500/50 transition-all hover:-translate-y-0.5">
|
|
<i class="fa-solid fa-save mr-2" x-show="!isSubmitting"></i>
|
|
<i class="fa-solid fa-spinner fa-spin mr-2" x-show="isSubmitting" style="display: none;"></i>
|
|
<span x-text="isSubmitting ? 'กำลังบันทึก...' : 'บันทึกแบบรายงาน'"></span>
|
|
</button>
|
|
</div>
|
|
|
|
</form>
|
|
</div>
|
|
|
|
</div>
|
|
</main>
|
|
</div>
|
|
|
|
<!-- Flatpickr CSS & JS -->
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
|
|
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/flatpickr/dist/l10n/th.js"></script>
|
|
|
|
<!-- Alpine.js logic for form -->
|
|
<script>
|
|
document.addEventListener('alpine:init', () => {
|
|
Alpine.data('inspectionForm', () => ({
|
|
isSubmitting: false,
|
|
form: {
|
|
inspector_cid: '<?= htmlspecialchars($defaultCid) ?>',
|
|
vehicle_id: '',
|
|
inspection_date: new Date().toISOString().split('T')[0],
|
|
inspection_time: new Date().toLocaleTimeString('th-TH', { hour: '2-digit', minute: '2-digit' }),
|
|
mileage: '',
|
|
fuel_level: '',
|
|
other_items: '',
|
|
vehicle_status: 'available'
|
|
},
|
|
|
|
initDatepicker(element) {
|
|
const self = this;
|
|
flatpickr(element, {
|
|
locale: "th",
|
|
defaultDate: this.form.inspection_date,
|
|
dateFormat: "Y-m-d",
|
|
altInput: true,
|
|
altFormat: "j F Y",
|
|
formatDate: (date, format, locale) => {
|
|
if (format === "Y-m-d") {
|
|
const y = date.getFullYear();
|
|
const m = String(date.getMonth() + 1).padStart(2, '0');
|
|
const d = String(date.getDate()).padStart(2, '0');
|
|
return `${y}-${m}-${d}`;
|
|
}
|
|
// ปรับแสดงผลเป็นปี พ.ศ. เฉพาะใน input ที่ผู้ใช้เห็น (altInput)
|
|
const d = date.getDate();
|
|
const m = flatpickr.l10ns.th.months.longhand[date.getMonth()];
|
|
const y = date.getFullYear() + 543;
|
|
return `${d} ${m} ${y}`;
|
|
},
|
|
onChange: function(selectedDates, dateStr) {
|
|
self.form.inspection_date = dateStr; // ค่าที่เก็บในตัวแปรจะเป็น ค.ศ. (Y-m-d)
|
|
},
|
|
onReady: function(selectedDates, dateStr, instance) {
|
|
// เปลี่ยนปีในปฏิทินให้แสดงเป็น พ.ศ.
|
|
const updateYear = () => {
|
|
if (instance.currentYearElement) {
|
|
instance.currentYearElement.value = instance.currentYear + 543;
|
|
}
|
|
};
|
|
updateYear();
|
|
instance.config.onMonthChange.push(updateYear);
|
|
instance.config.onYearChange.push(updateYear);
|
|
}
|
|
});
|
|
},
|
|
|
|
inspectionItems: [
|
|
{ name: 'ความสะอาดของรถยนต์', status: '', reason: '', remark: '' },
|
|
{ name: 'น้ำมันเครื่อง', status: '', reason: '', remark: '' },
|
|
{ name: 'น้ำมันครัทช์', status: '', reason: '', remark: '' },
|
|
{ name: 'น้ำหม้อน้ำ', status: '', reason: '', remark: '' },
|
|
{ name: 'น้ำกลั่นแบตเตอรี่', status: '', reason: '', remark: '' },
|
|
{ name: 'น้ำมันเบรค', status: '', reason: '', remark: '' },
|
|
{ name: 'ระบบเบรค', status: '', reason: '', remark: '' },
|
|
{ name: 'ระบบไฟรถยนต์', status: '', reason: '', remark: '' },
|
|
{ name: 'ระบบจ่ายน้ำมันเชื้อเพลิง', status: '', reason: '', remark: '' },
|
|
{ name: 'ระบบเครื่องปรับอากาศ (แอร์)', status: '', reason: '', remark: '' },
|
|
{ name: 'ยางรถยนต์', status: '', reason: '', remark: '' }
|
|
],
|
|
|
|
resetForm() {
|
|
if(confirm('ต้องการล้างข้อมูลในฟอร์มทั้งหมดใช่หรือไม่?')) {
|
|
this.form.vehicle_id = '';
|
|
this.form.mileage = '';
|
|
this.form.fuel_level = '';
|
|
this.form.other_items = '';
|
|
this.inspectionItems.forEach(item => {
|
|
item.status = '';
|
|
item.reason = '';
|
|
item.remark = '';
|
|
});
|
|
}
|
|
},
|
|
|
|
async submitForm() {
|
|
// Validation checking
|
|
for(let i=0; i<this.inspectionItems.length; i++) {
|
|
let item = this.inspectionItems[i];
|
|
if(!item.status) {
|
|
Swal.fire({ icon: 'warning', title: 'ข้อมูลไม่ครบถ้วน', text: `กรุณาระบุสถานะ ปกติ/ไม่ปกติ สำหรับรายการที่ ${i+1} "${item.name}"`, confirmButtonColor: '#3b82f6' });
|
|
return;
|
|
}
|
|
if(item.status === 'abnormal' && !item.reason.trim()) {
|
|
Swal.fire({ icon: 'warning', title: 'ข้อมูลไม่ครบถ้วน', text: `กรุณาระบุสาเหตุที่รายการ "${item.name}" ไม่ปกติ`, confirmButtonColor: '#3b82f6' });
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(!this.form.vehicle_id) {
|
|
Swal.fire({ icon: 'warning', title: 'ข้อมูลไม่ครบถ้วน', text: 'กรุณาเลือกรถยนต์ที่ต้องการตรวจเช็ค', confirmButtonColor: '#3b82f6' });
|
|
return;
|
|
}
|
|
|
|
this.isSubmitting = true;
|
|
|
|
// เตรียมข้อมูลเพื่อส่งไปยัง API
|
|
const payload = {
|
|
...this.form,
|
|
items: this.inspectionItems
|
|
};
|
|
|
|
try {
|
|
// API endpoint for saving
|
|
const response = await fetch('api/inspection_save.php', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(payload)
|
|
});
|
|
const result = await response.json();
|
|
|
|
if(result.success) {
|
|
Swal.fire({
|
|
icon: 'success',
|
|
title: 'บันทึกสำเร็จ',
|
|
text: 'บันทึกแบบรายงานตรวจสภาพรถยนต์เรียบร้อยแล้ว',
|
|
timer: 2000,
|
|
showConfirmButton: false
|
|
}).then(() => {
|
|
window.location.href = 'vehicles.php';
|
|
});
|
|
} else {
|
|
Swal.fire({ icon: 'error', title: 'เกิดข้อผิดพลาด', text: result.message || 'ไม่สามารถบันทึกข้อมูลได้', confirmButtonColor: '#ef4444' });
|
|
}
|
|
} catch (error) {
|
|
Swal.fire({ icon: 'error', title: 'เกิดข้อผิดพลาด', text: 'ไม่สามารถเชื่อมต่อเซิร์ฟเวอร์ได้ หรือเกิดข้อผิดพลาดในการบันทึกข้อมูล', confirmButtonColor: '#ef4444' });
|
|
console.error(error);
|
|
} finally {
|
|
this.isSubmitting = false;
|
|
}
|
|
}
|
|
}));
|
|
});
|
|
</script>
|
|
|
|
<?php require_once 'includes/footer.php'; ?>
|