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,4 @@
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
@@ -0,0 +1,8 @@
ไฟล์ชุดนี้เป็น Production Build พร้อมนำขึ้น Static Web Hosting
วิธีใช้งาน:
1) อัปโหลดไฟล์ทั้งหมดในโฟลเดอร์นี้ขึ้น Netlify, Vercel, Firebase Hosting หรือ Web Server
2) ต้องเปิดผ่าน http:// หรือ https:// ไม่ควรดับเบิลคลิก index.html ด้วย file://
3) ข้อมูลรุ่นนี้เก็บใน LocalStorage ของแต่ละเบราว์เซอร์ จึงยังไม่ซิงค์ข้ามเครื่อง
บัญชีทดสอบ: admin / PIN 1234
@@ -0,0 +1,9 @@
import{r as O}from"./icons-BLu1UXn4.js";var y={exports:{}},n={};/**
* @license React
* react-dom.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var o;function S(){if(o)return n;o=1;var u=O();function g(r){var e="https://react.dev/errors/"+r;if(1<arguments.length){e+="?args[]="+encodeURIComponent(arguments[1]);for(var t=2;t<arguments.length;t++)e+="&args[]="+encodeURIComponent(arguments[t])}return"Minified React error #"+r+"; visit "+e+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}function c(){}var i={d:{f:c,r:function(){throw Error(g(522))},D:c,C:c,L:c,m:c,X:c,S:c,M:c},p:0,findDOMNode:null},m=Symbol.for("react.portal");function v(r,e,t){var a=3<arguments.length&&arguments[3]!==void 0?arguments[3]:null;return{$$typeof:m,key:a==null?null:""+a,children:r,containerInfo:e,implementation:t}}var f=u.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;function d(r,e){if(r==="font")return"";if(typeof e=="string")return e==="use-credentials"?e:""}return n.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE=i,n.createPortal=function(r,e){var t=2<arguments.length&&arguments[2]!==void 0?arguments[2]:null;if(!e||e.nodeType!==1&&e.nodeType!==9&&e.nodeType!==11)throw Error(g(299));return v(r,e,null,t)},n.flushSync=function(r){var e=f.T,t=i.p;try{if(f.T=null,i.p=2,r)return r()}finally{f.T=e,i.p=t,i.d.f()}},n.preconnect=function(r,e){typeof r=="string"&&(e?(e=e.crossOrigin,e=typeof e=="string"?e==="use-credentials"?e:"":void 0):e=null,i.d.C(r,e))},n.prefetchDNS=function(r){typeof r=="string"&&i.d.D(r)},n.preinit=function(r,e){if(typeof r=="string"&&e&&typeof e.as=="string"){var t=e.as,a=d(t,e.crossOrigin),s=typeof e.integrity=="string"?e.integrity:void 0,l=typeof e.fetchPriority=="string"?e.fetchPriority:void 0;t==="style"?i.d.S(r,typeof e.precedence=="string"?e.precedence:void 0,{crossOrigin:a,integrity:s,fetchPriority:l}):t==="script"&&i.d.X(r,{crossOrigin:a,integrity:s,fetchPriority:l,nonce:typeof e.nonce=="string"?e.nonce:void 0})}},n.preinitModule=function(r,e){if(typeof r=="string")if(typeof e=="object"&&e!==null){if(e.as==null||e.as==="script"){var t=d(e.as,e.crossOrigin);i.d.M(r,{crossOrigin:t,integrity:typeof e.integrity=="string"?e.integrity:void 0,nonce:typeof e.nonce=="string"?e.nonce:void 0})}}else e==null&&i.d.M(r)},n.preload=function(r,e){if(typeof r=="string"&&typeof e=="object"&&e!==null&&typeof e.as=="string"){var t=e.as,a=d(t,e.crossOrigin);i.d.L(r,t,{crossOrigin:a,integrity:typeof e.integrity=="string"?e.integrity:void 0,nonce:typeof e.nonce=="string"?e.nonce:void 0,type:typeof e.type=="string"?e.type:void 0,fetchPriority:typeof e.fetchPriority=="string"?e.fetchPriority:void 0,referrerPolicy:typeof e.referrerPolicy=="string"?e.referrerPolicy:void 0,imageSrcSet:typeof e.imageSrcSet=="string"?e.imageSrcSet:void 0,imageSizes:typeof e.imageSizes=="string"?e.imageSizes:void 0,media:typeof e.media=="string"?e.media:void 0})}},n.preloadModule=function(r,e){if(typeof r=="string")if(e){var t=d(e.as,e.crossOrigin);i.d.m(r,{as:typeof e.as=="string"&&e.as!=="script"?e.as:void 0,crossOrigin:t,integrity:typeof e.integrity=="string"?e.integrity:void 0})}else i.d.m(r)},n.requestFormReset=function(r){i.d.r(r)},n.unstable_batchedUpdates=function(r,e){return r(e)},n.useFormState=function(r,e,t){return f.H.useFormState(r,e,t)},n.useFormStatus=function(){return f.H.useHostTransitionStatus()},n.version="19.2.7",n}var _;function T(){if(_)return y.exports;_=1;function u(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(u)}catch(g){console.error(g)}}return u(),y.exports=S(),y.exports}export{T as r};
@@ -0,0 +1,21 @@
<!doctype html>
<html lang="th">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<meta name="theme-color" content="#1e3a8a" />
<meta
name="description"
content="ระบบบริหารจัดการศูนย์รับแจ้งเหตุและสั่งการนเรนทรอ่าวไทย พร้อมระบบรับแจ้งเหตุ รายงานประจำเวร ทดสอบวิทยุ และตรวจความพร้อมรถพยาบาล"
/>
<title>ศูนย์รับแจ้งเหตุและสั่งการนเรนทรอ่าวไทย</title>
<script type="module" crossorigin src="./assets/index-DWp6u1Ix.js"></script>
<link rel="modulepreload" crossorigin href="./assets/icons-BLu1UXn4.js">
<link rel="modulepreload" crossorigin href="./assets/react-Cfa4jLPc.js">
<link rel="stylesheet" crossorigin href="./assets/index-CmaWRkNt.css">
</head>
<body>
<div id="root"></div>
<noscript>ระบบนี้จำเป็นต้องเปิดใช้งาน JavaScript</noscript>
</body>
</html>
@@ -0,0 +1,121 @@
เลือกหมายเลขรถพยาบาลและกรอกข้อมูลตรวจสอบทางเทคนิคและอุปกรณ์กู้ชีพ
นับพบกี่ชิ้น
ปกติ
บท
ถ้ามี
ตรวจโดย
พร้อมใช้
ตรวจสอบผลแล้ว
ท่อช่วยหายใจ
นายเอกชัย
ระบบไม่พบปัญหาเร่งด่วนในรถกู้ชีพพยาบาลทุกคัน
ควรแจ้งเติมด่วน
งาน
บ่าย
แสดงข้อมูลจากการประเมินครั้งล่าสุดของแต่ละคันในระบบ
บทบาทหน้าที่ของคุณ
ไม่พร้อมปฏิบัติการ
ประเภทรถ
พบจุดชำรุด
รายการซ่อมบำรุง
สำคัญ
หมดอายุ
พบอุปกรณ์วิกฤตทำงานผิดปกติหรือชำรุดจำนวน
ขนาด
วันที่
แจ้งเตือนรถพยาบาลวิกฤต
ทั่วไป
วิกฤต
พร้อมใช้มีข้อจำกัด
กู้ชีพทีมบ่าย
ปิดรายการ
คัน
หรือปัญหาที่ต้องให้วิศวกรซ่อมบำรุงดำเนินการด่วน
มีอุปกรณ์ทั่วไปไม่พร้อมใช้หรือจำนวนไม่เพียงพอ
ต้องการแก้ไขด่วน
อธิบายรายละเอียดปัญหาชำรุด
ยืนยันผลตรวจสอบและบันทึกข้อมูล
การดำเนินการแก้ไข
เช้า
เลขไมล์รถล่าสุด
ถัง
ทะเบียนรถ
เหลือ
รายงานปัญหา
กข
แบบฟอร์มบันทึกการตรวจสอบความพร้อมรถประจำเวร
เครื่องมือแพทย์
ติดตามการเติมเวชภัณฑ์และซ่อมแซมวิทยุ
สารน้ำ
อุปสรรคความร่วมมือ
อัปเดตงานบำรุงรักษาผ่านแดชบอร์ด
วันข้างหน้า
ยังไม่ได้ตรวจ
เวลาที่ตรวจล่าสุด
เลือกรถกู้ชีพพยาบาล
ระบบ
ยานพาหนะ
อุปกรณ์เคลื่อนย้ายผู้ป่วยและการตรึงผู้บาดเจ็บ
ยา
ผลการประมวลสถานะความพร้อมรถอัตโนมัติ
ระดับน้ำมันเชื้อเพลิง
และเอกสารประจำรถ
ค่ายดูแล
พร้อมปฏิบัติการ
ทะเบียน
อุปกรณ์วิกฤตและระบบพื้นฐานพยาบาลผ่านการประเมินความพร้อม
หน่วยงานผู้ควบคุม
จำนวนไม่เพียงพอ
เต็มถัง
แผ่น
ครึ่งถัง
ปัญหาที่พบ
แจ้งโดย
อุปกรณ์ช่วยชีวิตและการเฝ้าสัญญาณผู้ป่วย
รายการ
สุราษฎร์ธานี
แบตเตอรี่
แบบฟอร์มตรวจความพร้อมรถ
สถานะความพร้อมรถพยาบาลปัจจุบัน
แห่ง
ชำรุด
ไม่มีประจำรถ
ยังไม่ได้ตรวจประจำเวร
รหัส
ชื่อผู้ร่วมตรวจสอบ
รถ
แดชบอร์ดรถพยาบาล
พร้อมใช้งานแบบมีข้อจำกัด
ยาฉุกเฉิน
หมายเหตุเพิ่มเติมภาพรวมการตรวจเช็ก
ตรวจสอบดวงชะตาเวชภัณฑ์
ผู้ตรวจสภาพ
หัวข้อตรวจประเมินแยกหมวด
สถานะความพร้อม
ไม่เกี่ยวข้องกับรถคันนี้
และเวชภัณฑ์พกพาประจำรถ
ยังค้างอยู่
รออะไหล่หรือรอเวชภัณฑ์
เช่น
สำเร็จ
ประตูรถของทุกคัน
อยู่ระหว่างดำเนินการ
ตรวจสภาพรถพยาบาล
ดึก
รายการซ่อมบำรุงและงานติดตามแก้ไขปัญหา
รอรับเรื่อง
วัน
กิโลเมตร
สถานะตั๋ว
ไม่พร้อมใช้
ความปลอดภัย
แก้ไขแล้ว
ส่งซ่อม
กรอกรายละเอียดความคืบหน้าการทำงาน
หมวด
ปัญหา
ปิดถาวร
ประมวลผลสถานะ
เวชภัณฑ์ใกล้หมดอายุ
ฉุกเฉิน
@@ -0,0 +1,75 @@
สำเร็จเรียบร้อยแล้ว
เร่งด่วน
ขณะนี้เวลา
ปิดการทดสอบ
ติดต่อไม่ได้
เช่น
ช่องพิเศษ
นเรนทรอ่าวไทยขอขอบคุณทุกสถานีที่ร่วมทดสอบ
เจ็บป่วยฉุกเฉิน
คัดลอกข้อความ
ช่องตรง
ปานกลาง
กู้ชีพตลิ่งงาม
เข้าร่วม
จะทำการทดสอบ
ระบุชื่อสถานีลูกข่ายเพิ่มเติม
นเรนทรอ่าวไทย
บันทึกและส่งข้อมูลเข้ารายงานเวร
ให้ขออนุญาต
อ่อน
ไม่มีความเห็นพิเศษ
ตารางทดสอบวิทยุเพิ่มเติม
ระบบจึงจะนำข้อมูลมาคำนวณจำนวนผลสรุป
เช้า
นเรนทรอ่าวไทยแจ้งลูกข่ายและในข่าย
สถานี
เข้ามาได้
ดึก
เรียบร้อยแล้ว
สถานีหลัก
ดี
ผู้ทดสอบ
ก่อนทดสอบ
วันนี้มีผู้ร่วมทดสอบ
เปิดพิธี
แย่มาก
ที่นี่ศูนย์รับแจ้งเหตุนเรนทรอ่าวไทย
มี
ทดสอบโดย
สัญญาณส่ง
ยืนยันและสรุปผลตรวจ
คัดลอกบทพูด
ระบุระดับสัญญาณรับส่ง
ชื่อสถานี
ลำดับ
ช่องรับสัญญาณ
จำนวน
บ่าย
มีอีกหรือไม่
สมุย
หมายถึงดีที่สุด
หมายเหตุเพิ่มเติม
ข้อความประกาศ
หากมีการกรอกชื่อ
สัญญาณรับ
ตารางทดสอบวิทยุ
ให้
ดีมาก
ระบุชื่อลูกข่ายและผลทดสอบวิทยุ
แจ้งลูกข่ายและในข่ายใช้ความถี่ได้ตามปกติ
นี้
ลูกข่ายและในข่ายนเรนทรอ่าวไทยที่ต้องการทดสอบ
หากมี
ลูกข่ายอื่น
หมายถึงสัญญาณขาดหาย
ลูกข่ายและในข่ายนเรนทรอ่าวไทย
ไม่เร่งด่วน
นเรนทรอ่าวไทยแจ้ง
ปล่อยว่างเพื่อไม่บันทึก
เวร
ผู้บันทึก
บันทึกผลทดสอบวิทยุ
โทร
@@ -0,0 +1,129 @@
และความพร้อมของขบวนรถพยาบาล
หลอดเลือดสมองเฉลี่ย
ไม่มีรายงานการทดสอบวิทยุ
รอรับมอบเวร
สรุปเคสปฏิบัติการและการออกปฏิบัติการประจำเวร
เวรปฏิบัติงาน
ยืนยันรับเวรเสร็จสิ้น
ราย
สายอื่น
ส่งมอบต่อให้กับ
คัดลอกสรุปเป็นข้อความเวร
สีขาว
ยังไม่ได้รับการยืนยันยืนเวร
เคสเร่งด่วนรหัสเฉพาะ
สีแดง
ส่งเวรสำเร็จ
สถานีเข้าร่วมตรวจสำเร็จ
เหลือง
สายปฏิบัติการ
เจ้าหน้าที่เปลี่ยนเวร
ไม่รุนแรง
ข้อมูลผู้รับเวรถูกลงบันทึกในเอกสารอย่างเป็นทางการแล้ว
รายงานสรุปผลการปฏิบัติการประจำเวร
หลัก
ประเมิน
ผลการทดสอบวิทยุ
เวร
วันที่
ทั่วไป
ประสานงานย้อนหลัง
สรุปความเร่งด่วนและจำแนกคัดกรองอาการ
หน่วย
ต้องยืนยันตนด้วยชื่อและรหัสผ่าน
วิกฤต
ไม่มีรายงานเหตุการณ์สำคัญเป็นพิเศษ
สถานีที่ไม่เข้าร่วม
ยืนยันการเซ็นรับมอบเวร
ติดเชื้อในกระแสโลหิต
สาย
ลงชื่อรับเวรเมื่อ
บันทึกในเวรนี้
ระดับความรุนแรง
ผู้ทดสอบ
สายเรียกเข้าทั้งหมด
สรุปข้อมูลสายเรียกเข้าประจำเวร
เขียว
กู้ชีพมูลนิธิ
ผู้สรุปรายงาน
โรคหัวใจเฉียบพลัน
ไม่มี
กรุณาเซ็นชื่อเข้าระบบด้วย
ระดับหน่วย
ผู้ป่วยนัด
ลงชื่อเข้ารหัสดิจิตอลเรียบร้อยแล้ว
อุบัติเหตุพหุบาดเจ็บรุนแรง
ส่งเวร
ยอดสรุปสถิติ
ฉุกเฉินคุกคามชีพ
สรุปเหตุการณ์และข้อขัดข้องสำคัญในรอบเวร
ระบบรับ
กรุณาเลือกผู้รับเวร
ติดต่อไม่ได้
เคสตกค้าง
เคส
โทรผิด
ปลอดภัย
พิมพ์หรือเซฟรายงาน
ระดับ
ทดสอบสำเร็จ
เซ็นมอบเวรโดย
สายก่อกวน
กรุณาลองใหม่อีกครั้ง
ความเสี่ยงหรือความขัดแย้งที่ต้องปรับปรุงระบบ
ศูนย์รับแจ้งเหตุและสั่งการนเรนทรอ่าวไทย
สายโทรผิด
เรียบร้อยแล้ว
รายชื่อสถานีที่ขาดการติดต่อ
กึ่งวิกฤต
ส่งเวรและรักษาความปลอดภัย
ผลทดสอบวิทยุ
และมีการลงบันทึกในรายงานเวรแล้ว
ยืนยันรหัส
กรุณากรอกรหัสผ่าน
ป้อน
สีเหลือง
เคสปฏิบัติการที่ค้าง
สีเขียว
คัดลอกสรุปข้อความประจำเวร
รับเวร
ผู้ส่งเวร
แพทย์กู้ชีพ
ห้องฉุกเฉิน
เลือก
ไม่ถูกต้อง
ผู้ส่งมอบเวร
ผู้รับเวร
ข้อมูลสายเรียกเข้าทั้งหมด
หลักของตนเอง
ล่าสุด
แดง
สัญญาณชีพ
เร่งด่วน
สำเร็จ
วันที่รายงาน
แจ้งเหตุอื่น
เคสรวม
สรุปรับ
ผู้รับมอบเวร
รหัสผ่าน
เบอร์โทรฉุกเฉิน
การประเมิน
สถานี
ไม่พบปัญหาความเสี่ยงพิเศษจากการรับแจ้งเหตุหรือการประสานขบวนรถ
ยืนยันการรับ
ก่อนพิมพ์รายงาน
จุดเกิดเหตุ
สรุปเหตุการณ์สำคัญและความเสี่ยงที่ตรวจพบ
ประเมินทางสายโทรศัพท์
รายงานประจำวันนเรนทรอ่าวไทย
เพื่อลงลายเซ็นดิจิตอลรับมอบภาระงาน
เคสปฏิบัติการทั้งหมด
เลือกเจ้าหน้าที่รับเวร
ลงชื่อรับเวรดิจิตอล
ผู้เซ็นรับมอบเวร
รอลงชื่อรับเวรดิจิตอล
และสถานี
@@ -0,0 +1,712 @@
กู้ชีพตลิ่งงาม
เอกสารพรบ
และทีม
ประเภทปฏิบัติการ
การยืนยันรหัส
เส้นทางลำเลียงผู้ป่วย
หัวใจ
สำหรับเด็ก
ผู้บริหารระดับสูง
หน่วยงานกู้ชีพทุกข่าย
นิ้ว
สายเข็มขัดรัดตรึงตัวคนป่วยบนเปล
พยายามฆ่าตัวตาย
ตกเลือด
แบตเตอรี่ในด้ามส่องและหลอดไฟใบมีด
ไฟหรี่
ไม่มีระดับความเสี่ยงพิเศษนอกกวน
หน่วยปฏิบัติการกู้ชีพทั้งหมด
อุบัติเหตุจราจร
เคสค้าง
บันทึกการปรับปรุงผู้ใช้
ช่างสมหมาย
รอสรุปผลประเมินอาการส่งต่อ
เลือก
กรอกเหตุการณ์เบื้องต้น
ตรวจขนาดตรงกับรถ
เพิ่มและจัดสร้างผู้ใช้ใหม่
ปวดท้อง
มอเตอร์ไซค์ชนท้ายรถกระบะ
อุปกรณ์ทุ่นพยุงลอยคอ
ไฟหน้า
แพทย์อำนวยการรับปรึกษา
วันที่คัดรายงาน
ชุดอุปกรณ์ให้น้ำเกลือมาตรฐาน
เบอร์
วิทยุ
รับแจ้งเหตุแรกรับ
กรวยสะท้อนแสง
วิทยุโมบายล์พังควันขึ้น
หอบหืด
โรงพยาบาลเกาะสมุย
เปลนอนหลักประจำรถพยาบาล
โรงพยาบาลพะงันอินเตอร์
เปลตะกร้าสำหรับเคลื่อนย้ายในที่สูงหรือข้ามเกาะ
หลอดเลือดสมองอุดตัน
เข็มขัดนิรภัยห้องคนขับและทีมงาน
ขึ้น
โรงพยาบาลกรุงเทพสมุย
ชลิดา
ไฟเลี้ยว
ไม่พร้อมปฏิบัติการ
รับแจ้งเหตุ
แผ่นแปะซีลแผลทะลวงหน้าอกป้องก้นปอดแฟบ
เปิดใช้งานขบวนนี้
คีย์ระบุข้อมูลหากหน่วยกู้ภัยในข่ายนเรนทรไม่พร้อมปฏิบัติการ
ท่อเปิดทางเดินหายใจทางปาก
สมุย
หน่วยปฏิบัติการรับมอบ
สมชาย
ขณะนี้ไม่มีเคสค้างออกปฏิบัติการนอกพื้นที่
เรือกู้ชีพ
เลขปฏิบัติการ
แดง
ไม่ระบุ
เครื่องยนต์
สายเรียกเข้า
ระบุเหตุผลขัดข้องความพร้อม
ผลวินิจฉัย
อยู่ระหว่างรออะไหล่ส่งซ่อม
เลือกเวรรอบ
จมน้ำ
ที่นอนสูญญากาศลดแรงกระแทก
วิทยุสื่อสาร
ระดับน้ำมันเชื้อเพลิง
กู้ชีพละไม
ถังดับเพลิงเคมีประจำรถ
ข้อมูลเคสจะถูกนำเข้าสู่ระบบบัญชี
ติดรถ
ปัญหาทางการมองเห็น
ข้อต่อสามทางควบคุมทิศทางยา
อัปเดตสถานะหน่วยงาน
เฝือกคอชนิดแข็งสำหรับเด็ก
พร้อมปฏิบัติการ
มาตรฐานต้องมี
ขนาดผู้ใหญ่
กล่องเจาะพลาสติกแข็งทิ้งเข็มใช้แล้วป้องก้นเข็มตำ
เกียรติภูมิ
เช่น
หลัง
น้ำยาทำแผลฆ่าเชื้อโรค
วิกฤตสูงสุด
จิตเวชคลุ้มคลั่ง
ช่องทาง
กู้ภัยพะงัน
ปรับลำดับการทำงาน
เจ็บตื้อ
ผ้าคลุมปิดผู้เสียชีวิต
ตรวจรถ
อัปเดตแบบ
ปวดศีรษะ
เฮลิคอปเตอร์กู้ชีพ
คุณต้องการเปลี่ยนสถานะบัญชีนี้เป็นระงับการใช้งานหรือไม่
ไม่พบเคสปฏิบัติการที่ตรงตามตัวกรองที่ระบุในเวรนี้
หน่วยกู้ภัยพื้นฐาน
ชิ้น
รับ
สัญญาณดีมาก
อัปเดตสัญชีพ
เปิดใช้งานบัญชีนี้
ไม่สบายตัว
สถานะ
ยางอะไหล่ประจำรถ
สถานีพร้อมออกปฏิบัติการ
ชื่อบัญชีผู้ใช้งานหรือรหัส
สถานะเคสทั้งหมด
มีแผลฉีกขาดขนาดใหญ่ที่ศีรษะและสงสัยกระดูกต้นขาหักข้างขวา
กู้ภัยสมุยจุดศิลางู
เหตุพิเศษ
หมดสติ
ส่งซ่อม
พร้อมออกปฏิบัติการ
ผู้ป่วยเพศชายอายุ
โรงพยาบาลเกาะเต่า
ได้รับบาดเจ็บทางร่างกายอื่น
ถุงมือปราศจากเชื้อทางการแพทย์
ยกย้ายแบบผ้าหนาเหนียว
แก้ไขปรับปรุงข้อมูลเคสปฏิบัติการ
ป้อนข้อมูลข้อขัดข้องหรือความเสี่ยงที่พบในรอบเวร
จิตเวช
เลข
ด้ามและใบมีดชุดส่องกล่องเสียง
เต็มถัง
สายแจ้งเหตุ
หน่วยขัดข้อง
ระงับความพร้อมชั่วคราว
ดำเนินการคัดแยกสี
ระบุเป็นหน่วยโรงพยาบาลเกาะสมุย
รอรับเรื่อง
และเปลี่ยนสถานะเพื่อส่งต่อรายงานสถิติอย่างถูกต้อง
ส่งแจ้งเตือน
ไม่พร้อมออกปฏิบัติการ
แบตเตอรี่เครื่อง
นายสมเกียรติ
เมืองสมุย
เคสตกค้างค้างกรอกข้อมูล
บรรเทา
ระดับ
ไฟกระพริบพกพา
นาที
พบปัญหาคลื่นสัญญาณวิทยุจุดบ่อผุดรับส่งเบาบาง
ห้ามเลือด
เฉพาะระดับ
ปลดล็อคระบบ
ถุงขยะแดงทิ้งสิ่งปนเปื้อนสารคัดหลั่ง
รายการรับเคสปฏิบัติการ
ยางรถเสื่อมชำรุดชั่วคราว
ระบุเบอร์โทร
ส่งต่อ
เสาวิทยุชำรุดชั่วคราว
เคสตกค้าง
การฉีดพ่นทำความสะอาดฆ่าเชื้อหลังปฏิบัติภารกิจล่าสุด
เฝือกดามขาแยกสัดส่วน
วิทยุช่องใด
สายไฟหลวมชำรุด
สถานี
เจ็บป่วยทั่วไป
หน่วยกู้ชีพละไม
เลือกหน่วยปฏิบัติการที่มีปัญหา
คาดการณ์ระยะเวลาไม่พร้อมใช้
บันทึกและสรุปข้อมูลแรกรับ
ชื่อผู้ใช้
จัดการข้อมูลผู้ใช้งานระบบ
ไม่เร่งด่วนทั่วไป
ปัจจุบัน
ค้างกับใคร
ถังออกซิเจนสำรองแบบพกพา
ลบรายการสายเรียกเข้าสำเร็จ
ถุงมือตรวจโรคชนิดใช้ครั้งเดียวทิ้ง
ปี
ทีมงานมูลนิธิพื้นฐาน
การประสานรับเคสอุบัติเหตุหมู่
เคสที่ปิดแล้ว
ยังไม่ปิด
พยาบาลวิชาชีพ
สุขใจ
เข็มแทงเส้นเลือดดำสำหรับให้น้ำเกลือ
หน่วยกู้ชีพตลิ่งงาม
นางสาวสุดารัตน์
เปลี่ยนสิทธิ์
เปลี่ยนรหัสผ่าน
ชาร์จเต็ม
กู้ภัยสมุยจุดสระเกศ
เร่งด่วน
วิทยุสื่อสารประจำรถ
กู้ภัย
นามสกุลทางการแพทย์
ผู้บาดเจ็บชายชาวต่างชาติ
เช็กกุญแจล็อกซีลและใบรายการพร้อมใช้
ดึก
ชื่อ
พะงัน
กรุณาเข้าสู่ระบบด้วยรหัส
แขนขาซีกซ้ายอ่อนแรงเฉียบพลัน
หน่วยปฏิบัติการรับเหมา
กู้ภัยสมุยจุดบ้านใต้
ตกที่สูง
โรงพยาบาลบ้านดอนอินเตอร์
ยกเลิกแก้ไข
เสื้อชูชีพสำหรับคนไข้
สายปฏิบัติการ
สายและชุดยึดตรึงผู้ป่วยเข้ากับเปลตะกร้า
ก้าวร้าว
ใหม่ไม่ตรงกัน
จุดเกิดเหตุ
ปริมาณแรงดันเกจ์
แตก
เสื้อคลุม
ไม่มี
เวชภัณฑ์
จัดลำดับการทำงาน
โดยอัตโนมัติ
ลบข้อมูลสายโทรศัพท์
จำนวนไม่เพียงพอ
ยอดเคสสะสมในระบบ
ผ้าพันยืดหยุ่นลดแรงดันห้ามเลือด
บันทึกโดย
ผ้าห่มความร้อน
อย่างน้อย
ค้นหาเลขสพฉ
กระดานสั้นรองหลัง
นเรนทรอ่าวไทย
ผ้ารองเลื่อนตัว
ฉุกเฉินคุกคามชีพ
ผืน
เครื่องพกพา
และเอกสารนำส่งผู้ป่วย
โดนสารเคมี
เวรรอบ
และหน้ากาก
ระบบไฟฟ้าของรถพยาบาล
สว่างชัดเจน
เทปกาวเหนียว
คีมจับ
นค
บ่าย
ตีบ
รับสายโทรศัพท์
ระดับหน่วยกู้ชีพ
อ่อนเพลีย
เจ้าหน้าที่บันทึกข้อมูล
ผู้รับผิดชอบการ
ทางอากาศ
น้ำยาเบตาดีน
สำลีแอลกอฮอล์ฉีกซองฆ่าเชื้อ
กระเป๋ายาฉุกเฉินหลัก
เครื่องควบคุมให้สารละลายทางหลอดเลือดดำ
พร้อมใช้งานแบบมีข้อจำกัด
เครื่องวัดความเข้มข้นออกซิเจนปลายนิ้ว
ดัชนีผลผลิตผู้ปฏิบัติการรับรับแจ้งเหตุและสั่งการ
บันทึกข้อมูลจริงในข่าย
บัญชีผู้ใช้
จำเป็นต้องเบิกจ่ายทดแทนด่วน
และระบุหน่วยรับส่งประจำเกาะสมุย
ค้างปรับปรุงข้อมูล
แก้ไขข้อมูล
ประสานลำเลียงส่งต่อ
สำหรับทารกแรกเกิด
สำลักสิ่งอุดกั้นทางเดินหายใจ
ไม่มีไข้
ติดต่อไม่ได้
สถานีเสริม
เคสประสานเฮลิคอปเตอร์กู้ชีพเกาะเต่า
สุราษฎร์ธานี
ยังไม่ทราบเวลาสิ้นสุดกู้คืนความพร้อมแน่นอน
แว่นครอบป้องกันใบหน้าสายตา
อุบัติเหตุพหุบาดเจ็บ
โดยไม่จำเป็นต้องกรอกครบทุกช่องก็สามารถบันทึกได้
และเด็ก
แจ้งหัวหน้าเวร
แผ่นนำไฟฟ้าสำหรับช็อกไฟฟ้าชนิดใช้ครั้งเดียว
ยกเลิกการแก้ไข
เครื่องช่วยหายใจเคลื่อนย้ายพกพาอัตโนมัติ
เพิ่มหน่วยงานกู้ชีพใหม่
วิกฤตคุกคามชีพ
แก้ไขข้อมูลหน่วยงานกู้ชีพ
รถ
สายเรียกเข้าและรายงานล่าสุดในรอบเวร
สัญญาณสายแทงเข้าปกติ
หลักเพื่อเริ่มต้นปฏิบัติงาน
คลุ้มคลั่ง
ไฟฉุกเฉินบนหลังคารถ
ต้อง
สีขาว
บอร์ดลอยน้ำกู้ภัยทางทะเล
รับแจ้งเหตุแรก
สายซ้อนประสาน
นายเด่นดนัย
พญ
ตัวเลข
เชือกโรยตัวและชุดรอกกู้ภัยขั้นต้นประจำเรือ
หลักเท่านั้น
เครื่องช็อกไฟฟ้าอัตโนมัติ
โดย
กู้ภัยสมุย
กลับคืนพร้อมปฏิบัติ
บรรจุซอง
กู้ชีพ
ตรวจสอบผลแล้ว
กำลังโหลดหน้าการทำงาน
กู้ชีพหน้าเมือง
ศูนย์รับแจ้งเหตุและสั่งการนเรนทรอ่าวไทย
ต่อย
ปิดรายการ
หน่วยงาน
สมุยหลัก
ไม่มีประวัติเคสฉุกเฉินค้างปรับปรุงข้อมูลในรอบเวรนี้
เครื่องวัดความดันโลหิตแบบดิจิตอล
ยาเกินขนาด
หน้ากากอนามัยชนิดป้องกันอนุภาคเล็กพิเศษ
คุณแน่ใจหรือไม่ที่จะลบรายการสายเรียกเข้านี้ออกจากระบบ
หากปัญหาซ่อมบำรุงในรถพยาบาลได้รับการแก้ไขแล้ว
รายการสอดคล้อง
ลำดับ
มีอาการหน้าเบี้ยว
ไปยัง
เครื่องช่วยหายใจชนิดบีบมือ
กรุณากรอกชื่อหน่วยงานปฏิบัติการ
แสดงรายการประวัติสายเรียกเข้าทั้งหมดที่คุณคีย์ล่าสุด
หญิงไทยอายุ
หูฟังแพทย์
ระดับความพร้อม
ชื่อเจ้าหน้าที่กู้ชีพกู้ภัย
รหัสเฉพาะ
สถานะเคส
เคสตกหล่นค้างข้อมูล
เช็กสายต่อ
เปลี่ยนสถานะผู้ใช้งานเป็นระงับการใช้งานสำเร็จ
สิทธิ์ในระบบ
รับแจ้งเหตุกลุ่มอาการ
สายต่อเพิ่มความยาวชุดให้น้ำเกลือ
กลุ่มอาการ
คุณจำเป็นต้องเปลี่ยนรหัสผ่าน
ฟอยล์สีเงินอลูมิเนียมกักอุณหภูมิร่างกายป้องก้นช็อกหนาว
ยางรถทุกล้อ
ความสะอาดห้องโดยสารหน้ารถ
รถพยาบาลฉุกเฉิน
ทำร้ายตนเอง
ปวดท้องน้อยด้านขวา
โทรผิด
สำเร็จ
ยอดเยี่ยม
แบบกันน้ำชนิดใช้ครั้งเดียวกึ่งซักได้
เจ็บหน้าอก
แก้ไขปรับปรุงข้อมูลผู้ใช้
ลำเลียง
ต้องมากกว่าครึ่งถัง
ปริมาณแรงดันออกซิเจนคงเหลือพร้อมใช้งานจริง
กู้ภัยสมุยจุดบ่อผุด
ผู้รับผิดชอบกรอกข้อมูล
ไม่
สายรับแรกรับเวรปัจจุบัน
เพื่อให้ผู้รับผิดชอบ
วันที่
เพิ่มหน่วยกู้ภัยเครือข่ายใหม่
ทางน้ำ
เฝือกลมระบบสูญญากาศ
พยาบาลสมหญิง
ไฟช็อต
บันทึกข้อมูลสายเรียกเข้าประเภท
เพื่อนำไปลงบันทึกในเอกสารรายงานประจำวันอัตโนมัติ
ความพร้อมรถพยาบาล
หน่วยพยาบาลกู้ชีพ
รายการ
ชื่อแพทย์อำนวยการ
อาการ
กรุณาติดต่อ
ขับปลอดภัย
ระดับการประเมิน
ฝนตกถนนลื่น
ประเมินหน้าจุดเกิดเหตุ
กู้ชีพวิชาชีพ
รู้สึกตัวดีปวดต้นคอ
ยกเลิก
ชุดส่องกล่องเสียงตรวจทางเดินหายใจ
ยังไม่มีประวัติสายเรียกเข้าที่ได้รับการบันทึกในรอบเวรนี้
อุ้งเชิงกราน
ใหม่
บันทึกข้อมูลปรับปรุง
ปล่อยว่างหากยังไม่มี
เฝือกดามแขนแยกสัดส่วน
บริการไฟรถยนต์
นำส่งเกาะสมุยประสานลำเลียงขึ้นฝั่ง
เสียงสัญญาณไซเรนฉุกเฉิน
อยู่ระหว่างดำเนินการ
เครื่องดูดเสมหะแบบเคลื่อนย้ายได้
นายกิตติพงษ์
สำหรับผู้ใหญ่
ติดเชื้อในกระแสโลหิต
อุปกรณ์ความปลอดภัยทางถนน
ยางรถเสื่อมสภาพ
ประกันภัย
เวรบ่าย
บัญชี
หลักใหม่เพื่อความปลอดภัยของระบบกู้ชีพ
หน่วยกู้ชีพเฉวง
หัวหน้าทีมพัสดุกู้ชีพ
และปิดเคสอย่างละเอียด
การให้สารละลายและดามกระดูกฉุกเฉิน
เครื่องวัดระดับน้ำตาลในกระแสเลือด
ไฟส่องสว่างภายในห้องปฏิบัติการผู้ป่วย
กู้ภัยเกาะเต่า
พูดไม่ชัด
และแผ่นนำไฟฟ้าแบบเจล
สพฉ
ป้อน
เหลือ
เปลตักเคลื่อนย้ายผู้ป่วย
โคม่า
เลือดออก
เครื่อง
เวรเช้า
หน้ากากใสกันกระเซ็น
ถ้ามี
และผู้ประเมินสถานะการพยาบาลรับ
หลักไม่ถูกต้อง
ปรับปรุงข้อมูลแล้ว
รถพยาบาลมาตรฐาน
ระบบ
บท
หน่วยงานกู้ชีพรับเหมา
พอป
แท้ง
สายรัดขันชะเนาะห้ามเลือดภายนอกสไตล์ทหาร
บทบาทการทำงาน
หน้ากากอนามัยชนิดธรรมดา
ไฟไซเรน
ผ้าปิดแผลขนาดใหญ่เหนียวพกพา
หรือจำนวนไม่ครบตามมาตรฐาน
หน่วย
รายละเอียดปฏิบัติการกู้ชีพ
กระบอกฉีดยา
สมุดบันทึก
หัวใจหยุดเต้น
ปัญหาทางนรีเวช
จุด
สร้างเคสใหม่
สายแจ้งเหตุหรือสายปฏิบัติการ
โปรดระบุรายละเอียดสายเรียกเข้า
ทุกสถานีปิดรอบงานเรียบร้อย
ประเภทสายเรียกเข้า
หายใจลำบาก
กรุณากดปุ่ม
วิธีอื่น
เมนูการปฏิบัติงาน
แพ้ยา
รวมเคสฉุกเฉินกู้ชีพทุกลำดับ
กรุณากรอกข้อมูลผู้ใช้ให้ครบถ้วนก่อนบันทึก
มีสุข
บัญชีทดสอบระบบตามความต้องการ
สายรัดยึดกระดูกเชิงกรานหักช็อกตกเลือด
ยืนยันรหัส
อาการแรกรับ
เสียงเครื่องยนต์
ประสานพยาบาลต่อ
ประเมินทางสาย
เครื่องวัดอุณหภูมิร่างกาย
ผ้าก๊อซกึ่งห้ามเลือดในแผลกระสุนปืนหรือแผลเหวอะ
การประเมินหน้างาน
บันทึกการปรับปรุงหน่วยงาน
แพทย์อำนวยการ
แผ่นแถบตรวจระดับน้ำตาล
ภัยพิบัติ
ของเจ้าหน้าที่
ชม
วิชาชีพขั้นสูง
ความเสี่ยงหรือปัญหาที่สืบค้นพบ
ปิดเคส
สีแดง
เขียว
รหัส
รับมอบ
ระดับหน่วย
กู้ชีพเฉวง
ชุดอุปกรณ์ทำคลอดฉุกเฉินประกอบด้วยผ้า
สายก่อกวน
ส่งช่างถอดแผงครอบไซเรนออกตรวจซ่อมแก้ไขขั้วสัมผัส
เจ็บตา
รพ
เร่งด่วนกึ่งวิกฤต
โรงพยาบาลไทยอินเตอร์
เหลือง
บัญชีนี้ถูกเปิดใช้งานครั้งแรก
นัดหมายรับบริการ
เป็น
สัตว์กัด
รายละเอียดช่องทางเสริม
บันทึกข้อมูลและสร้างเคสปฏิบัติการ
น้ำร้อนลวก
บันทึกเมื่อ
ขาว
ขบวนกู้ภัยที่ยังไม่พร้อมปฏิบัติการ
ทดสอบเปิด
หลอดไฟ
ใช่
บทบาท
เฝือกดึงกระดูกต้นขาหัก
ไม่หายใจ
นายกู้ชีพ
กระดานแข็งรองหลังช่วยชีวิต
ผลการวินิจฉัยพยาบาล
เดินไหว
บันทึกการรับสายโทรศัพท์
สีเหลือง
มาตรฐาน
รหัสเฉพาะผู้ป่วยวิกฤต
มุ่งมั่น
ช่องทางอื่น
ถังออกซิเจนหลักในตัวรถ
พัชรสมุย
คำนวณสถิติสรุปงานแยกรายเจ้าหน้าที่โดยอัตโนมัติอ้างอิงตาม
ป่วย
ไม่สามารถปิดการใช้งานหรือลบบัญชีหลักของตนเองได้
สัดส่วนช่องทางการแจ้งเหตุ
รักเกาะ
จำแนกกลุ่มอาการ
เคสสำเร็จ
ชัก
เทศบาลนครเกาะสมุย
หน่วยกู้ชีพหน้าเมือง
แจ้งเหตุอื่น
สัญญาณชีพปกติ
สมุยดี
หน่วยในข่ายไม่พร้อมทำงาน
ท่อเปิดทางเดินหายใจทางจมูก
ชุดเข็มระบายลมออกจากช่องอกแรงดันสูง
เช็กระดับน้ำมันเครื่อง
ผู้ป่วยนัดหมาย
ชื่อสถานี
ส่งมอบเวรเสร็จสิ้นให้กับ
ตรวจสุขภาพนัดส่งต่อ
การดำเนินการ
กข
เรือสปีดโบ๊ท
ใหม่ต้องเป็นตัวเลข
เครื่องปรับอากาศห้องปฏิบัติการผู้ป่วยด้านหลัง
หมดคลังรถ
ประสบอุบัติเหตุล้มหัวฟาดพื้น
มีการปรึกษาแพทย์อำนวยการ
หน่วยกู้ชีพร่วมเครือข่าย
เวรดึก
ประเภทเคส
ไม่มีข้อติดขัดเรื่องรถ
รถส่งซ่อมชั่วคราว
ฝนตกจุดเกาะพะงันคลื่นแรงสปีดโบ๊ทยกยาก
เคส
ลำดับการออกขบวน
โรงพยาบาลเฟิร์สเวสเทิร์น
เครื่องปรับอากาศห้องขับขี่ด้านหน้า
อุบัติเหตุทางน้ำ
เพิ่ม
ทางบก
สิทธิ์
เวร
ผ้าห่มพับผืนหนารองนอน
รายงานสถิติ
เครื่องดูดเสมหะระบบติดตั้งในรถพยาบาล
แม่แรงและอุปกรณ์เครื่องมือเปลี่ยนยาง
ผ้าพันแขนวัดความดัน
อุปกรณ์ประคองข้างศีรษะ
ช่องทางการแจ้งเหตุ
ทั่วไป
ผู้ใช้งานสิทธิ์
เหตุสาธารณภัยกลุ่มใหญ่
ชั่วโมงก่อนมา
ท่อช่วยหายใจทางปาก
ด้านซ้ายท้ายไม่ติดกะพริบ
ภูมิแพ้
ฟ้าผ่า
ยอดสายเรียกเข้าแรกรับ
และกลอนล็อกประตูทิศต่าง
ประตูรถ
คลอดชีพ
เกาะสมุย
หัวใจขาดเลือด
บันทึกรายงานระดับสถานะความพร้อมของหน่วยงานกู้ชีพ
แก้ไข
แจ้งประสานงานสุนัขติดเกาะ
กรุณาตรวจสอบอีกครั้ง
นางพิศมัย
ระบบแท่นรางล็อกตัวเปลเข้ากับโครงตัวรถพยาบาล
กำลังรอการสั่งเบิกเติม
เก้าอี้เคลื่อนย้ายผู้ป่วยลงบันได
ระดับวิกฤตสายแรกรับ
เปลี่ยนและเข้าสู่ระบบ
ระบุบทบันทึกสรุปและเรื่องค้างส่งมอบ
ไม่เกี่ยวข้องกับรถคันนี้
ผู้บริหารและพยาบาลนำส่ง
เฝือกคอชนิดแข็งสำหรับผู้ใหญ่
ความสะอาดห้องผู้ป่วยด้านหลัง
ทดสอบวิทยุ
เสื้อชูชีพสำหรับเจ้าหน้าที่ปฏิบัติการทางน้ำ
กรรไกร
ผู้ป่วยหญิง
กลับคืนสถานะ
เพื่อล้างสถานะ
เข้าสู่ระบบปฏิบัติงาน
คีมพลาสติกหนีบสายสะดือเด็กทารก
ลมบ้าหมู
โรงพยาบาลวัฒนแพทย์สมุย
เครื่องกดนวดหัวใจอัตโนมัติ
กรุณาลงชื่อเข้าใช้งานด้วย
โรงพยาบาลไทยอินเตอร์เกาะพะงัน
เข็มฉีดยาขนาดต่าง
เลือกหน่วยงานกู้ชีพ
เข้าระบบสำเร็จ
ระบบล็อก
ลวดนำสำหรับใส่ท่อช่วยหายใจ
มือถือ
อุปกรณ์คุมเกจ์ออกซิเจน
ไม่รู้สึกตัว
นพ
แพ้แมลง
ขวดน้ำเกลือทำความสะอาดล้างแผล
เข้าสู่ระบบปฏิบัติการ
ผ้าก๊อซทำแผลปลอดเชื้อขนาด
ป้อนรหัส
จัดการหน่วยกู้ชีพและระดับกู้ภัย
ได้รับสารพิษ
วิชาชีพแพทย์
พร้อมใช้
ภูมิใจไทย
คีย์ข้อมูลผู้เจ็บป่วยฉุกเฉินอย่างรวดเร็ว
โรงพยาบาลเกาะพะงัน
เช็กข้อต่อและแรงดัน
เคสสำคัญที่ต้องสืบสวนและติดตามต่อ
คลื่นลมทะเลแรงปานกลางในรอบบ่าย
ปรับปรุงข้อมูลเคสฉุกเฉินและ
ศูนย์นเรนทรอ่าวไทย
ลบ
มีระดับความคลาดเคลื่อนชำรุด
บีบมือ
หน้าเคสปฏิบัติการ
ไม่มีประจำรถ
ประเมินเคสปิดสำเร็จ
บัญชีผู้ใช้งาน
พขร
อัปเดตสเตตัสใบสั่งซ่อมบำรุง
อาการฉุกเฉิน
ออกจากระบบ
ญาติคนไข้
เมื่อเข้าสู่ระบบครั้งแรก
ผู้รับผิดชอบกู้ชีพ
สารน้ำ
แก้ไขแล้ว
สำหรับความปลอดภัย
ความดันลมยางและดอกยาง
อุปกรณ์ยึดตรึงท่อช่วยหายใจ
ลงชื่อเข้าใช้งาน
ระบบบริหารจัดการ
ขบวนกู้ชีพกำลังออกปฏิบัติงานหลัก
บังคับให้เปลี่ยน
ค้าง
ประเมินหน้าห้องฉุกเฉิน
พัฒนาระบบ
ชื่อหน่วยกู้ภัยเครือข่าย
ดร
ดูดเสมหะทารกแรกคลอด
สีเขียว
ยินดีต้อนรับคุณ
แบตเตอรี่รถและขั้วต่อแบตเตอรี่
สายรัดข้อพับสำหรับแทงเส้นเลือดำ
หลัก
ขนาด
สมองขาดเลือด
ไม่มีความเสี่ยงพิเศษในเวร
และ
เกาะเต่า
รายงานประจำวัน
ออกจากระบบสำเร็จเรียบร้อยแล้ว
อุบัติเหตุสิ่งของหล่นทับ
เข็มขัดรัดตรึงเปลผู้ป่วย
ประสานงานเคลื่อนย้ายสุนัขบาดเจ็บ
บัญชีผู้ใช้นี้ถูกระงับการเข้าใช้งานชั่วคราว
พบทั้งหมด
เคสกู้ภัยที่กำลังออก
อุปกรณ์นำส่องทางเดินหายใจ
อุปกรณ์ปรับอัตราไหลออกซิเจน
ผ้าคลุมทำแผลไฟไหม้พุพองสูญเสียความชื้น
สรุปเหตุการณ์สำคัญประจำเวร
เรียบร้อยแล้ว
เป็นไม่พร้อมออกปฏิบัติการ
ผู้อำนวยการศูนย์
ลูกยางแดงเบอร์
สาย
หน้ากากกล่องเสียงท่อช่วยหายใจฉุกเฉิน
เคล็ดลับปฏิบัติการ
ไหม้
ข้อสั่งการแพทย์ออนไลน์
เช้า
เจ้าหน้าที่ควบคุมคุณภาพ
หมายเลขอื่น
ชั่วโมง
ผู้รับผิดชอบหลัก
ข้อมูล
เพิ่มบัญชีผู้ใช้งานใหม่
มีจำนวนเหลือน้อยกว่าขั้นต่ำ
พลาสเตอร์ติดทับสายน้ำเกลือ
เหตุผลชำรุด
@@ -0,0 +1,747 @@
<?php
require_once 'includes/db.php';
require_once 'includes/auth.php';
requireLogin();
// -----------------------------------------------------
// Backend Logic Processing
// -----------------------------------------------------
$success_msg = '';
$error_msg = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
if ($action === 'save_user') {
$user_id = $_POST['user_id'] ?? '';
$username = trim($_POST['username']);
$full_name = trim($_POST['full_name']);
$role = $_POST['role'];
$pin = trim($_POST['pin']);
$must_change_pin = isset($_POST['must_change_pin']) ? 1 : 0;
$is_active = isset($_POST['is_active']) ? 1 : 0;
$password = $_POST['password'] ?? '';
try {
if ($user_id) {
// Update
if (!empty($password)) {
$pw_hash = password_hash($password, PASSWORD_BCRYPT);
$stmt = $pdo->prepare("UPDATE users SET username=?, password=?, full_name=?, role=?, pin=?, must_change_pin=?, is_active=? WHERE id=?");
$stmt->execute([$username, $pw_hash, $full_name, $role, $pin, $must_change_pin, $is_active, $user_id]);
} else {
$stmt = $pdo->prepare("UPDATE users SET username=?, full_name=?, role=?, pin=?, must_change_pin=?, is_active=? WHERE id=?");
$stmt->execute([$username, $full_name, $role, $pin, $must_change_pin, $is_active, $user_id]);
}
$success_msg = "อัปเดตข้อมูลผู้ใช้เรียบร้อยแล้ว";
} else {
// Insert
$pw_hash = password_hash($password ?: '123456', PASSWORD_BCRYPT);
$stmt = $pdo->prepare("INSERT INTO users (username, password, full_name, role, pin, must_change_pin, is_active) VALUES (?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([$username, $pw_hash, $full_name, $role, $pin, $must_change_pin, $is_active]);
$success_msg = "สร้างบัญชีผู้ใช้ใหม่เรียบร้อยแล้ว";
}
} catch (PDOException $e) {
$error_msg = "เกิดข้อผิดพลาด: " . $e->getMessage();
}
}
elseif ($action === 'delete_user') {
$user_id = $_POST['user_id'] ?? '';
if ($user_id && $user_id != $_SESSION['user_id']) { // prevent deleting oneself
try {
$stmt = $pdo->prepare("DELETE FROM users WHERE id=?");
$stmt->execute([$user_id]);
$success_msg = "ลบบัญชีผู้ใช้เรียบร้อยแล้ว";
} catch (PDOException $e) {
$error_msg = "เกิดข้อผิดพลาด: " . $e->getMessage();
}
} else {
$error_msg = "ไม่สามารถลบบัญชีนี้ได้";
}
}
elseif ($action === 'save_unit') {
$unit_id = $_POST['unit_id'] ?? '';
$unit_name = trim($_POST['unit_name']);
$level = $_POST['level'];
$sort_order = (int)$_POST['sort_order'];
$is_samui_hospital = isset($_POST['is_samui_hospital']) ? 1 : 0;
$is_active = isset($_POST['is_active']) ? 1 : 0;
try {
if ($unit_id) {
// Update
$stmt = $pdo->prepare("UPDATE units SET name=?, level=?, sort_order=?, is_samui_hospital=?, is_active=? WHERE id=?");
$stmt->execute([$unit_name, $level, $sort_order, $is_samui_hospital, $is_active, $unit_id]);
$success_msg = "อัปเดตข้อมูลหน่วยกู้ชีพเรียบร้อยแล้ว";
} else {
// Insert
$stmt = $pdo->prepare("INSERT INTO units (name, level, sort_order, is_samui_hospital, is_active) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([$unit_name, $level, $sort_order, $is_samui_hospital, $is_active]);
$success_msg = "เพิ่มหน่วยกู้ภัยเครือข่ายใหม่เรียบร้อยแล้ว";
}
} catch (PDOException $e) {
$error_msg = "เกิดข้อผิดพลาด: " . $e->getMessage();
}
}
elseif ($action === 'delete_unit') {
$unit_id = $_POST['unit_id'] ?? '';
if ($unit_id) {
try {
$stmt = $pdo->prepare("DELETE FROM units WHERE id=?");
$stmt->execute([$unit_id]);
$success_msg = "ลบหน่วยกู้ชีพเรียบร้อยแล้ว";
} catch (PDOException $e) {
$error_msg = "เกิดข้อผิดพลาด: " . $e->getMessage();
}
}
}
elseif ($action === 'save_settings') {
$system_name = trim($_POST['system_name'] ?? '');
$footer_text = trim($_POST['footer_text'] ?? '');
try {
// Check if settings table exists
$pdo->query("SELECT 1 FROM settings LIMIT 1");
$stmt = $pdo->prepare("INSERT INTO settings (setting_key, setting_value) VALUES ('system_name', ?) ON DUPLICATE KEY UPDATE setting_value = ?");
$stmt->execute([$system_name, $system_name]);
$stmt = $pdo->prepare("INSERT INTO settings (setting_key, setting_value) VALUES ('footer_text', ?) ON DUPLICATE KEY UPDATE setting_value = ?");
$stmt->execute([$footer_text, $footer_text]);
$success_msg = "อัปเดตการตั้งค่าทั่วไปเรียบร้อยแล้ว";
} catch (PDOException $e) {
$error_msg = "เกิดข้อผิดพลาด: กรุณารัน mockup_settings.sql เพื่อสร้างตาราง settings ก่อน";
}
}
elseif ($action === 'save_master_data') {
$id = $_POST['id'] ?? '';
$category = trim($_POST['category'] ?? '');
$item_value = trim($_POST['item_value'] ?? '');
$item_label = trim($_POST['item_label'] ?? '');
$sort_order = (int)($_POST['sort_order'] ?? 99);
$is_active = isset($_POST['is_active']) ? 1 : 0;
if ($category && $item_value && $item_label) {
try {
if ($id) {
$stmt = $pdo->prepare("UPDATE master_data SET category = ?, item_value = ?, item_label = ?, sort_order = ?, is_active = ? WHERE id = ?");
$stmt->execute([$category, $item_value, $item_label, $sort_order, $is_active, $id]);
$success_msg = "อัปเดตข้อมูลตัวเลือกเรียบร้อยแล้ว";
} else {
$stmt = $pdo->prepare("INSERT INTO master_data (category, item_value, item_label, sort_order, is_active) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([$category, $item_value, $item_label, $sort_order, $is_active]);
$success_msg = "เพิ่มตัวเลือกใหม่เรียบร้อยแล้ว";
}
} catch (PDOException $e) {
$error_msg = "เกิดข้อผิดพลาด: กรุณารัน mockup_master_data.sql เพื่อสร้างตาราง master_data ก่อน";
}
}
}
}
// Handle GET actions for deletions
if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['action'])) {
$action = $_GET['action'];
if ($action === 'delete_master_data' && isset($_GET['id'])) {
try {
$stmt = $pdo->prepare("DELETE FROM master_data WHERE id = ?");
$stmt->execute([$_GET['id']]);
$success_msg = "ลบตัวเลือกเรียบร้อยแล้ว";
} catch (PDOException $e) {
$error_msg = "เกิดข้อผิดพลาดในการลบข้อมูล: " . $e->getMessage();
}
}
}
// -----------------------------------------------------
// Fetch Data
// -----------------------------------------------------
$users = [];
$units = [];
try {
$stmt = $pdo->query("SELECT * FROM users ORDER BY id ASC");
if ($stmt) $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt = $pdo->query("SELECT * FROM units ORDER BY sort_order ASC, id ASC");
if ($stmt) $units = $stmt->fetchAll(PDO::FETCH_ASSOC);
$master_data = [];
try {
$stmt = $pdo->query("SELECT * FROM master_data ORDER BY category ASC, sort_order ASC, id ASC");
if ($stmt) $master_data = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {}
} catch (PDOException $e) {}
// Fetch settings
$system_name = getSetting($pdo, 'system_name', 'ระบบบริหารจัดการ ศูนย์รับแจ้งเหตุและสั่งการนเรนทรอ่าวไทย');
$footer_text = getSetting($pdo, 'footer_text', 'ศูนย์รับแจ้งเหตุและสั่งการนเรนทรอ่าวไทย ระบบบริหารจัดการ. สงวนลิขสิทธิ์.');
?>
<?php require_once 'includes/header.php'; ?>
<div class="space-y-6 animate-fadeIn pb-10">
<!-- Top Navigation Tabs -->
<div class="flex flex-wrap items-center gap-2 mt-2">
<button type="button" onclick="switchTab('users')" id="tab-btn-users" class="flex items-center justify-center gap-2 px-5 py-2.5 rounded-xl text-sm font-bold shadow-sm cursor-pointer transition-all bg-indigo-600 text-white">
<i data-lucide="users" class="w-4 h-4"></i> ผู้ใช้งาน (Users)
</button>
<button type="button" onclick="switchTab('units')" id="tab-btn-units" class="flex items-center justify-center gap-2 px-5 py-2.5 rounded-xl text-sm font-bold shadow-sm cursor-pointer transition-all bg-white text-slate-600 border border-slate-200 hover:bg-slate-50">
<i data-lucide="truck" class="w-4 h-4"></i> หน่วยกู้ชีพ (Units)
</button>
<button type="button" onclick="switchTab('settings')" id="tab-btn-settings" class="flex items-center justify-center gap-2 px-5 py-2.5 rounded-xl text-sm font-bold shadow-sm cursor-pointer transition-all bg-white text-slate-600 border border-slate-200 hover:bg-slate-50">
<i data-lucide="settings" class="w-4 h-4"></i> ตั้งค่าทั่วไป (Settings)
</button>
<button type="button" onclick="switchTab('dropdowns')" id="tab-btn-dropdowns" class="flex items-center justify-center gap-2 px-5 py-2.5 rounded-xl text-sm font-bold shadow-sm cursor-pointer transition-all bg-white text-slate-600 border border-slate-200 hover:bg-slate-50">
<i data-lucide="list" class="w-4 h-4"></i> ตั้งค่าตัวเลือก (Dropdowns)
</button>
</div>
<!-- Main Content Area -->
<div class="grid grid-cols-1 gap-6">
<!-- Tab Content: User Management -->
<div id="tab-users" class="bg-white rounded-2xl p-5 md:p-6 shadow-sm border border-slate-100 space-y-6">
<div class="border-b border-slate-100 pb-3">
<h3 class="text-base font-black text-slate-800">จัดการข้อมูลผู้ใช้งานระบบ (User Management)</h3>
<p class="text-xs text-slate-400 mt-0.5">เพิ่ม ลบ บัญชีผู้ใช้ เปลี่ยนสิทธิ์ และ PIN ปลดล็อคระบบ</p>
</div>
<form method="POST" id="userForm" class="space-y-4 max-w-4xl" onsubmit="return validateUserForm()">
<input type="hidden" name="action" value="save_user">
<input type="hidden" name="user_id" id="user_id" value="">
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">Username (ลงชื่อเข้าใช้งาน)</label>
<input type="text" name="username" id="username" required placeholder="เช่น dispatcher_test" class="w-full py-2 px-3 border border-slate-200 rounded-lg text-xs font-bold text-slate-700 outline-none focus:border-blue-400">
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">รหัสผ่าน (Password)</label>
<input type="password" name="password" id="password" required minlength="6" placeholder="รหัสผ่านอย่างน้อย 6 อักขระ" class="w-full py-2 px-3 border border-slate-200 rounded-lg text-xs font-bold text-slate-700 outline-none focus:border-blue-400">
<p class="text-[9px] text-slate-400 mt-1 hidden" id="password_hint">เว้นว่างไว้หากไม่ต้องการเปลี่ยนรหัสผ่าน (กรณีแก้ไข)</p>
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">ยืนยันรหัสผ่าน (Confirm Password)</label>
<input type="password" id="confirm_password" required minlength="6" placeholder="ยืนยันรหัสผ่านอีกครั้ง" class="w-full py-2 px-3 border border-slate-200 rounded-lg text-xs font-bold text-slate-700 outline-none focus:border-blue-400">
<p class="text-[9px] text-rose-500 mt-1 hidden" id="password_error">รหัสผ่านไม่ตรงกัน</p>
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">ชื่อ-นามสกุลทางการแพทย์</label>
<input type="text" name="full_name" id="full_name" required placeholder="เช่น นายกู้ชีพ มีสุข" class="w-full py-2 px-3 border border-slate-200 rounded-lg text-xs font-bold text-slate-700 outline-none focus:border-blue-400">
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">สิทธิ์/บทบาทการทำงาน (Role)</label>
<select name="role" id="role" class="w-full py-2 px-3 border border-slate-200 rounded-lg text-xs font-bold text-slate-700 bg-white focus:border-blue-400 outline-none">
<option value="Admin">Admin</option>
<option value="Supervisor">Supervisor</option>
<option value="Dispatcher">Dispatcher</option>
<option value="Executive">Executive</option>
<option value="ER Koh Samui">ER Koh Samui</option>
<option value="Quality Officer">Quality Officer</option>
<option value="Driver">Driver</option>
<option value="EMS">EMS</option>
</select>
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">รหัส PIN 4 หลัก (สำหรับความปลอดภัย)</label>
<input type="password" name="pin" id="pin" maxlength="4" required placeholder="เช่น 1234" class="w-full py-2 px-3 border border-slate-200 rounded-lg text-xs font-bold text-slate-700 font-mono text-center tracking-widest outline-none focus:border-blue-400">
</div>
<div class="col-span-2 flex flex-wrap items-center gap-4 py-1">
<label class="flex items-center gap-1.5 text-xs font-bold text-slate-600 cursor-pointer">
<input type="checkbox" name="must_change_pin" id="must_change_pin" value="1" class="w-4 h-4 text-blue-600 border-slate-200 rounded">
บังคับให้เปลี่ยน PIN เมื่อเข้าสู่ระบบครั้งแรก
</label>
<label class="flex items-center gap-1.5 text-xs font-bold text-slate-600 cursor-pointer">
<input type="checkbox" name="is_active" id="user_is_active" value="1" checked class="w-4 h-4 text-blue-600 border-slate-200 rounded">
เปิดใช้งานบัญชีนี้ (Active)
</label>
</div>
</div>
<div class="flex gap-2 w-full md:w-1/2">
<button type="button" id="btn_cancel_user" onclick="resetUserForm()" class="hidden flex-1 py-2 bg-slate-100 hover:bg-slate-200 text-slate-600 text-xs font-bold rounded-xl transition-all cursor-pointer">ยกเลิกแก้ไข</button>
<button type="submit" id="btn_submit_user" class="flex-1 py-2.5 bg-blue-600 hover:bg-blue-700 text-white font-bold text-xs rounded-xl shadow-md transition-all cursor-pointer">เพิ่มและจัดสร้างผู้ใช้ใหม่</button>
</div>
</form>
<div class="overflow-x-auto border border-slate-100 rounded-xl max-w-4xl">
<table class="w-full text-left border-collapse text-xs">
<thead>
<tr class="bg-slate-50 text-slate-600 font-bold border-b border-slate-100">
<th class="py-2.5 px-3">บัญชี / ชื่อผู้ใช้</th>
<th class="py-2.5 px-3">บทบาท (Role)</th>
<th class="py-2.5 px-3 text-center">สถานะ</th>
<th class="py-2.5 px-3 text-center w-16">แก้ไข</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-50 font-semibold text-slate-700">
<?php foreach ($users as $u): ?>
<tr class="hover:bg-slate-50/50">
<td class="py-2 px-3">
<div class="font-bold text-slate-800"><?php echo htmlspecialchars($u['full_name']); ?></div>
<div class="text-[10px] text-slate-400 font-mono">@<?php echo htmlspecialchars($u['username']); ?></div>
</td>
<td class="py-2 px-3">
<span class="bg-slate-100 px-2 py-0.5 rounded text-[10px] border border-slate-200 text-slate-600"><?php echo htmlspecialchars($u['role']); ?></span>
</td>
<td class="py-2 px-3 text-center">
<?php if($u['is_active']): ?>
<span class="px-2 py-0.5 rounded-[5px] text-[9px] font-black bg-emerald-50 text-emerald-600 border border-emerald-100">Active</span>
<?php else: ?>
<span class="px-2 py-0.5 rounded-[5px] text-[9px] font-black bg-slate-100 text-slate-500 border border-slate-200">Inactive</span>
<?php endif; ?>
</td>
<td class="py-2 px-3 text-center">
<div class="flex gap-1.5 justify-center">
<button type="button" onclick='editUser(<?php echo json_encode($u); ?>)' class="p-1 hover:bg-blue-50 text-slate-400 hover:text-blue-600 rounded cursor-pointer transition-colors"><i data-lucide="pencil" class="w-3.5 h-3.5"></i></button>
<?php if($u['id'] != $_SESSION['user_id']): ?>
<button type="button" onclick="deleteUser(<?php echo $u['id']; ?>)" class="p-1 hover:bg-rose-50 text-slate-300 hover:text-rose-600 rounded cursor-pointer transition-colors"><i data-lucide="trash-2" class="w-3.5 h-3.5"></i></button>
<?php endif; ?>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<!-- Tab Content: Ambulance Fleet -->
<div id="tab-units" class="bg-white rounded-2xl p-5 md:p-6 shadow-sm border border-slate-100 space-y-6 hidden">
<div class="border-b border-slate-100 pb-3">
<h3 class="text-base font-black text-slate-800">จัดการหน่วยกู้ชีพและระดับกู้ภัย (Ambulance Fleet)</h3>
<p class="text-xs text-slate-400 mt-0.5">เพิ่ม ปรับลำดับการทำงาน และระบุหน่วยรับส่งประจำเกาะสมุย</p>
</div>
<form method="POST" class="space-y-4 max-w-4xl">
<input type="hidden" name="action" value="save_unit">
<input type="hidden" name="unit_id" id="unit_id" value="">
<div class="grid grid-cols-2 gap-4">
<div class="col-span-2">
<label class="block text-xs font-bold text-slate-500 mb-1">ชื่อสถานี / หน่วยกู้ชีพร่วมเครือข่าย</label>
<input type="text" name="unit_name" id="unit_name" required placeholder="เช่น หน่วยกู้ชีพตลิ่งงาม" class="w-full py-2 px-3 border border-slate-200 rounded-lg text-xs font-bold text-slate-700 outline-none focus:border-blue-400">
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">ระดับหน่วย (Level)</label>
<select name="level" id="unit_level" class="w-full py-2 px-3 border border-slate-200 rounded-lg text-xs font-bold text-slate-700 bg-white focus:border-blue-400 outline-none">
<option value="ALS">ALS (วิชาชีพขั้นสูง)</option>
<option value="BLS">BLS (รถพยาบาลมาตรฐาน)</option>
<option value="CLS">CLS (หน่วยกู้ภัยพื้นฐาน)</option>
</select>
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">จัดลำดับการทำงาน (Sort Order)</label>
<input type="number" name="sort_order" id="sort_order" placeholder="ลำดับการออกขบวน" value="99" required class="w-full py-2 px-3 border border-slate-200 rounded-lg text-xs font-bold text-slate-700 outline-none focus:border-blue-400">
</div>
<div class="col-span-2 flex flex-wrap items-center gap-4 py-1">
<label class="flex items-center gap-1.5 text-xs font-bold text-slate-600 cursor-pointer">
<input type="checkbox" name="is_samui_hospital" id="is_samui_hospital" value="1" class="w-4 h-4 text-blue-600 border-slate-200 rounded">
ระบุเป็นหน่วยโรงพยาบาลเกาะสมุย (ER สมุยหลัก)
</label>
<label class="flex items-center gap-1.5 text-xs font-bold text-slate-600 cursor-pointer">
<input type="checkbox" name="is_active" id="unit_is_active" value="1" checked class="w-4 h-4 text-blue-600 border-slate-200 rounded">
เปิดใช้งานขบวนนี้ (Active)
</label>
</div>
</div>
<div class="flex gap-2 w-full md:w-1/2">
<button type="button" id="btn_cancel_unit" onclick="resetUnitForm()" class="hidden flex-1 py-2 bg-slate-100 hover:bg-slate-200 text-slate-600 text-xs font-bold rounded-xl transition-all cursor-pointer">ยกเลิกแก้ไข</button>
<button type="submit" id="btn_submit_unit" class="flex-1 py-2.5 bg-blue-600 hover:bg-blue-700 text-white font-bold text-xs rounded-xl shadow-md transition-all cursor-pointer">เพิ่มหน่วยกู้ภัยเครือข่ายใหม่</button>
</div>
</form>
<div class="overflow-x-auto border border-slate-100 rounded-xl max-w-4xl">
<table class="w-full text-left border-collapse text-xs">
<thead>
<tr class="bg-slate-50 text-slate-600 font-bold border-b border-slate-100">
<th class="py-2.5 px-3">ชื่อหน่วยกู้ภัยเครือข่าย</th>
<th class="py-2.5 px-3">ระดับ</th>
<th class="py-2.5 px-3 text-center">สิทธิ์ รพ.สมุย</th>
<th class="py-2.5 px-3 text-center w-16">แก้ไข</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-50 font-semibold text-slate-700">
<?php foreach ($units as $unit): ?>
<tr class="hover:bg-slate-50/50">
<td class="py-2 px-3">
<div class="font-bold text-slate-800"><?php echo htmlspecialchars($unit['name']); ?></div>
<div class="text-[10px] text-slate-400 font-mono">ลำดับ: <?php echo htmlspecialchars($unit['sort_order']); ?></div>
</td>
<td class="py-2 px-3">
<?php
$levelColor = 'bg-slate-100 text-slate-600 border-slate-200';
if ($unit['level'] === 'ALS') $levelColor = 'bg-red-50 text-red-600 border-red-100';
if ($unit['level'] === 'BLS') $levelColor = 'bg-blue-50 text-blue-600 border-blue-100';
if ($unit['level'] === 'CLS') $levelColor = 'bg-amber-50 text-amber-600 border-amber-100';
?>
<span class="px-1.5 py-0.5 rounded-[4px] text-[10px] font-black border <?php echo $levelColor; ?>"><?php echo htmlspecialchars($unit['level']); ?></span>
</td>
<td class="py-2 px-3 text-center">
<?php if($unit['is_samui_hospital']): ?>
<span class="text-emerald-600 flex items-center justify-center gap-1 font-black"><span class="w-2 h-2 rounded-full bg-emerald-500"></span> ใช่</span>
<?php else: ?>
<span class="text-rose-600 flex items-center justify-center gap-1 font-bold"><i data-lucide="x" class="w-3.5 h-3.5 text-rose-500 stroke-[3px]"></i> ไม่</span>
<?php endif; ?>
</td>
<td class="py-2 px-3 text-center">
<div class="flex gap-1.5 justify-center">
<button type="button" onclick='editUnit(<?php echo json_encode($unit); ?>)' class="p-1 hover:bg-blue-50 text-slate-400 hover:text-blue-600 rounded cursor-pointer transition-colors"><i data-lucide="pencil" class="w-3.5 h-3.5"></i></button>
<button type="button" onclick="deleteUnit(<?php echo $unit['id']; ?>)" class="p-1 hover:bg-rose-50 text-slate-300 hover:text-rose-600 rounded cursor-pointer transition-colors"><i data-lucide="trash-2" class="w-3.5 h-3.5"></i></button>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<!-- Tab Content: General Settings -->
<div id="tab-settings" class="bg-white rounded-2xl p-5 md:p-6 shadow-sm border border-slate-100 space-y-6 hidden">
<div class="border-b border-slate-100 pb-3">
<h3 class="text-base font-black text-slate-800">ตั้งค่าทั่วไป (General Settings)</h3>
<p class="text-xs text-slate-400 mt-0.5">ปรับแต่งข้อความและชื่อระบบหลัก</p>
</div>
<form method="POST" class="space-y-4 max-w-4xl">
<input type="hidden" name="action" value="save_settings">
<div class="grid grid-cols-1 gap-4">
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">ชื่อระบบ (แสดงผลที่ Topbar)</label>
<input type="text" name="system_name" value="<?php echo htmlspecialchars($system_name); ?>" required class="w-full py-2 px-3 border border-slate-200 rounded-lg text-sm font-bold text-slate-700 outline-none focus:border-blue-400">
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">ข้อความส่วนท้าย (Footer)</label>
<input type="text" name="footer_text" value="<?php echo htmlspecialchars($footer_text); ?>" required class="w-full py-2 px-3 border border-slate-200 rounded-lg text-sm font-bold text-slate-700 outline-none focus:border-blue-400">
</div>
</div>
<div class="flex gap-2 w-full md:w-1/3 pt-2">
<button type="submit" class="flex-1 py-2.5 bg-blue-600 hover:bg-blue-700 text-white font-bold text-xs rounded-xl shadow-md transition-all cursor-pointer">
บันทึกการตั้งค่า
</button>
</div>
</form>
</div>
<!-- Tab Content: Dropdowns Master Data -->
<div id="tab-dropdowns" class="bg-white rounded-2xl p-5 md:p-6 shadow-sm border border-slate-100 space-y-6 hidden">
<div class="border-b border-slate-100 pb-3">
<h3 class="text-base font-black text-slate-800">ตั้งค่าตัวเลือกฟอร์ม (Form Dropdowns)</h3>
<p class="text-xs text-slate-400 mt-0.5">จัดการรายการตัวเลือกต่างๆ ในหน้าฟอร์มรับแจ้งเหตุ</p>
</div>
<form method="POST" class="space-y-4 max-w-4xl">
<input type="hidden" name="action" value="save_master_data">
<input type="hidden" name="id" id="md_id" value="">
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">หมวดหมู่ (Category)</label>
<select name="category" id="md_category" required class="w-full py-2 px-3 border border-slate-200 rounded-lg text-sm font-bold text-slate-700 outline-none focus:border-blue-400">
<option value="call_type">ประเภทสายเรียกเข้า (call_type)</option>
<option value="call_channel">ช่องทางการแจ้งเหตุ (call_channel)</option>
<option value="ems_refer">ประเภทปฏิบัติการ (ems_refer)</option>
<option value="unit_level">ระดับหน่วยกู้ชีพ (unit_level)</option>
<option value="cbd_symptom">จำแนกกลุ่มอาการ (cbd_symptom)</option>
<option value="phone_triage">Phone Triage (phone_triage)</option>
<option value="fast_track">รหัสเฉพาะผู้ป่วยวิกฤต (fast_track)</option>
<option value="transport_route">เส้นทางลำเลียงผู้ป่วย (transport_route)</option>
</select>
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">ข้อความที่แสดง (Label)</label>
<input type="text" name="item_label" id="md_item_label" required placeholder="เช่น สายก่อกวน" class="w-full py-2 px-3 border border-slate-200 rounded-lg text-sm font-bold text-slate-700 outline-none focus:border-blue-400">
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">ค่า (Value)</label>
<input type="text" name="item_value" id="md_item_value" required placeholder="เช่น สายก่อกวน" class="w-full py-2 px-3 border border-slate-200 rounded-lg text-sm font-bold text-slate-700 outline-none focus:border-blue-400">
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">ลำดับการแสดงผล (Sort Order)</label>
<input type="number" name="sort_order" id="md_sort_order" value="99" required class="w-full py-2 px-3 border border-slate-200 rounded-lg text-sm font-bold text-slate-700 outline-none focus:border-blue-400">
</div>
<div class="col-span-2 flex items-center pt-2">
<label class="flex items-center gap-1.5 text-xs font-bold text-slate-600 cursor-pointer">
<input type="checkbox" name="is_active" id="md_is_active" value="1" checked class="w-4 h-4 text-blue-600 border-slate-200 rounded">
เปิดใช้งานตัวเลือกนี้ (Active)
</label>
</div>
</div>
<div class="flex gap-2 w-full md:w-1/2 pt-2">
<button type="button" id="btn_cancel_md" onclick="resetMasterDataForm()" class="hidden flex-1 py-2 bg-slate-100 hover:bg-slate-200 text-slate-600 text-xs font-bold rounded-xl transition-all cursor-pointer">ยกเลิก</button>
<button type="submit" id="btn_submit_md" class="flex-1 py-2.5 bg-blue-600 hover:bg-blue-700 text-white font-bold text-xs rounded-xl shadow-md transition-all cursor-pointer">เพิ่มตัวเลือกใหม่</button>
</div>
</form>
<div class="overflow-x-auto border border-slate-100 rounded-xl max-w-4xl mt-6">
<?php
$grouped_md = [];
foreach($master_data as $md) {
$grouped_md[$md['category']][] = $md;
}
$category_names = [
'call_type' => 'ประเภทสายเรียกเข้า',
'call_channel' => 'ช่องทางการแจ้งเหตุ',
'ems_refer' => 'ประเภทปฏิบัติการ',
'unit_level' => 'ระดับหน่วยกู้ชีพ',
'cbd_symptom' => 'จำแนกกลุ่มอาการ',
'phone_triage' => 'Phone Triage',
'fast_track' => 'รหัสเฉพาะผู้ป่วยวิกฤต',
'transport_route' => 'เส้นทางลำเลียงผู้ป่วย'
];
?>
<table class="w-full text-left border-collapse text-xs">
<thead>
<tr class="bg-slate-50 text-slate-600 font-bold border-b border-slate-100">
<th class="py-2.5 px-3">ข้อความ (Label)</th>
<th class="py-2.5 px-3">ค่า (Value)</th>
<th class="py-2.5 px-3">ลำดับ</th>
<th class="py-2.5 px-3 text-center">สถานะ</th>
<th class="py-2.5 px-3 text-center w-16">จัดการ</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-50 font-semibold text-slate-700">
<?php foreach ($grouped_md as $cat_key => $items): ?>
<tr class="bg-indigo-50/50 border-b border-indigo-100">
<td colspan="5" class="py-2 px-3 font-bold text-indigo-700">
<div class="flex items-center gap-2">
<i data-lucide="layers" class="w-4 h-4"></i>
หมวดหมู่: <?php echo htmlspecialchars($category_names[$cat_key] ?? $cat_key); ?> (<?php echo $cat_key; ?>)
</div>
</td>
</tr>
<?php foreach ($items as $md): ?>
<tr class="hover:bg-slate-50/50">
<td class="py-2 px-3"><?php echo htmlspecialchars($md['item_label']); ?></td>
<td class="py-2 px-3 text-slate-400"><?php echo htmlspecialchars($md['item_value']); ?></td>
<td class="py-2 px-3"><?php echo htmlspecialchars($md['sort_order']); ?></td>
<td class="py-2 px-3 text-center">
<?php if($md['is_active']): ?>
<span class="px-2 py-0.5 rounded-[5px] text-[9px] font-black bg-emerald-50 text-emerald-600 border border-emerald-100">Active</span>
<?php else: ?>
<span class="px-2 py-0.5 rounded-[5px] text-[9px] font-black bg-slate-100 text-slate-500 border border-slate-200">Inactive</span>
<?php endif; ?>
</td>
<td class="py-2 px-3 text-center">
<div class="flex gap-1.5 justify-center">
<button type="button" onclick='editMasterData(<?php echo json_encode($md); ?>)' class="p-1 hover:bg-blue-50 text-slate-400 hover:text-blue-600 rounded cursor-pointer transition-colors"><i data-lucide="pencil" class="w-3.5 h-3.5"></i></button>
<a href="admin.php?action=delete_master_data&id=<?php echo $md['id']; ?>" onclick="return confirm('ยืนยันการลบ?');" class="p-1 hover:bg-rose-50 text-slate-300 hover:text-rose-600 rounded cursor-pointer transition-colors"><i data-lucide="trash-2" class="w-3.5 h-3.5"></i></a>
</div>
</td>
</tr>
<?php endforeach; ?>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Forms Hidden Actions for Delete -->
<form id="deleteUserForm" method="POST" style="display:none;">
<input type="hidden" name="action" value="delete_user">
<input type="hidden" name="user_id" id="delete_user_id" value="">
</form>
<form id="deleteUnitForm" method="POST" style="display:none;">
<input type="hidden" name="action" value="delete_unit">
<input type="hidden" name="unit_id" id="delete_unit_id" value="">
</form>
<script>
lucide.createIcons();
// Tab Switching Logic
function switchTab(tabName) {
// Hide all tabs
document.getElementById('tab-users').classList.add('hidden');
document.getElementById('tab-units').classList.add('hidden');
document.getElementById('tab-settings').classList.add('hidden');
document.getElementById('tab-dropdowns').classList.add('hidden');
// Reset all buttons styling
const btnClassesActive = ['bg-indigo-600', 'text-white'];
const btnClassesInactive = ['bg-white', 'text-slate-600', 'border', 'border-slate-200', 'hover:bg-slate-50'];
const btns = ['users', 'units', 'settings', 'dropdowns'];
btns.forEach(name => {
const btn = document.getElementById('tab-btn-' + name);
btn.classList.remove(...btnClassesActive);
btn.classList.add(...btnClassesInactive);
});
// Show target tab and update button styling
document.getElementById('tab-' + tabName).classList.remove('hidden');
const activeBtn = document.getElementById('tab-btn-' + tabName);
activeBtn.classList.remove(...btnClassesInactive);
activeBtn.classList.add(...btnClassesActive);
}
<?php if ($success_msg): ?>
Swal.fire({
icon: 'success',
title: 'สำเร็จ!',
text: '<?php echo $success_msg; ?>',
timer: 2500,
showConfirmButton: false
});
<?php endif; ?>
<?php if ($error_msg): ?>
Swal.fire({
icon: 'error',
title: 'เกิดข้อผิดพลาด',
text: '<?php echo $error_msg; ?>'
});
<?php endif; ?>
function editUser(user) {
document.getElementById('user_id').value = user.id;
document.getElementById('username').value = user.username;
document.getElementById('password').value = '';
document.getElementById('confirm_password').value = '';
document.getElementById('password').removeAttribute('required');
document.getElementById('confirm_password').removeAttribute('required');
document.getElementById('full_name').value = user.full_name;
document.getElementById('role').value = user.role;
document.getElementById('pin').value = user.pin;
document.getElementById('must_change_pin').checked = user.must_change_pin == 1;
document.getElementById('user_is_active').checked = user.is_active == 1;
document.getElementById('btn_submit_user').textContent = 'บันทึกการปรับปรุงผู้ใช้';
document.getElementById('btn_cancel_user').classList.remove('hidden');
document.getElementById('password_hint').classList.remove('hidden');
document.getElementById('password_error').classList.add('hidden');
window.scrollTo({top: 0, behavior: 'smooth'});
}
function resetUserForm() {
document.getElementById('user_id').value = '';
document.getElementById('username').value = '';
document.getElementById('password').value = '';
document.getElementById('confirm_password').value = '';
document.getElementById('password').setAttribute('required', 'required');
document.getElementById('confirm_password').setAttribute('required', 'required');
document.getElementById('full_name').value = '';
document.getElementById('role').value = 'Dispatcher';
document.getElementById('pin').value = '';
document.getElementById('must_change_pin').checked = false;
document.getElementById('user_is_active').checked = true;
document.getElementById('btn_submit_user').textContent = 'เพิ่มและจัดสร้างผู้ใช้ใหม่';
document.getElementById('btn_cancel_user').classList.add('hidden');
document.getElementById('password_hint').classList.add('hidden');
document.getElementById('password_error').classList.add('hidden');
}
function deleteUser(id) {
Swal.fire({
title: 'ยืนยันการลบผู้ใช้?',
text: "ข้อมูลผู้ใช้นี้จะถูกลบออกจากระบบอย่างถาวร",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#cbd5e1',
confirmButtonText: 'ใช่, ลบเลย!',
cancelButtonText: 'ยกเลิก'
}).then((result) => {
if (result.isConfirmed) {
document.getElementById('delete_user_id').value = id;
document.getElementById('deleteUserForm').submit();
}
});
}
function editUnit(unit) {
document.getElementById('unit_id').value = unit.id;
document.getElementById('unit_name').value = unit.name;
document.getElementById('unit_level').value = unit.level;
document.getElementById('sort_order').value = unit.sort_order;
document.getElementById('is_samui_hospital').checked = unit.is_samui_hospital == 1;
document.getElementById('unit_is_active').checked = unit.is_active == 1;
document.getElementById('btn_submit_unit').textContent = 'บันทึกการปรับปรุงหน่วยงาน';
document.getElementById('btn_cancel_unit').classList.remove('hidden');
window.scrollTo({top: 0, behavior: 'smooth'});
}
function resetUnitForm() {
document.getElementById('unit_id').value = '';
document.getElementById('unit_name').value = '';
document.getElementById('unit_level').value = 'BLS';
document.getElementById('sort_order').value = '99';
document.getElementById('is_samui_hospital').checked = false;
document.getElementById('unit_is_active').checked = true;
document.getElementById('btn_submit_unit').textContent = 'เพิ่มหน่วยกู้ภัยเครือข่ายใหม่';
document.getElementById('btn_cancel_unit').classList.add('hidden');
}
function deleteUnit(id) {
Swal.fire({
title: 'ยืนยันการลบหน่วยกู้ชีพ?',
text: "ข้อมูลหน่วยกู้ชีพนี้จะถูกลบออกจากระบบอย่างถาวร",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#cbd5e1',
confirmButtonText: 'ใช่, ลบเลย!',
cancelButtonText: 'ยกเลิก'
}).then((result) => {
if (result.isConfirmed) {
document.getElementById('delete_unit_id').value = id;
document.getElementById('deleteUnitForm').submit();
}
});
}
function editMasterData(md) {
document.getElementById('md_id').value = md.id;
document.getElementById('md_category').value = md.category;
document.getElementById('md_item_value').value = md.item_value;
document.getElementById('md_item_label').value = md.item_label;
document.getElementById('md_sort_order').value = md.sort_order;
document.getElementById('md_is_active').checked = md.is_active == 1;
document.getElementById('btn_submit_md').textContent = 'บันทึกการแก้ไขตัวเลือก';
document.getElementById('btn_cancel_md').classList.remove('hidden');
window.scrollTo({top: 0, behavior: 'smooth'});
}
function resetMasterDataForm() {
document.getElementById('md_id').value = '';
document.getElementById('md_category').value = 'call_type';
document.getElementById('md_item_value').value = '';
document.getElementById('md_item_label').value = '';
document.getElementById('md_sort_order').value = '99';
document.getElementById('md_is_active').checked = true;
document.getElementById('btn_submit_md').textContent = 'เพิ่มตัวเลือกใหม่';
document.getElementById('btn_cancel_md').classList.add('hidden');
}
function validateUserForm() {
const pw = document.getElementById('password').value;
const cpw = document.getElementById('confirm_password').value;
const errorMsg = document.getElementById('password_error');
if (pw !== cpw) {
errorMsg.classList.remove('hidden');
document.getElementById('confirm_password').focus();
return false;
}
errorMsg.classList.add('hidden');
return true;
}
</script>
<?php require_once 'includes/footer.php'; ?>
@@ -0,0 +1,299 @@
<?php
require_once 'includes/db.php';
require_once 'includes/auth.php';
requireLogin();
// Fetch summary counts
$readyCount = 0;
$limitedCount = 0;
$notReadyCount = 0;
$uncheckedCount = 0;
try {
$stmt = $pdo->query("SELECT overall_status, COUNT(*) as count FROM ambulances GROUP BY overall_status");
if ($stmt) {
$counts = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($counts as $row) {
if ($row['overall_status'] === 'พร้อมปฏิบัติการ') $readyCount = $row['count'];
if ($row['overall_status'] === 'พร้อมใช้งานแบบมีข้อจำกัด') $limitedCount = $row['count'];
if ($row['overall_status'] === 'ไม่พร้อมปฏิบัติการ') $notReadyCount = $row['count'];
if ($row['overall_status'] === 'ยังไม่ได้ตรวจ') $uncheckedCount = $row['count'];
}
}
} catch (Exception $e) {}
// Fetch ambulances list
$ambulances = [];
try {
$query = "
SELECT
a.id, a.plate_no, a.type, a.latest_check_date, a.latest_check_time,
a.latest_check_by, a.overall_status, a.issues_count,
u.name as unit_name
FROM ambulances a
LEFT JOIN units u ON a.unit_id = u.id
ORDER BY a.id ASC
";
$stmt = $pdo->query($query);
if ($stmt) $ambulances = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Exception $e) {}
// Fetch Critical Issues
$criticalAmbulances = [];
try {
$query = "
SELECT
a.id, a.plate_no, u.name as unit_name, a.latest_check_by, a.issues_count
FROM ambulances a
LEFT JOIN units u ON a.unit_id = u.id
WHERE a.overall_status = 'ไม่พร้อมปฏิบัติการ' OR a.issues_count > 0
";
$stmt = $pdo->query($query);
if ($stmt) $criticalAmbulances = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Exception $e) {}
// Fetch Expiring Inventory
$expiringItems = [];
try {
$query = "
SELECT
i.item_name, i.expire_date,
a.id as ambulance_id, a.plate_no
FROM ambulance_inventory i
JOIN ambulances a ON i.ambulance_id = a.id
ORDER BY i.expire_date ASC
";
$stmt = $pdo->query($query);
if ($stmt) $expiringItems = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Exception $e) {}
function getDaysUntil($dateStr) {
$now = new DateTime();
$target = new DateTime($dateStr);
$diff = $now->diff($target);
$days = (int)$diff->format('%R%a');
return $days;
}
?>
<?php require_once 'includes/header.php'; ?>
<div class="space-y-6 animate-fadeIn pb-10">
<!-- Top Navigation Tabs -->
<div class="flex flex-wrap items-center gap-2">
<button class="bg-indigo-600 text-white flex items-center justify-center gap-2 px-5 py-2.5 rounded-xl text-sm font-bold shadow-sm cursor-default">
<i data-lucide="layout-dashboard" class="w-4 h-4"></i> แดชบอร์ดรถพยาบาล
</button>
<button onclick="Swal.fire('Coming Soon', 'ระบบแบบฟอร์มกำลังพัฒนา', 'info')" class="bg-white text-slate-600 border border-slate-200 hover:bg-slate-50 flex items-center justify-center gap-2 px-5 py-2.5 rounded-xl text-sm font-bold transition-all cursor-pointer">
<i data-lucide="plus-circle" class="w-4 h-4 text-slate-400"></i> แบบฟอร์มตรวจความพร้อมรถ
</button>
<button onclick="Swal.fire('Coming Soon', 'ระบบรายการซ่อมบำรุงกำลังพัฒนา', 'info')" class="bg-white text-slate-600 border border-slate-200 hover:bg-slate-50 flex items-center justify-center gap-2 px-5 py-2.5 rounded-xl text-sm font-bold transition-all cursor-pointer">
<i data-lucide="triangle-alert" class="w-4 h-4 text-slate-400"></i> รายการซ่อมบำรุง (2)
</button>
</div>
<!-- 4 Summary Cards -->
<div class="grid grid-cols-2 lg:grid-cols-4 gap-4">
<div class="bg-white p-4 rounded-2xl shadow-sm border border-slate-100 flex items-center gap-3">
<div class="p-3 bg-emerald-50 text-emerald-600 rounded-xl">
<i data-lucide="shield-check" class="w-6 h-6"></i>
</div>
<div>
<div class="text-xs text-slate-400 font-bold">พร้อมปฏิบัติการ</div>
<div class="text-xl md:text-2xl font-black text-slate-800"><?php echo $readyCount; ?> <span class="text-sm font-bold text-slate-500">คัน</span></div>
</div>
</div>
<div class="bg-white p-4 rounded-2xl shadow-sm border border-slate-100 flex items-center gap-3">
<div class="p-3 bg-amber-50 text-amber-600 rounded-xl">
<i data-lucide="triangle-alert" class="w-6 h-6"></i>
</div>
<div>
<div class="text-xs text-slate-400 font-bold font-sans">พร้อมใช้มีข้อจำกัด</div>
<div class="text-xl md:text-2xl font-black text-slate-800"><?php echo $limitedCount; ?> <span class="text-sm font-bold text-slate-500">คัน</span></div>
</div>
</div>
<div class="bg-white p-4 rounded-2xl shadow-sm border border-slate-100 flex items-center gap-3">
<div class="p-3 bg-red-50 text-red-600 rounded-xl">
<i data-lucide="x-circle" class="w-6 h-6"></i>
</div>
<div>
<div class="text-xs text-slate-400 font-bold">ไม่พร้อมใช้</div>
<div class="text-xl md:text-2xl font-black text-slate-800"><?php echo $notReadyCount; ?> <span class="text-sm font-bold text-slate-500">คัน</span></div>
</div>
</div>
<div class="bg-white p-4 rounded-2xl shadow-sm border border-slate-100 flex items-center gap-3">
<div class="p-3 bg-slate-50 text-slate-400 rounded-xl">
<i data-lucide="clock" class="w-6 h-6"></i>
</div>
<div>
<div class="text-xs text-slate-400 font-bold">ยังไม่ได้ตรวจประจำเวร</div>
<div class="text-xl md:text-2xl font-black text-slate-800"><?php echo $uncheckedCount; ?> <span class="text-sm font-bold text-slate-500">คัน</span></div>
</div>
</div>
</div>
<!-- Main Table -->
<div class="bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden">
<div class="p-4 md:p-5 border-b border-slate-100 bg-slate-50 flex items-center justify-between">
<div>
<h3 class="text-base font-bold text-slate-800">สถานะความพร้อมรถพยาบาลปัจจุบัน</h3>
<p class="text-xs text-slate-500 mt-0.5">แสดงข้อมูลจากการประเมินครั้งล่าสุดของแต่ละคันในระบบ</p>
</div>
</div>
<div class="overflow-x-auto">
<table class="w-full text-left border-collapse text-xs md:text-sm">
<thead>
<tr class="bg-slate-100/50 text-slate-600 font-bold border-b border-slate-100">
<th class="py-3 px-4">รหัส / ทะเบียนรถ</th>
<th class="py-3 px-3">หน่วยงานผู้ควบคุม</th>
<th class="py-3 px-3 text-center">ประเภทรถ</th>
<th class="py-3 px-3">เวลาที่ตรวจล่าสุด</th>
<th class="py-3 px-3">ผู้ตรวจสภาพ</th>
<th class="py-3 px-3 text-center">สถานะความพร้อม</th>
<th class="py-3 px-3 text-center">รายงานปัญหา</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100 text-slate-700 font-medium">
<?php if (empty($ambulances)): ?>
<tr><td colspan="7" class="text-center py-6 text-slate-400 font-bold">ไม่มีข้อมูลรถพยาบาล</td></tr>
<?php else: ?>
<?php foreach ($ambulances as $amb):
// Determine type badge
$typeClass = $amb['type'] === 'ALS' ? 'bg-red-100 text-red-800 border border-red-200' : 'bg-blue-100 text-blue-800 border border-blue-200';
// Determine status badge
$statusClass = 'bg-slate-100 text-slate-500 border-slate-200';
$statusIcon = 'w-3 h-3 bg-slate-400 rounded-full';
if ($amb['overall_status'] === 'พร้อมปฏิบัติการ') {
$statusClass = 'bg-emerald-50 text-emerald-700 border-emerald-200';
$statusIcon = 'w-1.5 h-1.5 bg-emerald-500 rounded-full';
} elseif ($amb['overall_status'] === 'พร้อมใช้งานแบบมีข้อจำกัด') {
$statusClass = 'bg-amber-50 text-amber-700 border-amber-200';
$statusIcon = 'w-1.5 h-1.5 bg-amber-500 rounded-full';
} elseif ($amb['overall_status'] === 'ไม่พร้อมปฏิบัติการ') {
$statusClass = 'bg-rose-50 text-rose-700 border-rose-200';
$statusIcon = 'w-1.5 h-1.5 bg-rose-500 rounded-full';
}
?>
<tr class="hover:bg-slate-50/50 transition-colors">
<td class="py-3.5 px-4">
<div class="flex items-center gap-2">
<i data-lucide="truck" class="w-4 h-4 text-slate-400"></i>
<div>
<div class="font-bold text-slate-800"><?php echo htmlspecialchars($amb['id']); ?></div>
<div class="text-[10px] text-slate-400 font-mono font-semibold"><?php echo htmlspecialchars($amb['plate_no']); ?></div>
</div>
</div>
</td>
<td class="py-3.5 px-3">
<span class="bg-slate-100 px-2.5 py-1 rounded-lg text-slate-600 font-semibold"><?php echo htmlspecialchars($amb['unit_name'] ?? 'ไม่ระบุ'); ?></span>
</td>
<td class="py-3.5 px-3 text-center">
<span class="px-2 py-0.5 rounded text-[10px] font-bold <?php echo $typeClass; ?>"><?php echo htmlspecialchars($amb['type']); ?></span>
</td>
<td class="py-3.5 px-3 font-mono text-slate-500 text-xs">
<?php if ($amb['latest_check_date']): ?>
<?php echo htmlspecialchars($amb['latest_check_date']); ?> | <?php echo htmlspecialchars(substr($amb['latest_check_time'], 0, 5)); ?> น.
<?php else: ?>
ยังไม่ได้ตรวจ
<?php endif; ?>
</td>
<td class="py-3.5 px-3 text-slate-600 truncate max-w-[130px]">
<?php echo htmlspecialchars($amb['latest_check_by'] ?? '-'); ?>
</td>
<td class="py-3.5 px-3 text-center">
<span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-bold border shadow-sm <?php echo $statusClass; ?>">
<span class="<?php echo $statusIcon; ?>"></span>
<?php echo htmlspecialchars($amb['overall_status']); ?>
</span>
</td>
<td class="py-3.5 px-3 text-center">
<?php if ($amb['issues_count'] > 0): ?>
<span class="bg-rose-100 text-rose-700 font-black text-xs px-2.5 py-1 rounded-full border border-rose-200 animate-pulse">
⚠️ พบจุดชำรุด <?php echo $amb['issues_count']; ?> แห่ง
</span>
<?php else: ?>
<span class="text-slate-400 text-xs font-semibold">ปกติ</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<!-- Bottom Alerts -->
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Left: Critical Issues -->
<div class="bg-white rounded-2xl shadow-sm border border-slate-100 p-5 space-y-4">
<div class="flex items-center justify-between border-b border-slate-50 pb-2">
<h4 class="font-bold text-slate-800 flex items-center gap-2">
<i data-lucide="triangle-alert" class="w-4 h-4 text-rose-600"></i> แจ้งเตือนรถพยาบาลวิกฤต/ฉุกเฉิน
</h4>
<span class="text-[10px] bg-red-50 text-red-600 font-bold px-2 py-0.5 rounded-full border border-red-200">ต้องการแก้ไขด่วน</span>
</div>
<div class="space-y-2.5">
<?php if (empty($criticalAmbulances)): ?>
<div class="text-center py-6 text-slate-400 text-xs font-medium">✨ ระบบไม่พบปัญหาเร่งด่วนในรถกู้ชีพพยาบาลทุกคัน</div>
<?php else: ?>
<?php foreach ($criticalAmbulances as $cAmb): ?>
<div class="flex items-center justify-between bg-red-50/30 p-3 rounded-xl border border-red-100">
<div>
<div class="text-xs font-bold text-slate-800"><?php echo htmlspecialchars($cAmb['id']); ?> (<?php echo htmlspecialchars($cAmb['plate_no']); ?>)</div>
<div class="text-[10px] text-slate-500 mt-1">ค่ายดูแล: <?php echo htmlspecialchars($cAmb['unit_name']); ?> | ตรวจโดย: <?php echo htmlspecialchars($cAmb['latest_check_by']); ?></div>
</div>
<div class="text-right">
<span class="bg-red-100 text-red-800 text-[10px] font-black px-2 py-1 rounded border border-red-200 uppercase tracking-wide">ไม่พร้อมใช้ (<?php echo $cAmb['issues_count']; ?> ปัญหา)</span>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
<!-- Right: Expiring Inventory -->
<div class="bg-white rounded-2xl shadow-sm border border-slate-100 p-5 space-y-4">
<div class="flex items-center justify-between border-b border-slate-50 pb-2">
<h4 class="font-bold text-slate-800 flex items-center gap-2">
<i data-lucide="package" class="w-4 h-4 text-amber-600"></i> ยา/เวชภัณฑ์ใกล้หมดอายุ
</h4>
<span class="text-[10px] bg-amber-50 text-amber-700 font-bold px-2 py-0.5 rounded-full border border-amber-200">ตรวจสอบดวงชะตาเวชภัณฑ์</span>
</div>
<div class="space-y-2.5">
<?php if (empty($expiringItems)): ?>
<div class="text-center py-6 text-slate-400 text-xs font-medium">ไม่มียา/เวชภัณฑ์ใกล้หมดอายุ</div>
<?php else: ?>
<?php foreach ($expiringItems as $item):
$days = getDaysUntil($item['expire_date']);
$isExpired = $days <= 30; // Just an example threshold
$textClass = $isExpired ? 'text-amber-700' : 'text-slate-500';
$statusText = $isExpired ? "หมดอายุ {$days} วันข้างหน้า" : "เหลือ {$days} วัน";
?>
<div class="flex items-center justify-between bg-amber-50/40 p-3 rounded-xl border border-amber-100">
<div>
<div class="text-xs font-bold text-slate-800"><?php echo htmlspecialchars($item['item_name']); ?></div>
<div class="text-[10px] text-slate-400 mt-1">รถ: <?php echo htmlspecialchars($item['ambulance_id']); ?> | ทะเบียน: <?php echo htmlspecialchars($item['plate_no']); ?></div>
</div>
<div class="text-right">
<span class="text-xs font-extrabold <?php echo $textClass; ?>"><?php echo $statusText; ?></span>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
</div>
</div>
<script>
lucide.createIcons();
</script>
<?php require_once 'includes/footer.php'; ?>
@@ -0,0 +1,84 @@
<?php
header('Content-Type: application/json');
require_once '../includes/db.php';
require_once '../includes/auth.php';
if (!isset($_SESSION['user_id'])) {
echo json_encode(['success' => false, 'message' => 'Unauthorized']);
exit;
}
// Ensure tables exist
try {
$pdo->exec("
CREATE TABLE IF NOT EXISTS `radio_test_sessions` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` date NOT NULL,
`time` time NOT NULL,
`shift` varchar(20) NOT NULL,
`tester_id` int(11) NOT NULL,
`tested_count` int(11) NOT NULL DEFAULT 0,
`untested_count` int(11) NOT NULL DEFAULT 0,
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `radio_test_records` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`session_id` int(11) NOT NULL,
`station_id` varchar(50) NOT NULL,
`station_name` varchar(100) NOT NULL,
`tx_level` varchar(20) NOT NULL,
`rx_level` varchar(20) NOT NULL,
`channel_type` varchar(10) NOT NULL DEFAULT 'T',
`note` text,
PRIMARY KEY (`id`),
KEY `session_id` (`session_id`),
CONSTRAINT `radio_test_records_ibfk_1` FOREIGN KEY (`session_id`) REFERENCES `radio_test_sessions` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
");
} catch (Exception $e) {}
// Process request
$data = json_decode(file_get_contents('php://input'), true);
if (!$data) {
echo json_encode(['success' => false, 'message' => 'Invalid data payload.']);
exit;
}
try {
$pdo->beginTransaction();
$stmtSession = $pdo->prepare("INSERT INTO radio_test_sessions (date, time, shift, tester_id, tested_count, untested_count) VALUES (?, ?, ?, ?, ?, ?)");
$stmtSession->execute([
$data['date'],
$data['time'],
$data['shift'],
$_SESSION['user_id'],
$data['tested_count'],
$data['untested_count']
]);
$sessionId = $pdo->lastInsertId();
$stmtRecord = $pdo->prepare("INSERT INTO radio_test_records (session_id, station_id, station_name, tx_level, rx_level, channel_type, note) VALUES (?, ?, ?, ?, ?, ?, ?)");
foreach ($data['items'] as $item) {
$stmtRecord->execute([
$sessionId,
$item['station_id'],
$item['station_name'],
$item['tx_level'],
$item['rx_level'],
$item['channel_type'],
$item['note'] ?? ''
]);
}
$pdo->commit();
echo json_encode(['success' => true, 'message' => 'บันทึกผลทดสอบวิทยุ ว.16 สำเร็จเรียบร้อยแล้ว!', 'session_id' => $sessionId]);
} catch (PDOException $e) {
$pdo->rollBack();
echo json_encode(['success' => false, 'message' => 'Database error: ' . $e->getMessage()]);
}
@@ -0,0 +1,303 @@
<?php
require_once 'includes/db.php';
require_once 'includes/auth.php';
requireLogin();
// Fetch users for the handover dropdown
$stmt = $pdo->prepare("SELECT id, username, full_name as name, role FROM users WHERE is_active = 1 ORDER BY full_name ASC");
$stmt->execute();
$dispatchers = $stmt->fetchAll(PDO::FETCH_ASSOC);
require_once 'includes/header.php';
?>
<div class="space-y-6 animate-fadeIn pb-10">
<!-- Top Date/Shift Selector -->
<div class="bg-white rounded-2xl p-4 md:p-5 shadow-sm border border-slate-100 flex flex-wrap gap-4 items-center">
<div class="flex items-center gap-2">
<span class="text-xs font-bold text-slate-500">วันที่คัดรายงาน:</span>
<input type="date" value="2026-07-23" class="py-1.5 px-3 border border-slate-200 rounded-xl text-xs font-bold text-slate-700 outline-none">
</div>
<div class="flex items-center gap-2">
<span class="text-xs font-bold text-slate-500">เลือกเวรรอบ:</span>
<select class="py-1.5 px-3 border border-slate-200 rounded-xl text-xs font-bold text-slate-700 bg-white outline-none cursor-pointer">
<option value="เช้า">☀️ เวรเช้า (08:00 - 16:00 น.)</option>
<option value="บ่าย">⛅ เวรบ่าย (16:00 - 00:00 น.)</option>
<option value="ดึก">🌙 เวรดึก (00:00 - 08:00 น.)</option>
</select>
</div>
</div>
<!-- Summary Textareas Container -->
<div class="bg-white rounded-2xl p-5 md:p-6 shadow-sm border border-slate-100 space-y-4">
<div class="border-b border-slate-100 pb-2">
<h3 class="text-base font-black text-slate-800">ระบุบทบันทึกสรุปและเรื่องค้างส่งมอบ</h3>
<p class="text-xs text-slate-500 mt-1">ป้อนข้อมูลข้อขัดข้องหรือความเสี่ยงที่พบในรอบเวร เพื่อนำไปลงบันทึกในเอกสารรายงานประจำวันอัตโนมัติ</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">สรุปเหตุการณ์สำคัญประจำเวร (Narrative)</label>
<textarea rows="3" placeholder="เช่น การประสานรับเคสอุบัติเหตุหมู่ สัญญาณสายแทงเข้าปกติ ไม่มีข้อติดขัดเรื่องรถ ALS..." class="w-full px-3 py-2 border border-slate-200 rounded-xl text-xs font-medium outline-none focus:ring-1 focus:ring-indigo-500"></textarea>
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">ความเสี่ยงหรือปัญหาที่สืบค้นพบ</label>
<textarea rows="3" placeholder="เช่น พบปัญหาคลื่นสัญญาณวิทยุจุดบ่อผุดรับส่งเบาบาง, ฝนตกจุดเกาะพะงันคลื่นแรงสปีดโบ๊ทยกยาก..." class="w-full px-3 py-2 border border-slate-200 rounded-xl text-xs font-medium outline-none focus:ring-1 focus:ring-indigo-500"></textarea>
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">เคสสำคัญที่ต้องสืบสวนและติดตามต่อ</label>
<textarea rows="3" placeholder="เช่น เคสประสานเฮลิคอปเตอร์กู้ชีพเกาะเต่า OB-2569-0012 รอสรุปผลประเมินอาการส่งต่อ ER สุราษฎร์ธานี..." class="w-full px-3 py-2 border border-slate-200 rounded-xl text-xs font-medium outline-none focus:ring-1 focus:ring-indigo-500"></textarea>
</div>
</div>
</div>
<!-- Handover & Security Panel -->
<div class="bg-gradient-to-br from-slate-900 via-slate-800 to-slate-950 text-white rounded-2xl p-5 md:p-6 shadow-xl border border-slate-700/60 flex flex-col lg:flex-row gap-6 justify-between items-start">
<div class="flex-1 space-y-2">
<div class="flex items-center gap-2 text-blue-400">
<i data-lucide="lock" class="w-5 h-5"></i>
<h3 class="font-black text-sm uppercase tracking-wider">ระบบรับ-ส่งเวรและรักษาความปลอดภัย</h3>
</div>
<p class="text-xs text-slate-300 leading-relaxed font-semibold">เจ้าหน้าที่เปลี่ยนเวร (ผู้รับเวร) ต้องยืนยันตนด้วยชื่อและรหัสผ่าน / PIN 4 หลักของตนเอง เพื่อลงลายเซ็นดิจิตอลรับมอบภาระงาน ยอดสรุปสถิติ เคสปฏิบัติการที่ค้าง และความพร้อมของขบวนรถพยาบาล</p>
<div class="grid grid-cols-2 gap-4 pt-2">
<div class="bg-slate-800/40 border border-slate-700/40 p-3 rounded-xl">
<span class="text-[10px] text-slate-400 block font-bold uppercase">ผู้ส่งมอบเวร</span>
<span class="text-xs font-bold text-slate-100">นพ.เกียรติภูมิ ภูมิใจไทย (ผู้อำนวยการศูนย์)</span>
</div>
<div class="bg-slate-800/40 border border-slate-700/40 p-3 rounded-xl">
<span class="text-[10px] text-slate-400 block font-bold uppercase">ผู้เซ็นรับมอบเวร</span>
<span class="text-xs font-bold text-amber-400 animate-pulse">⏳ รอรับมอบเวร</span>
</div>
</div>
</div>
<form class="w-full lg:w-80 bg-slate-800 p-4 rounded-xl border border-slate-700 space-y-3.5">
<h4 class="text-xs font-bold text-slate-200 uppercase tracking-widest border-b border-slate-700 pb-1">ลงชื่อรับเวรดิจิตอล</h4>
<div>
<label class="block text-[10px] text-slate-300 font-bold mb-1">เลือกเจ้าหน้าที่รับเวร</label>
<select class="w-full py-1.5 px-2 bg-slate-900 border border-slate-700 rounded-lg text-xs font-semibold text-slate-200 outline-none">
<option value="">-- เลือก Dispatcher รับเวร --</option>
<?php foreach ($dispatchers as $dispatcher): ?>
<?php if ($dispatcher['id'] !== $_SESSION['user_id']): ?>
<option value="<?php echo htmlspecialchars($dispatcher['id']); ?>">
<?php echo htmlspecialchars($dispatcher['name']); ?>
</option>
<?php endif; ?>
<?php endforeach; ?>
</select>
</div>
<div>
<label class="block text-[10px] text-slate-300 font-bold mb-1">ป้อน PIN 4 หลัก ยืนยันรหัส</label>
<input type="password" maxLength="4" placeholder="••••" class="w-full py-1.5 px-2 bg-slate-900 border border-slate-700 rounded-lg text-xs font-mono text-center tracking-widest text-slate-200 outline-none">
</div>
<button type="button" class="w-full py-2 bg-blue-600 hover:bg-blue-700 text-xs font-bold text-white rounded-lg transition-all active:scale-95 cursor-pointer flex items-center justify-center gap-1.5">
<i data-lucide="lock" class="w-3.5 h-3.5"></i> ยืนยันการเซ็นรับมอบเวร
</button>
</form>
</div>
<!-- Export Actions -->
<div class="flex flex-wrap gap-2 justify-end print:hidden">
<button class="flex items-center gap-1.5 bg-slate-100 hover:bg-slate-200 text-slate-700 font-bold text-xs px-4 py-2 rounded-xl transition-all border border-slate-200 cursor-pointer">
<i data-lucide="copy" class="w-4 h-4"></i> คัดลอกสรุปเป็นข้อความเวร
</button>
<button class="flex items-center gap-1.5 bg-blue-600 hover:bg-blue-700 text-white font-bold text-xs px-4 py-2 rounded-xl transition-all shadow-md shadow-blue-200 cursor-pointer">
<i data-lucide="printer" class="w-4 h-4"></i> พิมพ์หรือเซฟรายงาน PDF
</button>
</div>
<!-- A4 Document Preview Area -->
<div class="bg-white rounded-3xl p-6 md:p-10 shadow-lg border border-slate-100 max-w-4xl mx-auto space-y-8 print:border-none print:shadow-none print:p-0" id="print-area">
<!-- Document Header -->
<div class="border-b-4 border-blue-900 pb-5 flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
<div class="flex items-center gap-3">
<div class="p-3 bg-blue-900 rounded-2xl text-white flex items-center justify-center">
<i data-lucide="shield" class="w-8 h-8"></i>
</div>
<div>
<h2 class="text-xl md:text-2xl font-black text-slate-900 tracking-tight">รายงานสรุปผลการปฏิบัติการประจำเวร</h2>
<p class="text-xs font-bold text-slate-500 uppercase tracking-widest mt-0.5">ศูนย์รับแจ้งเหตุและสั่งการนเรนทรอ่าวไทย (เบอร์โทรฉุกเฉิน 1669)</p>
</div>
</div>
<div class="text-right sm:text-right self-stretch sm:self-auto bg-slate-50 border border-slate-100 p-3 rounded-xl font-mono text-xs">
<div class="font-bold text-slate-800">เวรปฏิบัติงาน: <span class="text-blue-700 font-sans font-black">เช้า</span></div>
<div class="mt-1">วันที่รายงาน: 2026-07-23</div>
<div class="text-[10px] text-slate-400 font-sans mt-1">Generated: 23 กรกฎาคม 2569 เวลา 13:35</div>
</div>
</div>
<!-- Section 1: Call Stats -->
<div class="space-y-3">
<h3 class="text-sm font-black text-blue-900 uppercase tracking-widest border-b border-slate-100 pb-1 flex items-center gap-2">
<i data-lucide="phone" class="w-4 h-4"></i> 1. สรุปข้อมูลสายเรียกเข้าประจำเวร
</h3>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="bg-slate-50 p-3 rounded-xl border border-slate-100 text-center">
<div class="text-xs text-slate-400 font-bold">สายเรียกเข้าทั้งหมด</div>
<div class="text-xl font-black text-slate-800 mt-1">0 สาย</div>
</div>
<div class="bg-blue-50/50 p-3 rounded-xl border border-blue-100 text-center">
<div class="text-xs text-blue-800 font-bold">สายปฏิบัติการ</div>
<div class="text-xl font-black text-blue-900 mt-1">0 สาย</div>
</div>
<div class="bg-amber-50/40 p-3 rounded-xl border border-amber-100/70 text-center">
<div class="text-xs text-amber-700 font-bold">สายก่อกวน</div>
<div class="text-xl font-black text-amber-800 mt-1">0 สาย</div>
</div>
<div class="bg-slate-50 p-3 rounded-xl border border-slate-100 text-center">
<div class="text-xs text-slate-400 font-bold">สายโทรผิด/สายอื่น ๆ</div>
<div class="text-xl font-black text-slate-800 mt-1">0 สาย</div>
</div>
</div>
</div>
<!-- Section 2: Case Stats -->
<div class="space-y-3">
<h3 class="text-sm font-black text-blue-900 uppercase tracking-widest border-b border-slate-100 pb-1 flex items-center gap-2">
<i data-lucide="file-text" class="w-4 h-4"></i> 2. สรุปเคสปฏิบัติการและการออกปฏิบัติการประจำเวร
</h3>
<div class="grid grid-cols-2 md:grid-cols-5 gap-4">
<div class="bg-slate-50 p-3 rounded-xl border border-slate-100 text-center">
<div class="text-[10px] text-slate-400 font-bold">เคสรวม</div>
<div class="text-lg font-bold text-slate-800 mt-1">0 เคส</div>
</div>
<div class="bg-slate-50 p-3 rounded-xl border border-slate-100 text-center">
<div class="text-[10px] text-slate-400 font-bold">เคส EMS</div>
<div class="text-lg font-bold text-slate-800 mt-1">0 เคส</div>
</div>
<div class="bg-slate-50 p-3 rounded-xl border border-slate-100 text-center">
<div class="text-[10px] text-slate-400 font-bold">เคส REFER</div>
<div class="text-lg font-bold text-slate-800 mt-1">0 เคส</div>
</div>
<div class="bg-slate-50 p-3 rounded-xl border border-slate-100 text-center">
<div class="text-[10px] text-slate-400 font-bold">ระดับ ALS (แพทย์กู้ชีพ)</div>
<div class="text-lg font-bold text-slate-800 mt-1">0 หน่วย</div>
</div>
<div class="bg-slate-50 p-3 rounded-xl border border-slate-100 text-center col-span-2 md:col-span-1">
<div class="text-[10px] text-slate-400 font-bold font-sans">ระดับ BLS/CLS (กู้ชีพมูลนิธิ)</div>
<div class="text-lg font-bold text-slate-800 mt-1">0 หน่วย</div>
</div>
</div>
</div>
<!-- Section 3: Triage Summary -->
<div class="space-y-3">
<h3 class="text-sm font-black text-blue-900 uppercase tracking-widest border-b border-slate-100 pb-1 flex items-center gap-2">
<i data-lucide="file-text" class="w-4 h-4"></i> 3. สรุปความเร่งด่วนและจำแนกคัดกรองอาการ (Triage Summary)
</h3>
<div class="overflow-x-auto">
<table class="w-full text-left text-xs border border-slate-100 rounded-xl overflow-hidden">
<thead>
<tr class="bg-slate-50 text-slate-600 font-bold border-b border-slate-100">
<th class="p-2.5">ระดับความรุนแรง / สัญญาณชีพ</th>
<th class="p-2.5 text-center">ประเมินทางสายโทรศัพท์ (Phone Triage)</th>
<th class="p-2.5 text-center">ประเมิน ณ จุดเกิดเหตุ (Scene Triage)</th>
<th class="p-2.5 text-center">ประเมิน ณ ห้องฉุกเฉิน (ER Triage)</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100 text-slate-700 font-semibold text-center">
<tr>
<td class="p-2.5 text-left text-red-600 font-extrabold flex items-center gap-1.5">🔴 สีแดง (วิกฤต/ฉุกเฉินคุกคามชีพ)</td>
<td class="p-2.5">0</td>
<td class="p-2.5">0</td>
<td class="p-2.5">0</td>
</tr>
<tr>
<td class="p-2.5 text-left text-amber-600 font-extrabold flex items-center gap-1.5">🟡 สีเหลือง (เร่งด่วน/กึ่งวิกฤต)</td>
<td class="p-2.5">0</td>
<td class="p-2.5">0</td>
<td class="p-2.5">0</td>
</tr>
<tr>
<td class="p-2.5 text-left text-emerald-600 font-extrabold flex items-center gap-1.5">🟢 สีเขียว (ไม่รุนแรง/ทั่วไป)</td>
<td class="p-2.5">0</td>
<td class="p-2.5">0</td>
<td class="p-2.5">0</td>
</tr>
<tr>
<td class="p-2.5 text-left text-slate-500 font-extrabold flex items-center gap-1.5">⚪ สีขาว (ผู้ป่วยนัด/ประสานงานย้อนหลัง)</td>
<td class="p-2.5">0</td>
<td class="p-2.5">0</td>
<td class="p-2.5">0</td>
</tr>
</tbody>
</table>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 pt-2">
<div class="space-y-3">
<h4 class="text-xs font-black text-blue-900 uppercase tracking-widest border-b border-slate-100 pb-1">เคสเร่งด่วนรหัสเฉพาะ (Fast Track)</h4>
<div class="space-y-2 text-xs font-semibold text-slate-600">
<div class="flex justify-between py-1.5 border-b border-slate-50">
<span>🧠 STROKE (หลอดเลือดสมองเฉลี่ย):</span>
<span class="font-bold text-slate-800">0 ราย</span>
</div>
<div class="flex justify-between py-1.5 border-b border-slate-50">
<span>❤️ STEMI (โรคหัวใจเฉียบพลัน):</span>
<span class="font-bold text-slate-800">0 ราย</span>
</div>
<div class="flex justify-between py-1.5 border-b border-slate-50">
<span>🦠 Sepsis (ติดเชื้อในกระแสโลหิต):</span>
<span class="font-bold text-slate-800">0 ราย</span>
</div>
<div class="flex justify-between py-1.5 border-b border-slate-50">
<span>🚗 Multiple Trauma (อุบัติเหตุพหุบาดเจ็บรุนแรง):</span>
<span class="font-bold text-slate-800">0 ราย</span>
</div>
</div>
</div>
<div class="space-y-3">
<h4 class="text-xs font-black text-blue-900 uppercase tracking-widest border-b border-slate-100 pb-1">ผลการทดสอบวิทยุ ว.16 และสถานี</h4>
<div class="space-y-2 text-xs font-semibold text-slate-600 bg-slate-50 p-3 rounded-xl border border-slate-100">
<div class="flex justify-between py-1 border-b border-slate-100">
<span>ผู้ทดสอบ ว.16:</span>
<span class="font-bold text-slate-800">นายสมเกียรติ มุ่งมั่น</span>
</div>
<div class="flex justify-between py-1 border-b border-slate-100">
<span>สถานีเข้าร่วมตรวจสำเร็จ:</span>
<span class="font-bold text-emerald-600">16 สถานี</span>
</div>
<div class="flex justify-between py-1 border-b border-slate-100">
<span>สถานีที่ไม่เข้าร่วม/ติดต่อไม่ได้:</span>
<span class="font-bold text-rose-600">1 สถานี</span>
</div>
<div class="text-[10px] text-rose-500 leading-normal font-bold">
รายชื่อสถานีที่ขาดการติดต่อ: โรงพยาบาลไทยอินเตอร์เกาะพะงัน
</div>
</div>
</div>
</div>
</div>
<!-- Section 4: Narrative Summary -->
<div class="space-y-4 pt-2">
<h3 class="text-sm font-black text-blue-900 uppercase tracking-widest border-b border-slate-100 pb-1">4. สรุปเหตุการณ์สำคัญและความเสี่ยงที่ตรวจพบ</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 text-xs font-semibold">
<div class="bg-slate-50 p-4 rounded-xl border border-slate-100 space-y-1.5">
<span class="font-bold text-slate-800 block">สรุปเหตุการณ์และข้อขัดข้องสำคัญในรอบเวร:</span>
<p class="text-slate-500 leading-relaxed font-medium min-h-[40px]">ไม่มีรายงานเหตุการณ์สำคัญเป็นพิเศษ</p>
</div>
<div class="bg-slate-50 p-4 rounded-xl border border-slate-100 space-y-1.5">
<span class="font-bold text-slate-800 block">ความเสี่ยงหรือความขัดแย้งที่ต้องปรับปรุงระบบ:</span>
<p class="text-slate-500 leading-relaxed font-medium min-h-[40px]">ไม่พบปัญหาความเสี่ยงพิเศษจากการรับแจ้งเหตุหรือการประสานขบวนรถ</p>
</div>
</div>
</div>
<!-- Signatures -->
<div class="border-t border-slate-100 pt-6 flex flex-col sm:flex-row justify-between items-start sm:items-center gap-6 mt-8">
<div class="text-xs space-y-1">
<div class="font-bold text-slate-800">ผู้ส่งมอบเวร: <span class="text-slate-500 underline font-semibold">นพ.เกียรติภูมิ ภูมิใจไทย (ผู้อำนวยการศูนย์)</span></div>
<div class="text-[10px] text-slate-400">ลงชื่อเข้ารหัสดิจิตอลเรียบร้อยแล้ว</div>
</div>
<div class="text-xs space-y-1 sm:text-right">
<div class="font-bold text-slate-800">ผู้รับมอบเวร: <span class="text-blue-700 underline font-black">⏳ รอลงชื่อรับเวรดิจิตอล</span></div>
<div class="text-[10px] text-slate-400">กรุณาเซ็นชื่อเข้าระบบด้วย PIN ก่อนพิมพ์รายงาน</div>
</div>
</div>
</div>
</div>
<?php require_once 'includes/footer.php'; ?>
@@ -0,0 +1,244 @@
<?php
require_once 'includes/db.php';
require_once 'includes/auth.php';
requireLogin();
// Handle Create
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'create_incident') {
$call_type = $_POST['call_type'];
$channel = $_POST['channel'];
$case_number = trim($_POST['case_number']);
$ems_refer = $_POST['ems_refer'];
$unit_level = $_POST['unit_level'];
$assigned_unit_id = $_POST['assigned_unit_id'] ?: null;
$symptom_group = $_POST['symptom_group'];
$phone_triage = $_POST['phone_triage'];
$fast_track = $_POST['fast_track'];
$transport_route = $_POST['transport_route'];
$completed_by = $_POST['completed_by'];
$diagnosis = $_POST['diagnosis'];
$stmt = $pdo->prepare("INSERT INTO incidents (case_number, call_type, channel, ems_refer, unit_level, assigned_unit_id, symptom_group, phone_triage, fast_track, transport_route, completed_by, diagnosis, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([$case_number, $call_type, $channel, $ems_refer, $unit_level, $assigned_unit_id, $symptom_group, $phone_triage, $fast_track, $transport_route, $completed_by, $diagnosis, $_SESSION['user_id']]);
$_SESSION['flash'] = ['type' => 'success', 'title' => 'บันทึกสำเร็จ', 'message' => 'บันทึกการรับสายแจ้งเหตุเรียบร้อยแล้ว'];
header("Location: dashboard.php");
exit;
}
// Fetch Incidents History
$stmt = $pdo->query("
SELECT i.*, creator.full_name as creator_name
FROM incidents i
LEFT JOIN users creator ON i.created_by = creator.id
ORDER BY i.created_at DESC LIMIT 10
");
$incidents = $stmt->fetchAll();
// Fetch Units
$stmt = $pdo->query("SELECT id, name FROM units WHERE is_active = 1 ORDER BY name ASC");
$units = $stmt->fetchAll();
// Fetch Master Data
$md = [
'call_type' => [], 'call_channel' => [], 'ems_refer' => [],
'unit_level' => [], 'cbd_symptom' => [], 'phone_triage' => [],
'fast_track' => [], 'transport_route' => []
];
try {
$stmt = $pdo->query("SELECT category, item_value, item_label FROM master_data WHERE is_active = 1 ORDER BY category ASC, sort_order ASC, id ASC");
if ($stmt) {
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
$md[$row['category']][] = $row;
}
}
} catch (PDOException $e) {}
require_once 'includes/header.php';
?>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 h-full">
<!-- Left Column: Form -->
<div class="bg-white rounded-2xl p-5 md:p-6 shadow-sm border border-slate-100 flex flex-col h-full overflow-y-auto">
<div class="mb-4">
<h2 class="text-base font-black text-slate-800 flex items-center gap-2">
<i data-lucide="phone-call" class="w-5 h-5 text-indigo-600"></i> บันทึกการรับสายโทรศัพท์ (รับแจ้งเหตุแรกรับ)
</h2>
<p class="text-xs text-slate-400 mt-0.5">คีย์ข้อมูลผู้เจ็บป่วยฉุกเฉินอย่างรวดเร็ว โดยไม่จำเป็นต้องกรอกครบทุกช่องก็สามารถบันทึกได้</p>
</div>
<form method="POST" action="dashboard.php" class="space-y-4 flex-1">
<input type="hidden" name="action" value="create_incident">
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">ประเภทสายเรียกเข้า</label>
<div class="relative">
<select name="call_type" class="w-full py-2 px-3 pl-8 border border-slate-200 rounded-lg text-sm font-bold text-slate-700 outline-none focus:ring-1 focus:ring-indigo-500 bg-white appearance-none">
<?php foreach($md['call_type'] as $c): ?>
<option value="<?php echo htmlspecialchars($c['item_value']); ?>"><?php echo htmlspecialchars($c['item_label']); ?></option>
<?php endforeach; ?>
</select>
<i data-lucide="phone" class="w-4 h-4 absolute left-3 top-2.5 text-slate-400"></i>
</div>
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">ช่องทางการแจ้งเหตุ</label>
<select name="channel" class="w-full py-2 px-3 border border-slate-200 rounded-lg text-sm font-bold text-slate-700 outline-none focus:ring-1 focus:ring-indigo-500 bg-white">
<?php foreach($md['call_channel'] as $c): ?>
<option value="<?php echo htmlspecialchars($c['item_value']); ?>"><?php echo htmlspecialchars($c['item_label']); ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="pt-2">
<h3 class="text-sm font-black text-indigo-600 flex items-center gap-1.5 mb-3">
<i data-lucide="truck" class="w-4 h-4"></i> รายละเอียดปฏิบัติการกู้ชีพ (EMS / REFER)
</h3>
<div class="grid grid-cols-2 gap-4 mb-4">
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">เลขปฏิบัติการ (สพฉ.)</label>
<input type="text" name="case_number" placeholder="เช่น 08-2569-1234 (ปล่อยว่างหากยังไม่มี)" class="w-full py-2 px-3 border border-slate-200 rounded-lg text-sm font-bold text-slate-700 outline-none focus:ring-1 focus:ring-indigo-500 bg-white">
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">ประเภทปฏิบัติการ</label>
<div class="flex rounded-lg overflow-hidden border border-slate-200 bg-slate-100 p-0.5">
<?php $i=0; foreach($md['ems_refer'] as $c): ?>
<label class="flex-1 cursor-pointer">
<input type="radio" name="ems_refer" value="<?php echo htmlspecialchars($c['item_value']); ?>" class="peer hidden" <?php echo $i===0?'checked':''; ?>>
<div class="text-center py-1.5 text-[10px] font-bold text-slate-500 peer-checked:bg-indigo-600 peer-checked:text-white rounded-md transition-all"><?php echo htmlspecialchars($c['item_label']); ?></div>
</label>
<?php $i++; endforeach; ?>
</div>
</div>
</div>
<div class="grid grid-cols-2 gap-4 mb-4">
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">ระดับหน่วยกู้ชีพ</label>
<div class="flex rounded-lg overflow-hidden border border-slate-200 bg-slate-100 p-0.5">
<?php $i=0; foreach($md['unit_level'] as $c): ?>
<label class="flex-1 cursor-pointer">
<input type="radio" name="unit_level" value="<?php echo htmlspecialchars($c['item_value']); ?>" class="peer hidden" <?php echo $i===0?'checked':''; ?>>
<div class="text-center py-1.5 text-xs font-bold text-slate-500 peer-checked:bg-indigo-600 peer-checked:text-white rounded-md transition-all"><?php echo htmlspecialchars($c['item_label']); ?></div>
</label>
<?php $i++; endforeach; ?>
</div>
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">หน่วยปฏิบัติการรับมอบ (เฉพาะระดับ ALS)</label>
<select name="assigned_unit_id" class="w-full py-2 px-3 border border-slate-200 rounded-lg text-sm font-bold text-slate-700 outline-none focus:ring-1 focus:ring-indigo-500 bg-white">
<?php foreach($units as $unit): ?>
<option value="<?php echo $unit['id']; ?>" <?php echo $unit['name'] === 'โรงพยาบาลเกาะสมุย' ? 'selected' : ''; ?>><?php echo htmlspecialchars($unit['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="mb-4">
<label class="block text-xs font-bold text-slate-500 mb-1">จำแนกกลุ่มอาการ (25 กลุ่มอาการ สพฉ.)</label>
<select name="symptom_group" class="w-full py-2 px-3 border border-slate-200 rounded-lg text-sm font-bold text-slate-700 outline-none focus:ring-1 focus:ring-indigo-500 bg-white">
<?php foreach($md['cbd_symptom'] as $c): ?>
<option value="<?php echo htmlspecialchars($c['item_value']); ?>"><?php echo htmlspecialchars($c['item_label']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="grid grid-cols-2 gap-4 mb-4">
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">Phone Triage (ระดับวิกฤตสายแรกรับ)</label>
<select name="phone_triage" class="w-full py-2 px-3 border border-slate-200 rounded-lg text-sm font-bold text-slate-700 outline-none focus:ring-1 focus:ring-indigo-500 bg-white">
<?php foreach($md['phone_triage'] as $c): ?>
<option value="<?php echo htmlspecialchars($c['item_value']); ?>"><?php echo htmlspecialchars($c['item_label']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">รหัสเฉพาะผู้ป่วยวิกฤต (Fast Track)</label>
<select name="fast_track" class="w-full py-2 px-3 border border-slate-200 rounded-lg text-sm font-bold text-slate-700 outline-none focus:ring-1 focus:ring-indigo-500 bg-white">
<?php foreach($md['fast_track'] as $c): ?>
<option value="<?php echo htmlspecialchars($c['item_value']); ?>"><?php echo htmlspecialchars($c['item_label']); ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="grid grid-cols-2 gap-4 mb-4">
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">เส้นทางลำเลียงผู้ป่วย</label>
<select name="transport_route" class="w-full py-2 px-3 border border-slate-200 rounded-lg text-sm font-bold text-slate-700 outline-none focus:ring-1 focus:ring-indigo-500 bg-white">
<?php foreach($md['transport_route'] as $c): ?>
<option value="<?php echo htmlspecialchars($c['item_value']); ?>"><?php echo htmlspecialchars($c['item_label']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">ผู้รับผิดชอบกรอกข้อมูล (Complete ข้อมูล)</label>
<select name="completed_by" class="w-full py-2 px-3 border border-slate-200 rounded-lg text-sm font-bold text-slate-700 outline-none focus:ring-1 focus:ring-indigo-500 bg-white">
<option value="นพ.เกียรติภูมิ ภูมิใจไทย (ผู้อำนวยการศูนย์)">นพ.เกียรติภูมิ ภูมิใจไทย (ผู้อำนวยการศูนย์)</option>
<option value="<?php echo htmlspecialchars($_SESSION['name']); ?>"><?php echo htmlspecialchars($_SESSION['name']); ?></option>
</select>
</div>
</div>
<div class="mb-4">
<label class="block text-xs font-bold text-slate-500 mb-1">อาการแรกรับ / ผลวินิจฉัย (Diagnosis)</label>
<textarea name="diagnosis" rows="3" placeholder="กรอกเหตุการณ์เบื้องต้น เช่น ผู้ป่วยเพศชายอายุ 45 ปี ประสบอุบัติเหตุล้มหัวฟาดพื้น รู้สึกตัวดีปวดต้นคอ..." class="w-full py-2 px-3 border border-slate-200 rounded-lg text-sm outline-none focus:ring-1 focus:ring-indigo-500 bg-white resize-none text-slate-700"></textarea>
</div>
</div>
<div class="pt-2">
<button type="submit" class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-3 px-4 rounded-xl shadow-sm transition-all text-sm flex items-center justify-center gap-2">
<i data-lucide="save" class="w-4 h-4"></i> บันทึกและสรุปข้อมูลแรกรับ
</button>
</div>
</form>
</div>
<!-- Right Column: History -->
<div class="bg-white rounded-2xl p-5 md:p-6 shadow-sm border border-slate-100 flex flex-col h-full">
<div class="flex justify-between items-center mb-6">
<h2 class="text-base font-black text-slate-800">สายเรียกเข้าและรายงานล่าสุดในรอบเวร</h2>
<span class="bg-indigo-100 text-indigo-700 text-xs font-bold px-3 py-1 rounded-full"><?php echo count($incidents); ?> สายเรียกเข้า</span>
</div>
<p class="text-xs text-slate-400 mb-4 border-b border-slate-100 pb-3">แสดงรายการประวัติสายเรียกเข้าทั้งหมดที่คุณคีย์ล่าสุด</p>
<div class="flex-1 overflow-y-auto pr-2 space-y-4">
<?php foreach($incidents as $inc):
$dotColor = 'bg-rose-500';
if ($inc['call_type'] == 'สายก่อกวน') $dotColor = 'bg-amber-500';
elseif ($inc['call_type'] == 'โทรผิด') $dotColor = 'bg-slate-400';
elseif ($inc['call_type'] == 'แจ้งเหตุอื่น') $dotColor = 'bg-blue-500';
?>
<div class="flex items-start justify-between group">
<div class="flex items-start gap-3">
<div class="w-2 h-2 rounded-full mt-1.5 <?php echo $dotColor; ?>"></div>
<div>
<p class="text-sm font-bold text-slate-700">
<?php echo htmlspecialchars($inc['call_type']); ?>
<span class="text-xs font-normal text-slate-400 ml-1">(<?php echo date('H:i', strtotime($inc['created_at'])); ?> น.)</span>
</p>
<p class="text-[10px] text-slate-500 font-bold mt-0.5">ช่องทาง: <?php echo htmlspecialchars($inc['channel']); ?></p>
<p class="text-[9px] text-slate-400 mt-0.5">บันทึกโดย: <?php echo htmlspecialchars($inc['creator_name']); ?> (Dispatcher)</p>
</div>
</div>
<button class="text-slate-300 hover:text-rose-500 transition-colors hidden group-hover:block">
<i data-lucide="trash-2" class="w-4 h-4"></i>
</button>
</div>
<?php endforeach; ?>
</div>
<div class="mt-4 bg-amber-50 border border-amber-100 rounded-lg p-3 flex gap-2 items-start">
<i data-lucide="info" class="w-4 h-4 text-amber-500 mt-0.5"></i>
<p class="text-[10px] text-slate-600">
<span class="font-bold">เคล็ดลับปฏิบัติการ:</span> ข้อมูลเคสจะถูกนำเข้าสู่ระบบบัญชี "หน้าเคสปฏิบัติการ" โดยอัตโนมัติ เพื่อให้ผู้รับผิดชอบ (Complete) และทีม ER ดำเนินการคัดแยกสี และปิดเคสอย่างละเอียด
</p>
</div>
</div>
</div>
<?php require_once 'includes/footer.php'; ?>
@@ -0,0 +1,177 @@
<?php
require_once 'includes/db.php';
require_once 'includes/auth.php';
requireLogin();
// 1. Fetch counts for the 4 summary cards
$currentShiftCalls = 0;
$activeCasesCount = 0;
$pendingCasesCount = 0;
$notReadyUnitsCount = 0;
try {
// Current Shift Calls (using today's date as a proxy for 'current shift')
$stmt = $pdo->query("SELECT COUNT(*) FROM incidents WHERE DATE(created_at) = CURDATE() AND channel = 'First Call'");
if ($stmt) $currentShiftCalls = $stmt->fetchColumn();
// Active cases (Not 'ปิดเคส' and not 'ค้างปรับปรุงข้อมูล')
$stmt = $pdo->query("SELECT COUNT(*) FROM incidents WHERE status != 'ปิดเคส' AND status != 'ค้างปรับปรุงข้อมูล'");
if ($stmt) $activeCasesCount = $stmt->fetchColumn();
// Pending cases ('ค้างปรับปรุงข้อมูล')
$stmt = $pdo->query("SELECT COUNT(*) FROM incidents WHERE status = 'ค้างปรับปรุงข้อมูล'");
if ($stmt) $pendingCasesCount = $stmt->fetchColumn();
// Units not ready
$stmt = $pdo->query("SELECT COUNT(*) FROM units WHERE status = 'not_ready'");
if ($stmt) $notReadyUnitsCount = $stmt->fetchColumn();
} catch (Exception $e) {}
// 2. Fetch Active Cases list (Left column)
$activeCases = [];
try {
// Since we don't have unit names directly in incidents in our mock, we will mock the unit name if empty, or join if unit table has it.
// Our mock data didn't have unit names in `incidents`, so we'll just show it using assigned_unit_id or a fallback.
$query = "
SELECT
i.id, i.case_number, i.call_type, i.status, i.diagnosis, i.created_at,
u.name as unit_name
FROM incidents i
LEFT JOIN units u ON i.assigned_unit_id = u.id
WHERE i.status != 'ปิดเคส'
ORDER BY i.created_at DESC
";
$stmt = $pdo->query($query);
if ($stmt) $activeCases = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Exception $e) {}
// 3. Fetch Pending Cases Details (Right column)
$pendingCases = [];
try {
// Join with users to get the name of the dispatcher who created it, since we don't have a 'responsible_dispatcher' column explicitly in our mock. We'll use created_by or completed_by.
$query = "
SELECT
i.case_number, i.created_at, i.status,
u.name as responsible_name
FROM incidents i
LEFT JOIN users u ON i.created_by = u.id
WHERE i.status = 'ค้างปรับปรุงข้อมูล'
ORDER BY i.created_at ASC
";
$stmt = $pdo->query($query);
if ($stmt) $pendingCases = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Exception $e) {}
// Function to calculate time diff
function getPendingTime($datetime) {
$now = new DateTime();
$past = new DateTime($datetime);
$diff = $now->diff($past);
$parts = [];
if ($diff->d > 0) $parts[] = $diff->d . ' วัน';
if ($diff->h > 0) $parts[] = $diff->h . ' ชม.';
if ($diff->i > 0) $parts[] = $diff->i . ' นาที';
return empty($parts) ? 'เพิ่งเกิดขึ้น' : implode(' ', $parts);
}
?>
<?php require_once 'includes/header.php'; ?>
<div class="space-y-6 animate-fadeIn pb-10">
<!-- 4 Summary Cards -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="bg-indigo-600 p-4 rounded-2xl shadow-sm text-white">
<div class="text-xs font-bold opacity-80">สายแรกรับเวรปัจจุบัน</div>
<div class="text-2xl font-black mt-1"><?php echo $currentShiftCalls; ?> <span class="text-sm font-bold opacity-80">สาย</span></div>
</div>
<div class="bg-white p-4 rounded-2xl shadow-sm border border-slate-100">
<div class="text-xs text-slate-400 font-bold">เคสผู้ป่วยที่กำลังออก ว.4</div>
<div class="text-2xl font-black text-slate-800 mt-1"><?php echo $activeCasesCount; ?> <span class="text-sm font-bold text-slate-500">เคส</span></div>
</div>
<div class="bg-white p-4 rounded-2xl shadow-sm border border-slate-100">
<div class="text-xs text-slate-400 font-bold">เคสตกค้างข้อมูล</div>
<div class="text-2xl font-black text-rose-600 mt-1"><?php echo $pendingCasesCount; ?> <span class="text-sm font-bold text-rose-500">เคสค้าง</span></div>
</div>
<div class="bg-white p-4 rounded-2xl shadow-sm border border-slate-100">
<div class="text-xs text-slate-400 font-bold">หน่วยในข่ายไม่พร้อมทำงาน</div>
<div class="text-2xl font-black text-orange-500 mt-1"><?php echo $notReadyUnitsCount; ?> <span class="text-sm font-bold text-orange-400">สถานี</span></div>
</div>
</div>
<!-- 2 Column Layout -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Left Panel: Active Cases -->
<div class="lg:col-span-2 bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden">
<div class="p-4 md:p-5 border-b border-slate-100 bg-slate-50/50 flex items-center justify-between">
<h3 class="text-sm font-bold text-slate-800">ขบวนกู้ชีพกำลังออกปฏิบัติงานหลัก</h3>
<span class="bg-indigo-100 text-indigo-700 text-[10px] font-bold px-2 py-0.5 rounded-full">Realtime</span>
</div>
<div class="p-4 md:p-5 space-y-3">
<?php if (empty($activeCases)): ?>
<div class="text-center py-6 text-slate-400 text-sm font-semibold">ไม่มีเคสกำลังดำเนินการ</div>
<?php else: ?>
<?php foreach ($activeCases as $case):
$badgeClass = 'bg-amber-100 text-amber-700'; // Default yellow
if ($case['status'] === 'รอรับเรื่อง') $badgeClass = 'bg-slate-100 text-slate-600';
if ($case['status'] === 'กำลังดำเนินการ') $badgeClass = 'bg-blue-100 text-blue-700';
?>
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3 p-3.5 border border-slate-100 rounded-xl hover:bg-slate-50 transition-colors">
<div>
<div class="text-sm font-bold text-slate-800">
<?php echo htmlspecialchars($case['case_number']); ?>
<?php if (!empty($case['call_type'])): ?>
<span class="text-slate-500 font-semibold">(<?php echo htmlspecialchars($case['call_type']); ?>)</span>
<?php endif; ?>
</div>
<div class="text-xs text-slate-500 mt-1 truncate max-w-xl">
หน่วย: <?php echo htmlspecialchars($case['unit_name'] ?? 'ไม่ระบุหน่วย'); ?> | อาการ: <?php echo htmlspecialchars($case['diagnosis'] ?? 'ไม่ระบุอาการ'); ?>
</div>
</div>
<div class="shrink-0">
<span class="<?php echo $badgeClass; ?> text-[10px] font-bold px-2 py-1 rounded">
<?php echo htmlspecialchars($case['status']); ?>
</span>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
<!-- Right Panel: Pending Cases -->
<div class="lg:col-span-1 bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden">
<div class="p-4 md:p-5 border-b border-slate-100 bg-slate-50/50">
<h3 class="text-sm font-bold text-slate-800">เคสตกค้างการกรอกข้อมูล (ค้างกับใคร)</h3>
</div>
<div class="p-4 md:p-5 space-y-3">
<?php if (empty($pendingCases)): ?>
<div class="text-center py-6 text-slate-400 text-sm font-semibold">ไม่มีเคสตกค้าง</div>
<?php else: ?>
<?php foreach ($pendingCases as $pCase): ?>
<div class="flex items-center justify-between gap-3 p-3 border border-rose-200 bg-rose-50/40 rounded-xl">
<div>
<div class="text-sm font-bold text-slate-800">เลข: <?php echo htmlspecialchars($pCase['case_number']); ?></div>
<div class="text-xs text-slate-500 mt-0.5">ผู้รับผิดชอบหลัก: <?php echo htmlspecialchars($pCase['responsible_name'] ?? 'ไม่ระบุ'); ?></div>
</div>
<div class="text-xs font-bold text-rose-600 shrink-0">
ค้าง: <?php echo getPendingTime($pCase['created_at']); ?>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
</div>
</div>
<script>
lucide.createIcons();
</script>
<?php require_once 'includes/footer.php'; ?>
@@ -0,0 +1,94 @@
CREATE DATABASE IF NOT EXISTS narenthorn_samui CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE narenthorn_samui;
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password` varchar(255) NOT NULL,
`name` varchar(100) NOT NULL,
`role` enum('admin','user') NOT NULL DEFAULT 'user',
`status` enum('active','inactive') NOT NULL DEFAULT 'active',
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Password for admin is admin123456 (using password_hash in PHP, I will generate the hash 'admin123456' using BCRYPT)
-- BCRYPT of 'admin123456' is $2y$10$tZ9.zW.M3t5H.P/C8S3Ohe5M8Vw2F6p1DkR.754sTqL5qH1qCqX92
INSERT INTO `users` (`id`, `username`, `password`, `name`, `role`, `status`) VALUES
(1, 'admin', '$2y$10$tZ9.zW.M3t5H.P/C8S3Ohe5M8Vw2F6p1DkR.754sTqL5qH1qCqX92', 'Super Administrator', 'admin', 'active');
CREATE TABLE IF NOT EXISTS `units` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`type` varchar(50) NOT NULL,
`status` enum('ready','not_ready') NOT NULL DEFAULT 'ready',
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `units` (`name`, `type`, `status`) VALUES
('กู้ชีพตลิ่งงาม', 'กู้ชีพ', 'ready'),
('กู้ชีพละไม', 'กู้ชีพ', 'ready'),
('กู้ชีพหน้าเมือง', 'กู้ชีพ', 'ready'),
('กู้ภัยสมุยจุดศิลางู', 'กู้ภัย', 'ready'),
('กู้ภัยสมุยจุดสระเกศ', 'กู้ภัย', 'ready'),
('กู้ภัยสมุยจุดบ้านใต้', 'กู้ภัย', 'ready'),
('กู้ภัยสมุยจุดบ่อผุด', 'กู้ภัย', 'ready'),
('โรงพยาบาลเกาะสมุย', 'โรงพยาบาล', 'ready'),
('โรงพยาบาลเกาะพะงัน', 'โรงพยาบาล', 'ready'),
('โรงพยาบาลกรุงเทพสมุย', 'โรงพยาบาล', 'ready'),
('โรงพยาบาลไทยอินเตอร์', 'โรงพยาบาล', 'ready'),
('โรงพยาบาลวัฒนแพทย์สมุย', 'โรงพยาบาล', 'ready');
CREATE TABLE IF NOT EXISTS `incidents` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`case_number` varchar(50) DEFAULT NULL,
`call_type` varchar(100) DEFAULT NULL,
`channel` varchar(100) DEFAULT NULL,
`ems_refer` varchar(50) DEFAULT NULL,
`unit_level` varchar(50) DEFAULT NULL,
`assigned_unit_id` int(11) DEFAULT NULL,
`symptom_group` varchar(255) DEFAULT NULL,
`phone_triage` varchar(100) DEFAULT NULL,
`fast_track` varchar(100) DEFAULT NULL,
`transport_route` varchar(100) DEFAULT NULL,
`completed_by` varchar(100) DEFAULT NULL,
`diagnosis` text,
`status` varchar(50) NOT NULL DEFAULT 'รอรับเรื่อง',
`created_by` int(11) DEFAULT NULL,
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `incidents` (`case_number`, `call_type`, `channel`, `ems_refer`, `unit_level`, `assigned_unit_id`, `symptom_group`, `phone_triage`, `fast_track`, `transport_route`, `completed_by`, `diagnosis`, `status`, `created_by`) VALUES
('08-2569-1234', 'สายแจ้งเหตุ / สายปฏิบัติการ', 'First Call', 'EMS', 'ALS', 8, 'CBD-17: อุบัติเหตุจราจร (RTI)', 'สีแดง - วิกฤตคุกคามชีพ', 'ไม่มี Fast Track', 'ทางบก (รถพยาบาลฉุกเฉิน)', 'นพ.เกียรติภูมิ ภูมิใจไทย (ผู้อำนวยการศูนย์)', 'ผู้ป่วยเพศชายอายุ 45 ปี ประสบอุบัติเหตุล้มหัวฟาดพื้น...', 'รอรับเรื่อง', 1);
CREATE TABLE IF NOT EXISTS `ambulances` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`unit_id` int(11) NOT NULL,
`plate_number` varchar(20) NOT NULL,
`status` enum('พร้อมปฏิบัติการ','ไม่พร้อมปฏิบัติการ','ส่งซ่อม') NOT NULL DEFAULT 'พร้อมปฏิบัติการ',
`last_check_date` timestamp NULL DEFAULT NULL,
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `unit_id` (`unit_id`),
CONSTRAINT `ambulances_ibfk_1` FOREIGN KEY (`unit_id`) REFERENCES `units` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `ambulances` (`unit_id`, `plate_number`, `status`) VALUES
(1, 'กข-1234', 'พร้อมปฏิบัติการ'),
(2, 'นค-5678', 'พร้อมปฏิบัติการ'),
(8, 'รพ-9999', 'พร้อมปฏิบัติการ');
CREATE TABLE IF NOT EXISTS `radio_tests` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`unit_id` int(11) NOT NULL,
`signal_strength` varchar(50) NOT NULL,
`remarks` text,
`tester_id` int(11) NOT NULL,
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
@@ -0,0 +1,307 @@
<?php
require_once 'includes/db.php';
require_once 'includes/auth.php';
requireLogin();
// Mock Data to match the screenshot exactly for 100% UI fidelity
$cases = [
[
'id' => '08-2569-0012',
'date' => '2026-07-15',
'time' => '09:15',
'shift' => 'เช้า',
'type' => 'EMS',
'cbd' => 'CBD-17',
'unit' => 'โรงพยาบาลเกาะสมุย',
'level' => 'ALS',
'transport' => 'ทางบก',
'triage' => ['phone' => 'red', 'scene' => 'red', 'er' => 'red'],
'person' => 'นายสมเกียรติ',
'person_shift' => 'เช้า',
'status' => 'ปิดเคส'
],
[
'id' => '08-2569-0013',
'date' => '2026-07-15',
'time' => '10:10',
'shift' => 'เช้า',
'type' => 'Refer',
'cbd' => 'CBD-20',
'unit' => 'โรงพยาบาลเกาะสมุย',
'level' => 'ALS',
'transport' => 'ทางน้ำ',
'triage' => ['phone' => 'red', 'scene' => 'yellow', 'er' => 'red'],
'person' => 'นายสมเกียรติ',
'person_shift' => 'เช้า',
'status' => 'ปรับปรุงข้อมูลแล้ว'
],
[
'id' => '08-2569-0014',
'date' => '2026-07-15',
'time' => '17:15',
'shift' => 'บ่าย',
'type' => 'EMS',
'cbd' => 'CBD-01',
'unit' => 'หน่วยกู้ชีพหน้าเมือง',
'level' => 'CLS',
'transport' => 'ทางบก',
'triage' => ['phone' => 'green', 'scene' => 'green', 'er' => 'green'],
'person' => 'นางสาวสุดารัตน์',
'person_shift' => 'บ่าย',
'status' => 'ค้างปรับปรุงข้อมูล'
],
];
// Offline Units Mock
$offline_units = [
[
'name' => 'หน่วยกู้ชีพละไม',
'reason' => 'เหตุผลชำรุด: ยางรถเสื่อมสภาพ/อยู่ระหว่างรออะไหล่ส่งซ่อม',
'datetime' => '2026-07-15 08:30 น.',
'user' => 'dispatcher1'
]
];
// Fetch Active Units from Database
$stmt = $pdo->query("SELECT id, name, level FROM units WHERE is_active = 1 ORDER BY sort_order ASC, id ASC");
$activeUnits = $stmt ? $stmt->fetchAll(PDO::FETCH_ASSOC) : [];
require_once 'includes/header.php';
?>
<div class="space-y-6 animate-fadeIn pb-10">
<!-- Top Filter Area -->
<div class="bg-white rounded-2xl p-4 md:p-5 shadow-sm border border-slate-100 flex flex-wrap gap-3 items-center justify-between">
<div class="flex flex-wrap items-center gap-2.5">
<div class="relative">
<i data-lucide="search" class="w-4 h-4 text-slate-400 absolute left-3 top-1/2 -translate-y-1/2"></i>
<input type="text" id="filter-search" placeholder="ค้นหาเลขสพฉ. / CBD / อาการ..." class="pl-9 pr-3.5 py-1.5 border border-slate-200 focus:border-indigo-500 rounded-xl text-xs outline-none bg-slate-50/50 hover:bg-white focus:bg-white w-48 lg:w-64 font-semibold transition-all">
</div>
<select id="filter-unit" class="py-1.5 px-3 border border-slate-200 rounded-xl text-xs font-bold text-slate-700 bg-white focus:ring-1 focus:ring-indigo-500 outline-none">
<option value="">-- หน่วยปฏิบัติการกู้ชีพทั้งหมด --</option>
<?php foreach($activeUnits as $u): ?>
<option value="<?php echo htmlspecialchars($u['name']); ?>"><?php echo htmlspecialchars($u['name']); ?></option>
<?php endforeach; ?>
</select>
<select id="filter-status" class="py-1.5 px-3 border border-slate-200 rounded-xl text-xs font-bold text-slate-700 bg-white focus:ring-1 focus:ring-indigo-500 outline-none">
<option value="">-- สถานะเคสทั้งหมด --</option>
<option value="ค้างปรับปรุงข้อมูล">❌ ค้างปรับปรุงข้อมูล</option>
<option value="ปรับปรุงข้อมูลแล้ว">🟡 ปรับปรุงข้อมูลแล้ว</option>
<option value="ปิดเคส">🟢 ปิดเคส</option>
</select>
</div>
<div class="text-xs font-bold bg-indigo-50 text-indigo-700 px-3.5 py-1.5 rounded-xl border border-indigo-100 self-end md:self-auto flex items-center gap-1.5">
<i data-lucide="filter" class="w-3.5 h-3.5"></i> <span id="filter-count">พบทั้งหมด <?= count($cases) ?> รายการสอดคล้อง</span>
</div>
</div>
<!-- Data Table Area -->
<div class="bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden">
<div class="p-4 md:p-5 border-b border-slate-100 bg-slate-50/50 flex flex-col sm:flex-row sm:items-center justify-between gap-3">
<div>
<h3 class="text-base font-black text-slate-800">รายการรับเคสปฏิบัติการ ศูนย์นเรนทรอ่าวไทย</h3>
<p class="text-xs text-slate-500 mt-0.5 font-medium">รวมเคสฉุกเฉินกู้ชีพทุกลำดับ และผู้ประเมินสถานะการพยาบาลรับ-ส่งต่อ</p>
</div>
</div>
<div class="overflow-x-auto">
<table class="w-full text-left border-collapse text-xs md:text-sm whitespace-nowrap lg:whitespace-normal">
<thead>
<tr class="bg-slate-50 text-slate-600 font-bold border-b border-slate-100">
<th class="py-3 px-4 uppercase tracking-wider">เลขปฏิบัติการ (สพฉ.)</th>
<th class="py-3 px-3 uppercase tracking-wider">ประเภทเคส</th>
<th class="py-3 px-3 uppercase tracking-wider">หน่วยงานกู้ชีพรับเหมา</th>
<th class="py-3 px-3 text-center uppercase tracking-wider">Triage (Phone/Scene/ER)</th>
<th class="py-3 px-3 uppercase tracking-wider">ผู้รับผิดชอบกู้ชีพ</th>
<th class="py-3 px-3 text-center uppercase tracking-wider">สถานะเคส</th>
<th class="py-3 px-4 text-center uppercase tracking-wider">การดำเนินการ</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100 text-slate-700 font-medium">
<?php foreach ($cases as $c): ?>
<tr class="hover:bg-slate-50/50 transition-colors case-row">
<td class="py-3.5 px-4">
<div class="font-extrabold text-slate-900 font-mono text-xs case-id"><?= $c['id'] ?></div>
<div class="text-[10px] text-slate-400 mt-0.5 font-bold">วันที่: <?= $c['date'] ?> | <?= $c['time'] ?> น. (เวร<?= $c['shift'] ?>)</div>
</td>
<td class="py-3.5 px-3">
<div class="flex flex-col gap-1 items-start">
<?php if($c['type'] === 'EMS'): ?>
<span class="px-2 py-0.5 rounded text-[10px] font-black tracking-wide border bg-blue-50 text-blue-600 border-blue-200">EMS</span>
<?php else: ?>
<span class="px-2 py-0.5 rounded text-[10px] font-black tracking-wide border bg-indigo-50 text-indigo-600 border-indigo-200">Refer</span>
<?php endif; ?>
<span class="text-[10px] text-slate-500 font-bold case-cbd"><?= $c['cbd'] ?></span>
</div>
</td>
<td class="py-3.5 px-3">
<div class="font-extrabold text-slate-800 text-xs case-unit"><?= $c['unit'] ?></div>
<div class="text-[10px] text-slate-400 mt-0.5 font-semibold">ระดับความพร้อม: <?= $c['level'] ?> | ลำเลียง: <?= $c['transport'] ?></div>
</td>
<td class="py-3.5 px-3 text-center">
<div class="flex items-center justify-center gap-1.5 font-black text-white" style="font-size: 10px;">
<?php
$getColor = function($color) {
if ($color === 'red') return '#e60000';
if ($color === 'yellow') return '#f59e0b';
if ($color === 'green') return '#009959';
return '#94a3b8'; // slate-400
};
?>
<div class="rounded flex items-center justify-center" style="width: 18px; height: 18px; background-color: <?= $getColor($c['triage']['phone']) ?>;" title="Phone Triage">P</div>
<span class="text-slate-200 font-normal" style="font-size: 10px;">/</span>
<div class="rounded flex items-center justify-center" style="width: 18px; height: 18px; background-color: <?= $getColor($c['triage']['scene']) ?>;" title="Scene Triage">S</div>
<span class="text-slate-200 font-normal" style="font-size: 10px;">/</span>
<div class="rounded flex items-center justify-center" style="width: 18px; height: 18px; background-color: <?= $getColor($c['triage']['er']) ?>;" title="ER Triage">E</div>
</div>
</td>
<td class="py-3.5 px-3">
<div class="font-extrabold text-slate-800 text-xs"><?= $c['person'] ?></div>
<div class="text-[10px] text-slate-400 mt-0.5 font-semibold">เวรรอบ: <?= $c['person_shift'] ?></div>
</td>
<td class="py-3.5 px-3 text-center case-status">
<?php if($c['status'] === 'ปิดเคส'): ?>
<span class="px-2.5 py-1 rounded-full text-[10px] font-bold border bg-emerald-50 text-emerald-600 border-emerald-200">ปิดเคส</span>
<?php elseif($c['status'] === 'ปรับปรุงข้อมูลแล้ว'): ?>
<span class="px-2.5 py-1 rounded-full text-[10px] font-bold border bg-amber-50 text-amber-600 border-amber-200">ปรับปรุงข้อมูลแล้ว</span>
<?php else: ?>
<span class="px-2.5 py-1 rounded-full text-[10px] font-bold border bg-rose-50 text-rose-600 border-rose-200">ค้างปรับปรุงข้อมูล</span>
<?php endif; ?>
</td>
<td class="py-3.5 px-4 text-center">
<button class="flex items-center justify-center gap-1.5 border border-slate-200 hover:border-indigo-300 text-slate-600 hover:text-indigo-600 hover:bg-indigo-50 font-bold text-[10px] px-3 py-1.5 rounded-xl transition-all mx-auto shadow-sm cursor-pointer">
<i data-lucide="edit-3" class="w-3.5 h-3.5"></i> แก้ไขข้อมูล
</button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="bg-slate-50 p-3 rounded-b-2xl border-t border-slate-100 text-[11px] font-bold text-slate-500 flex items-center gap-2">
<div class="w-6 h-6 rounded-full bg-amber-100 text-amber-600 flex items-center justify-center flex-shrink-0"><i data-lucide="info" class="w-3.5 h-3.5"></i></div>
เคล็ดลับปฏิบัติการ: ข้อมูลเคสจะถูกนำเข้าสู่ระบบบัญชี "หน้าเคสปฏิบัติการ" โดยอัตโนมัติ เพื่อให้ผู้รับผิดชอบ (Complete) และทีม ER ดำเนินการคัดแยกสี และปิดเคสอย่างละเอียด
</div>
</div>
<!-- Bottom Grids -->
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Report Readiness Form -->
<div class="bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden">
<div class="p-5 border-b border-slate-100">
<h3 class="text-sm font-black text-rose-700 flex items-center gap-2">
<i data-lucide="alert-circle" class="w-5 h-5"></i> บันทึกรายงานระดับสถานะความพร้อมของหน่วยงานกู้ชีพ
</h3>
<p class="text-[10px] text-slate-500 mt-1 font-semibold">ระบบจะระงับการจ่ายงานหากหน่วยกู้ภัยในข่ายแจ้งไม่พร้อมปฏิบัติการ เช่น รอส่งซ่อมชั่วคราว</p>
</div>
<form class="p-5 space-y-4">
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label class="block text-xs font-bold text-slate-600 mb-1.5">เลือกหน่วยปฏิบัติการที่มีปัญหา</label>
<select class="w-full py-2 px-3 border border-slate-200 rounded-xl text-sm font-semibold text-slate-700 bg-white focus:ring-1 focus:ring-indigo-500 outline-none">
<option value="">-- เลือกหน่วยงานกู้ชีพ --</option>
<?php foreach($activeUnits as $u): ?>
<option value="<?php echo htmlspecialchars($u['id']); ?>"><?php echo htmlspecialchars($u['name'] . ' (' . $u['level'] . ')'); ?></option>
<?php endforeach; ?>
</select>
</div>
<div>
<label class="block text-xs font-bold text-slate-600 mb-1.5">คาดการณ์ระยะเวลาไม่พร้อมใช้ (ชั่วโมง)</label>
<input type="text" placeholder="เช่น 4, 12, 24" class="w-full py-2 px-3 border border-slate-200 rounded-xl text-sm font-semibold text-slate-700 bg-white focus:ring-1 focus:ring-indigo-500 outline-none">
</div>
</div>
<div class="flex items-center gap-2">
<input type="checkbox" id="unknown_time" class="w-4 h-4 text-rose-600 rounded border-slate-300 focus:ring-rose-500">
<label for="unknown_time" class="text-xs font-bold text-slate-700 cursor-pointer select-none">ยังไม่ทราบเวลาสิ้นสุดกู้คืนความพร้อมแน่นอน</label>
</div>
<div>
<label class="block text-xs font-bold text-slate-600 mb-1.5">ระบุเหตุผลขัดข้องความพร้อม</label>
<input type="text" placeholder="เช่น ยางรถเสื่อมชำรุดชั่วคราว, วิทยุโมบายล์พังควันขึ้น" class="w-full py-2 px-3 border border-slate-200 rounded-xl text-sm font-semibold text-slate-700 bg-white focus:ring-1 focus:ring-indigo-500 outline-none">
</div>
<button type="button" class="w-full bg-rose-600 hover:bg-rose-700 text-white font-black text-sm py-2.5 rounded-xl transition-all shadow-md shadow-rose-200/50 cursor-pointer">
ส่งแจ้งเตือน "ไม่พร้อมออกปฏิบัติการ" ขึ้น Dashboard EMS
</button>
</form>
</div>
<!-- Offline Units Status -->
<div class="bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden flex flex-col">
<div class="p-5 border-b border-slate-100 flex flex-col sm:flex-row justify-between items-start gap-2">
<div>
<h3 class="text-sm font-black text-slate-800">ขบวนกู้ภัยที่ยังไม่พร้อมปฏิบัติการ ณ ปัจจุบัน</h3>
<p class="text-[10px] text-slate-500 mt-1 font-semibold">อัปเดตแบบ Realtime ไปยัง Dashboard ผู้บริหารและพยาบาลนำส่ง</p>
</div>
<span class="bg-rose-100 text-rose-700 text-[10px] font-black px-2.5 py-1 rounded-full whitespace-nowrap self-start sm:self-auto">
1 หน่วยขัดข้อง
</span>
</div>
<div class="flex-1 p-5 overflow-y-auto min-h-[160px]">
<?php foreach($offline_units as $ou): ?>
<div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 border-b border-slate-50 pb-3 mb-3 last:border-0 last:pb-0 last:mb-0">
<div>
<div class="font-black text-slate-800 text-sm"><?= $ou['name'] ?></div>
<div class="text-[10px] font-bold text-rose-600 mt-1"><?= $ou['reason'] ?></div>
<div class="text-[10px] text-slate-400 mt-0.5 font-semibold">บันทึกเมื่อ: <?= $ou['datetime'] ?> | โดย: <?= $ou['user'] ?></div>
</div>
<button class="bg-emerald-50 hover:bg-emerald-100 text-emerald-600 border border-emerald-200 font-bold text-[10px] px-3 py-1.5 rounded-xl transition-all whitespace-nowrap self-end sm:self-auto cursor-pointer">
กลับคืนพร้อมปฏิบัติ
</button>
</div>
<?php endforeach; ?>
</div>
<div class="bg-slate-50/50 p-4 border-t border-slate-100 text-[10px] font-bold text-slate-600 flex items-start gap-2">
<span class="text-amber-500 text-sm mt-0.5">⚠️</span>
<span>แจ้งฝ่ายนำรถ: หากปัญหาซ่อมบำรุงในรถพยาบาลได้รับการแก้ไขแล้ว กรุณากดปุ่ม "กลับคืนพร้อมปฏิบัติ" เพื่อล้างสถานะ Dashboard</span>
</div>
</div>
</div>
</div>
<?php require_once 'includes/footer.php'; ?>
<script>
document.addEventListener('DOMContentLoaded', function() {
const filterSearch = document.getElementById('filter-search');
const filterUnit = document.getElementById('filter-unit');
const filterStatus = document.getElementById('filter-status');
const filterCount = document.getElementById('filter-count');
const caseRows = document.querySelectorAll('.case-row');
function filterCases() {
const searchTerm = filterSearch.value.toLowerCase();
const unitTerm = filterUnit.value.toLowerCase();
const statusTerm = filterStatus.value.toLowerCase();
let visibleCount = 0;
caseRows.forEach(row => {
const idText = row.querySelector('.case-id').innerText.toLowerCase();
const cbdText = row.querySelector('.case-cbd').innerText.toLowerCase();
const unitText = row.querySelector('.case-unit').innerText.toLowerCase();
const statusText = row.querySelector('.case-status').innerText.toLowerCase();
// Match conditions
const matchesSearch = searchTerm === '' || idText.includes(searchTerm) || cbdText.includes(searchTerm);
const matchesUnit = unitTerm === '' || unitText.includes(unitTerm);
const matchesStatus = statusTerm === '' || statusText.includes(statusTerm);
if (matchesSearch && matchesUnit && matchesStatus) {
row.style.display = '';
visibleCount++;
} else {
row.style.display = 'none';
}
});
filterCount.innerText = `พบทั้งหมด ${visibleCount} รายการสอดคล้อง`;
}
filterSearch.addEventListener('input', filterCases);
filterUnit.addEventListener('change', filterCases);
filterStatus.addEventListener('change', filterCases);
});
</script>
@@ -0,0 +1,30 @@
<?php
function isLoggedIn() {
return isset($_SESSION['user_id']);
}
function requireLogin() {
if (!isLoggedIn()) {
header("Location: index.php");
exit;
}
}
function requireAdmin() {
if (!isLoggedIn() || $_SESSION['role'] !== 'admin') {
echo "<script>
document.addEventListener('DOMContentLoaded', function() {
Swal.fire({
icon: 'error',
title: 'ไม่มีสิทธิ์เข้าถึงหน้านี้',
confirmButtonColor: '#4f46e5',
confirmButtonText: 'ตกลง'
}).then(() => {
window.location.href = 'dashboard.php';
});
});
</script>";
exit;
}
}
?>
@@ -0,0 +1,26 @@
<?php
session_start();
$host = 'localhost';
$user = 'root';
$pass = '@Samui@10742'; // Leave empty or set to user's local mysql root password
$db = 'narenthorn_samui';
try {
$pdo = new PDO("mysql:host=$host;dbname=$db;charset=utf8mb4", $user, $pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
} catch (PDOException $e) {
die("Database connection failed: " . $e->getMessage());
}
// Global settings function
function getSetting($pdo, $key, $default = '') {
try {
$stmt = $pdo->prepare("SELECT setting_value FROM settings WHERE setting_key = ?");
$stmt->execute([$key]);
$result = $stmt->fetchColumn();
return $result !== false ? $result : $default;
} catch (PDOException $e) {
return $default; // Settings table might not exist yet
}
}
@@ -0,0 +1,37 @@
<?php if(isLoggedIn()): ?>
</main>
</div> <!-- End Main Content Flex Row -->
<!-- Fixed Bottom Footer (Full Width) -->
<footer class="bg-white border-t border-slate-200/80 p-3 text-center flex-shrink-0 z-40 shadow-sm relative w-full">
<p class="text-[10px] text-slate-400 font-bold tracking-wider">
&copy; <?php echo date('Y'); ?> <?php echo htmlspecialchars(getSetting($pdo, 'footer_text', 'ศูนย์รับแจ้งเหตุและสั่งการนเรนทรอ่าวไทย ระบบบริหารจัดการ. สงวนลิขสิทธิ์.')); ?>
</p>
</footer>
<?php endif; ?>
<!-- Initialize Lucide Icons -->
<script>
lucide.createIcons();
</script>
<?php
// Flash Messages for SweetAlert2
if (isset($_SESSION['flash'])) {
$flash = $_SESSION['flash'];
echo "<script>
Swal.fire({
icon: '{$flash['type']}',
title: '{$flash['title']}',
text: '{$flash['message']}',
confirmButtonColor: '#4f46e5',
customClass: {
container: 'font-sans'
}
});
</script>";
unset($_SESSION['flash']);
}
?>
</body>
</html>
@@ -0,0 +1,155 @@
<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ศูนย์รับแจ้งเหตุและสั่งการนเรนทรอ่าวไทย</title>
<!-- Old System CSS -->
<link rel="stylesheet" href="assets/app.css">
<!-- SweetAlert2 -->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<!-- Lucide Icons -->
<script src="https://unpkg.com/lucide@latest"></script>
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Sarabun:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet">
<style>
:root {
--font-sans: 'Sarabun', sans-serif !important;
}
body, * {
font-family: 'Sarabun', sans-serif !important;
}
body {
margin: 0;
padding: 0;
}
.animate-fadeIn { animation: fadeIn 0.3s ease-in-out; }
.animate-slideDown { animation: slideDown 0.3s ease-out; }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes slideDown { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } }
/* Custom scrollbar for sidebar */
.sidebar-scroll::-webkit-scrollbar { width: 4px; }
.sidebar-scroll::-webkit-scrollbar-track { background: transparent; }
.sidebar-scroll::-webkit-scrollbar-thumb { background: #334155; border-radius: 4px; }
</style>
</head>
<body class="h-screen w-screen bg-slate-50 flex flex-col text-slate-800 antialiased font-sans overflow-hidden">
<?php if(!isLoggedIn()): ?>
<!-- Empty for Login Screen -->
<?php else:
$currentPage = basename($_SERVER['PHP_SELF']);
?>
<!-- Header -->
<header class="bg-white border-b border-slate-200/80 sticky top-0 z-40 shadow-sm transition-all flex-shrink-0" id="app-header">
<div class="px-4 lg:px-6 py-3.5 flex flex-col md:flex-row md:items-center md:justify-between gap-4">
<div class="flex items-center gap-3">
<div class="p-2.5 bg-indigo-600 rounded-xl text-white shadow-md shadow-indigo-100 flex items-center justify-center">
<i data-lucide="activity" class="w-6 h-6"></i>
</div>
<div>
<h1 class="text-lg md:text-xl font-bold text-slate-900 tracking-tight"><?php echo htmlspecialchars(getSetting($pdo, 'system_name', 'ระบบบริหารจัดการ ศูนย์รับแจ้งเหตุและสั่งการนเรนทรอ่าวไทย')); ?></h1>
<p class="text-xs text-slate-400 mt-0.5 font-semibold tracking-wider uppercase">Narenthorn Gulf of Thailand Dispatch & Fleet Command Center</p>
</div>
</div>
<div class="flex flex-wrap items-center gap-2.5 md:gap-4 self-end md:self-auto">
<div class="flex items-center gap-2.5 bg-slate-50 border border-slate-200/60 px-3 py-1.5 rounded-xl text-xs md:text-sm text-slate-600 shadow-xs">
<i data-lucide="clock" class="w-4 h-4 text-indigo-500 animate-pulse"></i>
<span class="font-mono font-bold tracking-wider text-slate-800"><?php echo date('H:i'); ?></span>
<span class="text-slate-300">|</span>
<span class="text-slate-500 font-semibold"><?php echo date('d/m/Y'); ?></span>
<span class="ml-1.5 flex items-center gap-1.5 px-2 py-0.5 rounded-lg border text-xs font-bold text-amber-700 bg-amber-50 border-amber-200/60">
<i data-lucide="sun" class="w-3.5 h-3.5"></i> เวรเช้า
</span>
</div>
<div class="flex items-center gap-2.5 bg-slate-50 border border-slate-200/60 px-3 py-1.5 rounded-xl shadow-xs">
<div class="w-8 h-8 rounded-lg bg-indigo-50 border border-indigo-100 text-indigo-600 flex items-center justify-center font-extrabold text-sm shadow-xs">
<i data-lucide="user" class="w-4 h-4"></i>
</div>
<div class="hidden sm:block text-left">
<div class="text-xs font-bold text-slate-800 truncate max-w-[140px]"><?php echo htmlspecialchars($_SESSION['name']); ?></div>
<div class="flex items-center gap-1 mt-0.5">
<span class="text-[10px] font-bold px-1.5 py-0.5 rounded border uppercase tracking-wider bg-indigo-50 text-indigo-700 border-indigo-200/60"><?php echo htmlspecialchars($_SESSION['role']); ?></span>
</div>
</div>
<a href="logout.php" class="ml-1 p-1.5 text-slate-400 hover:text-rose-600 hover:bg-rose-50 border border-transparent hover:border-rose-100 rounded-lg transition-all cursor-pointer" title="ออกจากระบบ">
<i data-lucide="log-out" class="w-4 h-4"></i>
</a>
</div>
</div>
</div>
</header>
<div class="flex-1 flex flex-col md:flex-row overflow-hidden bg-slate-50">
<!-- Sidebar -->
<aside class="fixed md:static inset-y-0 left-0 w-64 bg-slate-900 text-slate-100 border-r border-slate-800 z-40 transform transition-transform duration-300 flex flex-col h-full -translate-x-full md:translate-x-0" id="app-sidebar">
<div class="p-4 border-b border-slate-800/80">
<div class="text-xs font-bold text-slate-400 tracking-wider uppercase mb-1">เมนูการปฏิบัติงาน</div>
<div class="text-[10px] text-indigo-400 font-bold uppercase tracking-wider">ผู้ใช้งานสิทธิ์: <?php echo htmlspecialchars($_SESSION['role']); ?></div>
</div>
<nav class="flex-1 px-3 py-4 space-y-1.5 overflow-y-auto sidebar-scroll">
<a href="dashboard.php" class="w-full flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-semibold transition-all cursor-pointer <?php echo $currentPage === 'dashboard.php' || $currentPage === 'index.php' ? 'bg-indigo-600 text-white shadow-md shadow-indigo-900/40 font-bold' : 'text-slate-300 hover:text-white hover:bg-slate-800/70'; ?>">
<i data-lucide="phone-call" class="w-4 h-4 <?php echo $currentPage === 'dashboard.php' || $currentPage === 'index.php' ? 'text-white' : 'text-slate-400 group-hover:text-white'; ?>"></i>
<span>รับแจ้งเหตุ</span>
<?php if($currentPage === 'dashboard.php' || $currentPage === 'index.php'): ?><div class="ml-auto w-1.5 h-1.5 bg-white rounded-full"></div><?php endif; ?>
</a>
<a href="incidents.php" class="w-full flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-semibold transition-all cursor-pointer <?php echo $currentPage === 'incidents.php' ? 'bg-indigo-600 text-white shadow-md shadow-indigo-900/40 font-bold' : 'text-slate-300 hover:text-white hover:bg-slate-800/70'; ?>">
<i data-lucide="activity" class="w-4 h-4 <?php echo $currentPage === 'incidents.php' ? 'text-white' : 'text-slate-400 group-hover:text-white'; ?>"></i>
<span>หน้าเคสปฏิบัติการ</span>
<?php if($currentPage === 'incidents.php'): ?><div class="ml-auto w-1.5 h-1.5 bg-white rounded-full"></div><?php endif; ?>
</a>
<a href="daily_report.php" class="w-full flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-semibold transition-all cursor-pointer <?php echo $currentPage === 'daily_report.php' ? 'bg-indigo-600 text-white shadow-md shadow-indigo-900/40 font-bold' : 'text-slate-300 hover:text-white hover:bg-slate-800/70'; ?>">
<i data-lucide="file-text" class="w-4 h-4 <?php echo $currentPage === 'daily_report.php' ? 'text-white' : 'text-slate-400 group-hover:text-white'; ?>"></i>
<span>รายงานประจำวัน</span>
<?php if($currentPage === 'daily_report.php'): ?><div class="ml-auto w-1.5 h-1.5 bg-white rounded-full"></div><?php endif; ?>
</a>
<a href="radio_test.php" class="w-full flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-semibold transition-all cursor-pointer <?php echo $currentPage === 'radio_test.php' ? 'bg-indigo-600 text-white shadow-md shadow-indigo-900/40 font-bold' : 'text-slate-300 hover:text-white hover:bg-slate-800/70'; ?>">
<i data-lucide="radio" class="w-4 h-4 <?php echo $currentPage === 'radio_test.php' ? 'text-white' : 'text-slate-400 group-hover:text-white'; ?>"></i>
<span>ทดสอบวิทยุ</span>
<?php if($currentPage === 'radio_test.php'): ?><div class="ml-auto w-1.5 h-1.5 bg-white rounded-full"></div><?php endif; ?>
</a>
<a href="statistics.php" class="w-full flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-semibold transition-all cursor-pointer <?php echo $currentPage === 'statistics.php' ? 'bg-indigo-600 text-white shadow-md shadow-indigo-900/40 font-bold' : 'text-slate-300 hover:text-white hover:bg-slate-800/70'; ?>">
<i data-lucide="bar-chart-2" class="w-4 h-4 <?php echo $currentPage === 'statistics.php' ? 'text-white' : 'text-slate-400 group-hover:text-white'; ?>"></i>
<span>รายงานสถิติ</span>
<?php if($currentPage === 'statistics.php'): ?><div class="ml-auto w-1.5 h-1.5 bg-white rounded-full"></div><?php endif; ?>
</a>
<a href="dashboard_ems.php" class="w-full flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-semibold transition-all cursor-pointer <?php echo $currentPage === 'dashboard_ems.php' ? 'bg-indigo-600 text-white shadow-md shadow-indigo-900/40 font-bold' : 'text-slate-300 hover:text-white hover:bg-slate-800/70'; ?>">
<i data-lucide="layout-dashboard" class="w-4 h-4 <?php echo $currentPage === 'dashboard_ems.php' ? 'text-white' : 'text-slate-400 group-hover:text-white'; ?>"></i>
<span>Dashboard EMS</span>
<?php if($currentPage === 'dashboard_ems.php'): ?><div class="ml-auto w-1.5 h-1.5 bg-white rounded-full"></div><?php endif; ?>
</a>
<a href="ambulances.php" class="w-full flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-semibold transition-all cursor-pointer <?php echo $currentPage === 'ambulances.php' ? 'bg-indigo-600 text-white shadow-md shadow-indigo-900/40 font-bold' : 'text-slate-300 hover:text-white hover:bg-slate-800/70'; ?>">
<i data-lucide="truck" class="w-4 h-4 <?php echo $currentPage === 'ambulances.php' ? 'text-white' : 'text-slate-400 group-hover:text-white'; ?>"></i>
<span>ความพร้อมรถพยาบาล</span>
<?php if($currentPage === 'ambulances.php'): ?><div class="ml-auto w-1.5 h-1.5 bg-white rounded-full"></div><?php endif; ?>
</a>
<a href="admin.php" class="w-full flex items-center justify-between px-4 py-3 rounded-xl text-sm font-semibold transition-all cursor-pointer <?php echo $currentPage === 'admin.php' ? 'bg-indigo-600 text-white shadow-md shadow-indigo-500/20' : 'text-slate-300 hover:text-white hover:bg-slate-800/70'; ?>">
<div class="flex items-center gap-3">
<i data-lucide="settings" class="w-4 h-4"></i> Admin
</div>
<?php if ($currentPage === 'admin.php'): ?>
<div class="w-1.5 h-1.5 rounded-full bg-white animate-pulse"></div>
<?php endif; ?>
</a>
</nav>
<div class="p-4 border-t border-slate-800 bg-slate-950/40">
<a href="logout.php" class="w-full flex items-center gap-3 px-4 py-3 text-sm font-semibold text-rose-400 hover:text-rose-300 hover:bg-rose-500/10 rounded-xl transition-all cursor-pointer">
<i data-lucide="log-out" class="w-4 h-4"></i>
<span>ออกจากระบบ</span>
</a>
</div>
</aside>
<!-- Main Content Area -->
<main class="flex-1 overflow-y-auto p-4 md:p-6 animate-fadeIn relative">
<?php endif; ?>
@@ -0,0 +1,90 @@
<?php
require_once 'includes/db.php';
require_once 'includes/auth.php';
if (isLoggedIn()) {
header("Location: dashboard.php");
exit;
}
$error = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = trim($_POST['username'] ?? '');
$password = $_POST['password'] ?? '';
if ($username && $password) {
$stmt = $pdo->prepare("SELECT id, password, full_name as name, role, is_active as status FROM users WHERE username = ?");
$stmt->execute([$username]);
$user = $stmt->fetch();
if ($user && password_verify($password, $user['password'])) {
if ($user['status'] == 1) {
$_SESSION['user_id'] = $user['id'];
$_SESSION['name'] = $user['name'];
$_SESSION['role'] = $user['role'];
$_SESSION['flash'] = [
'type' => 'success',
'title' => 'เข้าสู่ระบบสำเร็จ',
'message' => 'ยินดีต้อนรับเข้าสู่ระบบงานนเรนทรอ่าวไทย'
];
header("Location: dashboard.php");
exit;
} else {
$error = 'บัญชีผู้ใช้นี้ถูกระงับการเข้าใช้งานชั่วคราว';
}
} else {
$error = 'ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง';
}
} else {
$error = 'กรุณากรอกชื่อผู้ใช้และรหัสผ่าน';
}
}
require_once 'includes/header.php';
?>
<div class="flex-1 flex items-center justify-center p-4 md:p-8 bg-gradient-to-br from-slate-900 via-blue-950 to-slate-950 min-h-screen">
<div class="w-full max-w-md bg-white rounded-3xl shadow-2xl overflow-hidden border border-slate-100 p-6 md:p-8 space-y-6 animate-fadeIn">
<div class="text-center space-y-2">
<div class="mx-auto w-14 h-14 bg-blue-600 rounded-2xl text-white shadow-xl shadow-blue-500/20 flex items-center justify-center">
<i data-lucide="shield-alert" class="w-8 h-8"></i>
</div>
<h2 class="text-xl md:text-2xl font-black text-slate-900 tracking-tight">ระบบบริหารจัดการ นเรนทรอ่าวไทย</h2>
<p class="text-xs text-slate-400 font-bold">กรุณาเข้าสู่ระบบด้วยรหัสผ่านเพื่อเริ่มต้นปฏิบัติงาน</p>
</div>
<?php if ($error): ?>
<div class="bg-rose-50 border border-rose-200 text-rose-600 px-4 py-3 rounded-xl text-xs font-semibold leading-relaxed text-center">
<?php echo htmlspecialchars($error); ?>
</div>
<?php endif; ?>
<form method="POST" action="index.php" class="space-y-4">
<div>
<label for="username" class="block text-xs font-bold text-slate-500 mb-1.5 uppercase tracking-wider">ชื่อบัญชีผู้ใช้งาน</label>
<input type="text" id="username" name="username" required
class="w-full py-2.5 px-3.5 border border-slate-200 focus:border-indigo-500 rounded-xl text-center text-lg font-mono tracking-widest text-slate-800 outline-none transition-all"
placeholder="admin">
</div>
<div>
<label for="password" class="block text-xs font-bold text-slate-500 mb-1.5 uppercase tracking-wider">รหัสผ่าน</label>
<input type="password" id="password" name="password" required
class="w-full py-2.5 px-3.5 border border-slate-200 focus:border-indigo-500 rounded-xl text-center text-lg font-mono tracking-widest text-slate-800 outline-none transition-all"
placeholder="รหัสผ่าน">
</div>
<button type="submit" class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-black py-3 px-4 rounded-xl shadow-md shadow-indigo-200 transition-all active:scale-95 flex items-center justify-center gap-2 cursor-pointer border border-indigo-500/20 text-sm mt-2">
เข้าสู่ระบบ <i data-lucide="arrow-right" class="w-4 h-4"></i>
</button>
</form>
<div class="mt-8 text-center border-t border-slate-50 pt-4">
<p class="text-[10px] font-bold text-slate-400">สำหรับความปลอดภัย ข้อมูลการทำงานจะถูกบันทึกในระบบบัญชี</p>
</div>
</div>
</div>
<?php require_once 'includes/footer.php'; ?>
@@ -0,0 +1,12 @@
<?php
session_start();
session_destroy();
session_start();
$_SESSION['flash'] = [
'type' => 'success',
'title' => 'ออกจากระบบสำเร็จ',
'message' => 'ออกจากระบบสำเร็จเรียบร้อยแล้ว'
];
header("Location: index.php");
exit;
?>
@@ -0,0 +1,52 @@
-- 1. ลบและสร้างตาราง users ใหม่ให้รองรับฟิลด์ของระบบ Admin
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password` varchar(255) NOT NULL,
`full_name` varchar(100) NOT NULL,
`role` varchar(50) NOT NULL DEFAULT 'Dispatcher',
`pin` varchar(4) DEFAULT NULL,
`must_change_pin` tinyint(1) NOT NULL DEFAULT 0,
`is_active` tinyint(1) NOT NULL DEFAULT 1,
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- รหัสผ่านตั้งต้นสำหรับทุกคนคือ password (ใช้ bcrypt)
INSERT INTO `users` (`username`, `password`, `full_name`, `role`, `pin`, `must_change_pin`, `is_active`) VALUES
('admin', '$2y$10$tZ9.zW.M3t5H.P/C8S3Ohe5M8Vw2F6p1DkR.754sTqL5qH1qCqX92', 'นพ.เกียรติภูมิ ภูมิใจไทย (ผู้อำนวยการศูนย์)', 'Admin', '1234', 0, 1),
('supervisor1', '$2y$10$tZ9.zW.M3t5H.P/C8S3Ohe5M8Vw2F6p1DkR.754sTqL5qH1qCqX92', 'พญ.ชลิดา พัชรสมุย (แพทย์อำนวยการ/Supervisor)', 'Supervisor', '1234', 0, 1),
('dispatcher1', '$2y$10$tZ9.zW.M3t5H.P/C8S3Ohe5M8Vw2F6p1DkR.754sTqL5qH1qCqX92', 'นายสมเกียรติ มุ่งมั่น (Dispatcher 01)', 'Dispatcher', '1234', 0, 1),
('dispatcher2', '$2y$10$tZ9.zW.M3t5H.P/C8S3Ohe5M8Vw2F6p1DkR.754sTqL5qH1qCqX92', 'นางสาวสุดารัตน์ บรรเทา (Dispatcher 02)', 'Dispatcher', '1234', 0, 1),
('executive1', '$2y$10$tZ9.zW.M3t5H.P/C8S3Ohe5M8Vw2F6p1DkR.754sTqL5qH1qCqX92', 'ดร.สมชาย สมุชตี (ผู้บริหารระดับสูง)', 'Executive', '1234', 0, 1),
('samui_er', '$2y$10$tZ9.zW.M3t5H.P/C8S3Ohe5M8Vw2F6p1DkR.754sTqL5qH1qCqX92', 'พยาบาลสมหญิง รักเกาะ (พยาบาลวิชาชีพ ER รพ.เกาะสมุย)', 'ER Koh Samui', '1234', 0, 1),
('quality1', '$2y$10$tZ9.zW.M3t5H.P/C8S3Ohe5M8Vw2F6p1DkR.754sTqL5qH1qCqX92', 'นางพิสมัย พัฒนาระบบ (เจ้าหน้าที่ควบคุมคุณภาพ)', 'Quality Officer', '1234', 0, 1),
('driver1', '$2y$10$tZ9.zW.M3t5H.P/C8S3Ohe5M8Vw2F6p1DkR.754sTqL5qH1qCqX92', 'นายเด่นดนัย ขับปลอดภัย (พขร. กู้ชีพ)', 'Driver', '1234', 0, 1),
('ems1', '$2y$10$tZ9.zW.M3t5H.P/C8S3Ohe5M8Vw2F6p1DkR.754sTqL5qH1qCqX92', 'นายกิตติพงษ์ สุขใจ (กู้ชีพวิชาชีพ EMS)', 'EMS', '1234', 0, 1);
-- 2. ปรับโครงสร้างตาราง units
DROP TABLE IF EXISTS `units`;
CREATE TABLE `units` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`level` varchar(50) NOT NULL DEFAULT 'BLS',
`sort_order` int(11) NOT NULL DEFAULT 99,
`is_samui_hospital` tinyint(1) NOT NULL DEFAULT 0,
`is_active` tinyint(1) NOT NULL DEFAULT 1,
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- เพิ่มข้อมูลหน่วยจากภาพตัวอย่าง Admin
INSERT INTO `units` (`name`, `level`, `sort_order`, `is_samui_hospital`, `is_active`) VALUES
('โรงพยาบาลเกาะสมุย', 'ALS', 1, 1, 1),
('โรงพยาบาลเกาะพะงัน', 'ALS', 2, 0, 1),
('โรงพยาบาลเกาะเต่า', 'BLS', 3, 0, 1),
('โรงพยาบาลไทยอินเตอร์', 'ALS', 4, 0, 1),
('กู้ชีพตลิ่งงาม', 'BLS', 5, 0, 1),
('กู้ชีพละไม', 'BLS', 6, 0, 1),
('กู้ภัยสมุยจุดศิลางู', 'CLS', 7, 0, 1),
('กู้ภัยสมุยจุดสระเกศ', 'CLS', 8, 0, 1);
@@ -0,0 +1,64 @@
SET FOREIGN_KEY_CHECKS = 0;
-- Drop existing table
DROP TABLE IF EXISTS `ambulance_issues`;
DROP TABLE IF EXISTS `ambulance_inventory`;
DROP TABLE IF EXISTS `ambulances`;
-- 1. สร้างตารางรถพยาบาล (ambulances)
CREATE TABLE `ambulances` (
`id` varchar(20) NOT NULL,
`plate_no` varchar(50) NOT NULL,
`unit_id` int(11) NOT NULL,
`type` enum('ALS','BLS','CLS') NOT NULL DEFAULT 'BLS',
`latest_check_date` date NULL DEFAULT NULL,
`latest_check_time` time NULL DEFAULT NULL,
`latest_check_by` varchar(100) NULL DEFAULT NULL,
`overall_status` enum('พร้อมปฏิบัติการ','พร้อมใช้งานแบบมีข้อจำกัด','ไม่พร้อมปฏิบัติการ','ยังไม่ได้ตรวจ') NOT NULL DEFAULT 'ยังไม่ได้ตรวจ',
`issues_count` int(11) NOT NULL DEFAULT 0,
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 2. สร้างตารางแจ้งซ่อม/ปัญหา (ambulance_issues)
CREATE TABLE `ambulance_issues` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ambulance_id` varchar(20) NOT NULL,
`issue_name` varchar(255) NOT NULL,
`severity` enum('critical','important','general') NOT NULL DEFAULT 'important',
`status` enum('pending','fixing','resolved') NOT NULL DEFAULT 'pending',
`reported_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 3. สร้างตารางยา/เวชภัณฑ์ใกล้หมดอายุ (ambulance_inventory)
CREATE TABLE `ambulance_inventory` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ambulance_id` varchar(20) NOT NULL,
`item_name` varchar(255) NOT NULL,
`expire_date` date NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Insert Mock Data
INSERT INTO `ambulances` (`id`, `plate_no`, `unit_id`, `type`, `latest_check_date`, `latest_check_time`, `latest_check_by`, `overall_status`, `issues_count`) VALUES
('NRT-01', 'กข-9988 สุราษฎร์ธานี', 1, 'ALS', '2026-07-15', '08:20:00', 'นายเด่นดนัย ขับปลอดภัย', 'พร้อมปฏิบัติการ', 0),
('NRT-02', 'กข-5566 สุราษฎร์ธานี', 1, 'ALS', NULL, NULL, NULL, 'ยังไม่ได้ตรวจ', 0),
('NRT-03', 'นค-1122 สุราษฎร์ธานี', 2, 'ALS', NULL, NULL, NULL, 'ยังไม่ได้ตรวจ', 0),
('NRT-04', 'นค-3344 สุราษฎร์ธานี', 3, 'BLS', NULL, NULL, NULL, 'ยังไม่ได้ตรวจ', 0),
('NRT-05', 'บท-7744 สุราษฎร์ธานี', 11, 'BLS', NULL, NULL, NULL, 'ยังไม่ได้ตรวจ', 0),
('NRT-06', 'บท-8855 สุราษฎร์ธานี', 12, 'BLS', '2026-07-15', '08:30:00', 'นายกิตติพงษ์ สุขใจ', 'พร้อมใช้งานแบบมีข้อจำกัด', 2);
-- Insert Issues (สำหรับรถ NRT-06 ที่พบจุดชำรุด 2 แห่ง)
INSERT INTO `ambulance_issues` (`ambulance_id`, `issue_name`, `severity`, `status`) VALUES
('NRT-06', 'หน้ากาก N95 จำนวนไม่เพียงพอ', 'important', 'pending'),
('NRT-06', 'ผ้าก๊อซกึ่งห้ามเลือด (Trauma Dressing) หมดคลังรถ', 'critical', 'pending');
-- Insert Expiring Inventory (สมมติให้ expire_date เป็นวันในอนาคตเทียบกับวันที่ในรูป 2026-07-23)
-- แผ่น Defibrillator หมดอายุใน 24 วัน -> 2026-08-16
-- ET Tube เหลือ 65 วัน -> 2026-09-26
INSERT INTO `ambulance_inventory` (`ambulance_id`, `item_name`, `expire_date`) VALUES
('NRT-06', 'แผ่น Defibrillator Pads (หมดอายุ)', '2026-08-16'),
('NRT-01', 'ท่อช่วยหายใจ ET Tube ขนาด 7.5', '2026-09-26');
SET FOREIGN_KEY_CHECKS = 1;
@@ -0,0 +1,48 @@
-- ========================================================
-- ชุดคำสั่ง SQL สร้างตาราง Incidents ใหม่ + จำลองข้อมูล
-- ========================================================
USE narenthorn_samui;
-- 1. ลบตารางเก่าทิ้ง (เพื่อสร้างใหม่ให้โครงสร้างสมบูรณ์)
DROP TABLE IF EXISTS `incidents`;
-- 2. สร้างตาราง incidents ใหม่
CREATE TABLE `incidents` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`case_number` varchar(50) DEFAULT NULL,
`call_type` varchar(100) DEFAULT NULL,
`channel` varchar(100) DEFAULT NULL,
`ems_refer` varchar(50) DEFAULT NULL,
`unit_level` varchar(50) DEFAULT NULL,
`assigned_unit_id` int(11) DEFAULT NULL,
`symptom_group` varchar(255) DEFAULT NULL,
`phone_triage` varchar(100) DEFAULT NULL,
`fast_track` varchar(100) DEFAULT NULL,
`transport_route` varchar(100) DEFAULT NULL,
`completed_by` varchar(100) DEFAULT NULL,
`diagnosis` text,
`status` varchar(50) NOT NULL DEFAULT 'รอรับเรื่อง',
`created_by` int(11) DEFAULT NULL,
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 3. เพิ่มผู้ใช้งานจำลอง (Users)
INSERT IGNORE INTO `users` (`id`, `username`, `password`, `name`, `role`, `status`) VALUES
(2, 'dispatcher1', '$2y$10$tZ9.zW.M3t5H.P/C8S3Ohe5M8Vw2F6p1DkR.754sTqL5qH1qCqX92', 'นายสมเกียรติ มุ่งมั่น', 'user', 'active'),
(3, 'dispatcher2', '$2y$10$tZ9.zW.M3t5H.P/C8S3Ohe5M8Vw2F6p1DkR.754sTqL5qH1qCqX92', 'นางสาวสุดารัตน์ บรรเทา', 'user', 'active'),
(4, 'supervisor1', '$2y$10$tZ9.zW.M3t5H.P/C8S3Ohe5M8Vw2F6p1DkR.754sTqL5qH1qCqX92', 'พญ.ชลิดา พัชรสมุย', 'admin', 'active');
-- 4. เพิ่มข้อมูลเคสรับแจ้งเหตุจำลอง (Mockup Data)
INSERT INTO `incidents` (`case_number`, `call_type`, `channel`, `ems_refer`, `unit_level`, `assigned_unit_id`, `symptom_group`, `phone_triage`, `fast_track`, `transport_route`, `completed_by`, `diagnosis`, `status`, `created_by`) VALUES
('08-2569-1001', 'สายแจ้งเหตุ', 'First Call', 'EMS', 'ALS', 8, 'อุบัติเหตุจราจร (RTI)', 'สีแดง - วิกฤตคุกคามชีพ', 'Multiple Trauma', 'ทางบก (รถพยาบาลฉุกเฉิน)', 'นายสมเกียรติ มุ่งมั่น', 'รถจักรยานยนต์ชนเสาไฟฟ้า ผู้ป่วยหมดสติ', 'ปิดเคส', 2),
('08-2569-1002', 'สายแจ้งเหตุ', 'Second Call', 'EMS', 'BLS', 1, 'บาดเจ็บ/แผล/เลือดออก', 'สีเหลือง - เร่งด่วนกึ่งวิกฤต', 'ไม่มี Fast Track', 'ทางบก (รถพยาบาลฉุกเฉิน)', 'นายสมเกียรติ มุ่งมั่น', 'โดนมีดบาดลึกที่แขน เลือดออกมาก', 'ปิดเคส', 2),
('08-2569-1003', 'สายแจ้งเหตุ', 'วิทยุ', 'EMS', 'FR', 4, 'ปวดท้อง/หลัง/เชิงกราน', 'สีเขียว - เจ็บป่วยทั่วไป', 'ไม่มี Fast Track', 'ทางบก (รถพยาบาลฉุกเฉิน)', 'นางสาวสุดารัตน์ บรรเทา', 'ปวดท้องโรคกระเพาะกำเริบ', 'ปิดเคส', 3),
('08-2569-1004', 'สายแจ้งเหตุ', 'First Call', 'EMS', 'ALS', 9, 'หมดสติ/ไม่ตอบสนอง', 'สีแดง - วิกฤตคุกคามชีพ', 'STROKE', 'ทางบก (รถพยาบาลฉุกเฉิน)', NULL, 'ผู้ป่วยสูงอายุ แขนขาซ้ายอ่อนแรง ปากเบี้ยว', 'ค้างปรับปรุงข้อมูล', 3),
('08-2569-1005', 'สายแจ้งเหตุ', 'First Call', 'EMS', 'BLS', 2, 'หายใจลำบาก', 'สีเหลือง - เร่งด่วนกึ่งวิกฤต', 'ไม่มี Fast Track', 'ทางบก (รถพยาบาลฉุกเฉิน)', NULL, 'หอบหืดกำเริบ พ่นยาแล้วไม่ดีขึ้น', 'รอรับเรื่อง', 1),
('08-2569-1006', 'ประสานงาน', 'เบอร์อื่นๆ', 'Refer', 'BLS', 10, 'ป่วยนัดหมาย', 'สีขาว - ตรวจสุขภาพนัดส่งต่อ', 'ไม่มี Fast Track', 'เรือกู้ชีพ/Speedboat', 'Super Administrator', 'ส่งต่อผู้ป่วยนัดฟอกไต', 'ปิดเคส', 1),
('08-2569-1007', 'สายแจ้งเหตุ', 'First Call', 'EMS', 'ALS', 8, 'เจ็บหน้าอก/หัวใจ', 'สีแดง - วิกฤตคุกคามชีพ', 'STEMI', 'ทางบก (รถพยาบาลฉุกเฉิน)', 'พญ.ชลิดา พัชรสมุย', 'เจ็บแน่นหน้าอกร้าวไปกราม เหงื่อแตก', 'ปิดเคส', 4),
('08-2569-1008', 'สายแจ้งเหตุ', 'วิทยุ', 'EMS', 'FR', 6, 'สัตว์มีพิษกัดต่อย', 'สีเขียว - เจ็บป่วยทั่วไป', 'ไม่มี Fast Track', 'ทางบก (รถพยาบาลฉุกเฉิน)', NULL, 'งูเขียวหางบอบกัดบริเวณเท้า', 'รอรับเรื่อง', 2),
('08-2569-1009', 'สายแจ้งเหตุ', 'First Call', 'EMS', 'ALS', 11, 'จมน้ำ', 'สีแดง - วิกฤตคุกคามชีพ', 'ไม่มี Fast Track', 'เรือกู้ชีพ/Speedboat', NULL, 'นักท่องเที่ยวจมน้ำที่หาดเฉวง', 'ค้างปรับปรุงข้อมูล', 2),
('08-2569-1010', 'ประสานงาน', 'Second Call', 'Refer', 'BLS', 12, 'ป่วยนัดหมาย', 'สีขาว - ตรวจสุขภาพนัดส่งต่อ', 'ไม่มี Fast Track', 'ทางบก (รถพยาบาลฉุกเฉิน)', 'นางสาวสุดารัตน์ บรรเทา', 'รับผู้ป่วยติดเตียงกลับบ้าน', 'ปิดเคส', 3);
@@ -0,0 +1,49 @@
-- สร้างตาราง master_data สำหรับเก็บตัวเลือกฟอร์ม (Dropdowns)
DROP TABLE IF EXISTS `master_data`;
CREATE TABLE `master_data` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`category` varchar(50) NOT NULL COMMENT 'หมวดหมู่ เช่น call_type, call_channel, ems_refer',
`item_value` varchar(255) NOT NULL COMMENT 'ค่า value (อาจใช้สำหรับส่งเข้า DB จริง)',
`item_label` varchar(255) NOT NULL COMMENT 'ข้อความที่แสดงให้ผู้ใช้เห็น',
`sort_order` int(11) DEFAULT 99 COMMENT 'ลำดับการแสดงผล',
`is_active` tinyint(1) DEFAULT 1 COMMENT 'เปิด/ปิดใช้งาน',
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- เพิ่มข้อมูลเริ่มต้น (Default Values)
INSERT INTO `master_data` (`category`, `item_value`, `item_label`, `sort_order`) VALUES
('call_type', 'สายแจ้งเหตุ / สายปฏิบัติการ', 'สายแจ้งเหตุ / สายปฏิบัติการ', 1),
('call_type', 'สายก่อกวน', 'สายก่อกวน', 2),
('call_type', 'โทรผิด', 'โทรผิด', 3),
('call_type', 'แจ้งเหตุอื่น', 'แจ้งเหตุอื่น', 4),
('call_channel', 'First Call', 'First Call', 1),
('call_channel', 'Second Call', 'Second Call', 2),
('call_channel', 'วิทยุสื่อสาร', 'วิทยุสื่อสาร', 3),
('call_channel', 'ช่องทางอื่น', 'ช่องทางอื่น', 4),
('ems_refer', 'EMS', 'EMS (รับแจ้งเหตุ ณ จุดเกิดเหตุ)', 1),
('ems_refer', 'Refer', 'Refer (ประสานลำเลียงส่งต่อ)', 2),
('unit_level', 'ALS', 'ALS', 1),
('unit_level', 'BLS', 'BLS', 2),
('unit_level', 'CLS', 'CLS', 3),
('cbd_symptom', 'CBD-17: อุบัติเหตุจราจร (RTI)', 'CBD-17: อุบัติเหตุจราจร (RTI)', 1),
('cbd_symptom', 'CBD-01: ปวดท้อง/หลัง/อุ้งเชิงกราน', 'CBD-01: ปวดท้อง/หลัง/อุ้งเชิงกราน', 2),
('cbd_symptom', 'CBD-02: ภูมิแพ้/แพ้รุนแรง (Allergy/Anaphylaxis)', 'CBD-02: ภูมิแพ้/แพ้รุนแรง (Allergy/Anaphylaxis)', 3),
('phone_triage', 'สีแดง - วิกฤตคุกคามชีพ', '🔴 สีแดง - วิกฤตคุกคามชีพ', 1),
('phone_triage', 'สีเหลือง - เร่งด่วน', '🟡 สีเหลือง - เร่งด่วน', 2),
('phone_triage', 'สีเขียว - เจ็บป่วยทั่วไป', '🟢 สีเขียว - เจ็บป่วยทั่วไป', 3),
('phone_triage', 'สีขาว - ไม่เร่งด่วนทั่วไป', '⚪ สีขาว - ไม่เร่งด่วนทั่วไป', 4),
('fast_track', 'ไม่มี Fast Track', 'ไม่มี Fast Track', 1),
('fast_track', 'Stroke Fast Track', 'Stroke Fast Track', 2),
('fast_track', 'STEMI Fast Track', 'STEMI Fast Track', 3),
('fast_track', 'Trauma Fast Track', 'Trauma Fast Track', 4),
('transport_route', 'ทางบก (รถพยาบาลฉุกเฉิน)', 'ทางบก (รถพยาบาลฉุกเฉิน)', 1),
('transport_route', 'ทางน้ำ (เรือกู้ชีพ)', 'ทางน้ำ (เรือกู้ชีพ)', 2),
('transport_route', 'ทางอากาศ (เฮลิคอปเตอร์)', 'ทางอากาศ (เฮลิคอปเตอร์)', 3);
@@ -0,0 +1,16 @@
-- สร้างตาราง settings สำหรับเก็บการตั้งค่าทั่วไปของระบบ
DROP TABLE IF EXISTS `settings`;
CREATE TABLE `settings` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`setting_key` varchar(100) NOT NULL,
`setting_value` text NOT NULL,
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `setting_key` (`setting_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- เพิ่มข้อมูลการตั้งค่าเริ่มต้น
INSERT INTO `settings` (`setting_key`, `setting_value`) VALUES
('system_name', 'ระบบบริหารจัดการ ศูนย์รับแจ้งเหตุและสั่งการนเรนทรอ่าวไทย'),
('footer_text', 'ศูนย์รับแจ้งเหตุและสั่งการนเรนทรอ่าวไทย ระบบบริหารจัดการ. สงวนลิขสิทธิ์.');
@@ -0,0 +1,394 @@
<?php
require_once 'includes/db.php';
require_once 'includes/auth.php';
requireLogin();
// Fetch stations from database
$stations = [];
try {
$stmt = $pdo->query("SELECT id, name FROM units WHERE status = 'ready' ORDER BY id ASC LIMIT 16");
$stations = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
// If table doesn't exist, it will fallback to default stations
}
$stationList = [];
foreach ($stations as $station) {
$stationList[] = $station['name'];
}
$defaultStations = [
"พะงัน 2", "เกาะเต่า 2", "กู้ภัยพะงัน", "กู้ภัยสมุย", "เมืองสมุย",
"กู้ชีพละไม", "กู้ชีพหน้าเมือง", "กู้ชีพตลิ่งงาม", "โรงพยาบาลกรุงเทพสมุย",
"โรงพยาบาลไทยอินเตอร์", "โรงพยาบาลบ้านดอนอินเตอร์", "โรงพยาบาลวัฒนแพทย์สมุย",
"โรงพยาบาลเกาะสมุยอินเตอร์", "โรงพยาบาลไทยอินเตอร์เกาะพะงัน", "ER สมุย", "ทชท. ว.4"
];
if (empty($stationList)) {
$stationList = $defaultStations;
}
$currentUserFullName = isset($_SESSION['user_name']) ? $_SESSION['user_name'] : 'ผู้ทดสอบ (Admin)';
$testerFirstName = explode(' ', trim($currentUserFullName))[0];
$currentTime = date('13:58:40');
$currentDateStr = "23 กรกฎาคม 2569";
$shift = "เช้า";
$announceStart = "“เจ็บป่วยฉุกเฉิน โทร 1669 ที่นี่ศูนย์รับแจ้งเหตุนเรนทรอ่าวไทย\nขณะนี้เวลา {$currentTime} นเรนทรอ่าวไทยแจ้งลูกข่ายและในข่าย จะทำการทดสอบ ว.16\nลูกข่ายและในข่ายนเรนทรอ่าวไทย มี ว.29 ไม่เร่งด่วน ให้ ว.00\nหากมี ว.29 เร่งด่วน ให้ขออนุญาต ว.6 เข้ามาได้”";
$announceEnd = "“มีอีกหรือไม่ ลูกข่ายและในข่ายนเรนทรอ่าวไทยที่ต้องการทดสอบ ว.16 ให้ ว.6 เข้ามาได้\nว.24 นี้ [ {$currentTime} ] นเรนทรอ่าวไทยแจ้ง ว.14 ว.16\nวันนี้มีผู้ร่วมทดสอบ ว.16 จำนวน <span id=\"announce-tested\">16</span> สถานี\nนเรนทรอ่าวไทยขอขอบคุณทุกสถานีที่ร่วมทดสอบ ว.16\nแจ้งลูกข่ายและในข่ายใช้ความถี่ได้ตามปกติ\nทดสอบโดย สมุย [ {$testerFirstName} ]\nนเรนทรอ่าวไทย [ {$currentTime} ]”";
require_once 'includes/header.php';
?>
<div class="space-y-6 animate-fadeIn pb-10">
<!-- Top Announcement Box -->
<div class="bg-gradient-to-br from-blue-900 to-indigo-900 text-white rounded-2xl p-5 md:p-6 shadow-lg border border-blue-800">
<div class="flex items-center justify-between mb-4">
<div class="flex items-center gap-2.5">
<i data-lucide="radio" class="w-5 h-5 text-blue-300 animate-pulse"></i>
<span class="text-sm font-bold uppercase tracking-wider text-blue-200">ข้อความประกาศ ว.16 - ก่อนทดสอบ</span>
</div>
<button type="button" class="flex items-center gap-1.5 bg-blue-800/80 hover:bg-blue-700 text-xs px-3 py-1.5 rounded-lg border border-blue-600/50 transition-all cursor-pointer font-medium" onclick="navigator.clipboard.writeText(`<?php echo htmlspecialchars($announceStart); ?>`); Swal.fire({title: 'สำเร็จ', text: 'คัดลอกข้อความ เรียบร้อยแล้ว', icon: 'success', timer: 1500, showConfirmButton: false});">
<i data-lucide="copy" class="w-3.5 h-3.5"></i> คัดลอกบทพูด
</button>
</div>
<div class="bg-slate-950/50 p-4 rounded-xl border border-blue-800/50 font-mono text-xs md:text-sm leading-relaxed whitespace-pre-line text-slate-100"><?php echo $announceStart; ?></div>
</div>
<!-- Main 16 Stations Table -->
<div class="bg-white rounded-2xl shadow-sm border border-slate-200/80 overflow-hidden">
<div class="p-4 md:p-5 bg-slate-50 border-b border-slate-200/80 flex flex-col sm:flex-row sm:items-center justify-between gap-3">
<div>
<h3 class="text-base font-bold text-slate-800 flex items-center gap-2">
<i data-lucide="mic" class="w-4.5 h-4.5 text-indigo-600 animate-pulse"></i> ตารางทดสอบวิทยุ (16 สถานีหลัก)
</h3>
<p class="text-xs text-slate-400 mt-0.5 font-medium">ระบุระดับสัญญาณรับส่ง (5 หมายถึงดีที่สุด, ติดต่อไม่ได้ หมายถึงสัญญาณขาดหาย)</p>
</div>
<div class="text-xs font-bold bg-indigo-50 text-indigo-700 px-3 py-1.5 rounded-lg border border-indigo-100 self-start sm:self-auto flex items-center gap-1.5">
<i data-lucide="clock" class="w-3.5 h-3.5 text-indigo-500"></i> เวร<?php echo $shift; ?> | ผู้บันทึก: <?php echo $testerFirstName; ?>
</div>
</div>
<div class="overflow-x-auto">
<table class="w-full text-left border-collapse text-xs md:text-sm" id="main-stations-table">
<thead>
<tr class="bg-slate-100/50 text-slate-600 font-bold border-b border-slate-200/80">
<th class="py-3 px-4 w-12 text-center">ลำดับ</th>
<th class="py-3 px-3 min-w-[150px]">ชื่อสถานี</th>
<th class="py-3 px-3 text-center min-w-[130px]">สัญญาณส่ง (TX)</th>
<th class="py-3 px-3 text-center min-w-[130px]">สัญญาณรับ (RX)</th>
<th class="py-3 px-3 text-center w-36">ช่องรับสัญญาณ</th>
<th class="py-3 px-3 min-w-[150px]">หมายเหตุเพิ่มเติม</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100 text-slate-700 font-medium">
<?php foreach ($stationList as $index => $stationName): ?>
<tr class="hover:bg-slate-50/50 transition-colors radio-row" data-id="s_<?php echo $index + 1; ?>">
<td class="py-2.5 px-4 text-center text-slate-400 font-semibold"><?php echo $index + 1; ?></td>
<td class="py-2.5 px-3">
<div class="font-bold text-slate-800 station-name"><?php echo htmlspecialchars($stationName); ?></div>
</td>
<td class="py-2.5 px-3 text-center">
<select class="tx-level tx-rx-select w-full py-1.5 px-2 rounded-lg border border-slate-200 text-xs font-bold text-slate-700 focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 outline-none transition-all bg-emerald-50 text-emerald-700 border-emerald-200">
<option value="5" selected>5/5 - ดีมาก</option>
<option value="4">4/5 - ดี</option>
<option value="3">3/5 - ปานกลาง</option>
<option value="2">2/5 - อ่อน</option>
<option value="1">1/5 - แย่มาก</option>
<option value="ติดต่อไม่ได้">❌ ติดต่อไม่ได้</option>
</select>
</td>
<td class="py-2.5 px-3 text-center">
<select class="rx-level tx-rx-select w-full py-1.5 px-2 rounded-lg border border-slate-200 text-xs font-bold text-slate-700 focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 outline-none transition-all bg-emerald-50 text-emerald-700 border-emerald-200">
<option value="5" selected>5/5 - ดีมาก</option>
<option value="4">4/5 - ดี</option>
<option value="3">3/5 - ปานกลาง</option>
<option value="2">2/5 - อ่อน</option>
<option value="1">1/5 - แย่มาก</option>
<option value="ติดต่อไม่ได้">❌ ติดต่อไม่ได้</option>
</select>
</td>
<td class="py-2.5 px-3 text-center">
<div class="flex rounded-lg overflow-hidden border border-slate-200 p-0.5 bg-slate-100">
<input type="hidden" class="channel-type" value="T">
<button type="button" class="btn-channel-t flex-1 py-1 text-[10px] font-bold rounded-md transition-all cursor-pointer bg-indigo-600 text-white shadow-sm">T (ช่องตรง)</button>
<button type="button" class="btn-channel-r flex-1 py-1 text-[10px] font-bold rounded-md transition-all cursor-pointer text-slate-600 hover:text-slate-800">R (Repeater)</button>
</div>
</td>
<td class="py-2.5 px-3">
<input type="text" class="note-input w-full px-2.5 py-1.5 border border-slate-200 rounded-lg text-xs font-medium outline-none focus:border-indigo-400 focus:ring-1 focus:ring-indigo-400 transition-all bg-slate-50/50 hover:bg-white focus:bg-white" placeholder="ไม่มีความเห็นพิเศษ...">
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<!-- Extra 5 Stations Table -->
<div class="bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden" id="extra-stations-container">
<div class="p-4 md:p-5 bg-slate-50 border-b border-slate-100">
<h3 class="text-base font-bold text-slate-800 flex items-center gap-2">
<i data-lucide="plus-circle" class="w-4 h-4 text-emerald-600"></i> ตารางทดสอบวิทยุเพิ่มเติม (ลูกข่ายอื่น ๆ 5 ช่องพิเศษ)
</h3>
<p class="text-xs text-slate-500 mt-0.5">ระบุชื่อลูกข่ายและผลทดสอบวิทยุ (หากมีการกรอกชื่อ ระบบจึงจะนำข้อมูลมาคำนวณจำนวนผลสรุป)</p>
</div>
<div class="p-4 space-y-4">
<div class="grid grid-cols-1 md:grid-cols-5 gap-3 font-bold text-xs text-slate-500 border-b border-slate-100 pb-2 hidden md:grid">
<div class="col-span-2 px-1">ระบุชื่อสถานีลูกข่ายเพิ่มเติม</div>
<div class="text-center">สัญญาณส่ง (TX)</div>
<div class="text-center">สัญญาณรับ (RX)</div>
<div class="px-1">หมายเหตุเพิ่มเติม</div>
</div>
<?php for($i = 0; $i < 5; $i++): ?>
<div class="radio-row extra-row grid grid-cols-1 md:grid-cols-5 gap-3 items-center bg-slate-50/30 p-2.5 md:p-1 rounded-xl border border-slate-100 md:border-none md:bg-transparent" data-id="extra_<?php echo $i; ?>">
<div class="col-span-2 flex items-center gap-2">
<span class="text-xs font-bold text-slate-400 w-6 text-center"><?php echo $i + 17; ?></span>
<input type="text" placeholder="เช่น กู้ชีพตลิ่งงาม (ปล่อยว่างเพื่อไม่บันทึก)" class="station-name-input flex-1 px-3 py-2 border border-slate-200 rounded-lg text-xs font-semibold outline-none focus:border-emerald-400 focus:ring-1 focus:ring-emerald-400 transition-all bg-white">
<input type="hidden" class="channel-type" value="T">
</div>
<div>
<select disabled class="tx-level tx-rx-select w-full py-2 px-2.5 rounded-lg border border-slate-200 text-xs font-bold text-slate-700 outline-none transition-all disabled:opacity-50 disabled:bg-slate-50 bg-emerald-50 text-emerald-700 border-emerald-200">
<option value="5" selected>5/5 - ดีมาก</option>
<option value="4">4/5 - ดี</option>
<option value="3">3/5 - ปานกลาง</option>
<option value="2">2/5 - อ่อน</option>
<option value="1">1/5 - แย่มาก</option>
<option value="ติดต่อไม่ได้">❌ ติดต่อไม่ได้</option>
</select>
</div>
<div>
<select disabled class="rx-level tx-rx-select w-full py-2 px-2.5 rounded-lg border border-slate-200 text-xs font-bold text-slate-700 outline-none transition-all disabled:opacity-50 disabled:bg-slate-50 bg-emerald-50 text-emerald-700 border-emerald-200">
<option value="5" selected>5/5 - ดีมาก</option>
<option value="4">4/5 - ดี</option>
<option value="3">3/5 - ปานกลาง</option>
<option value="2">2/5 - อ่อน</option>
<option value="1">1/5 - แย่มาก</option>
<option value="ติดต่อไม่ได้">❌ ติดต่อไม่ได้</option>
</select>
</div>
<div class="col-span-1">
<input type="text" disabled placeholder="หมายเหตุเพิ่มเติม..." class="note-input w-full px-3 py-2 border border-slate-200 rounded-lg text-xs font-medium outline-none focus:border-emerald-400 focus:ring-1 focus:ring-emerald-400 transition-all bg-white disabled:opacity-50 disabled:bg-slate-50">
</div>
</div>
<?php endfor; ?>
</div>
</div>
<!-- Bottom Announcement Box -->
<div class="bg-gradient-to-br from-indigo-900 to-slate-900 text-white rounded-2xl p-5 md:p-6 shadow-lg border border-indigo-800">
<div class="flex items-center justify-between mb-4">
<div class="flex items-center gap-2.5">
<i data-lucide="radio" class="w-5 h-5 text-indigo-300 animate-pulse"></i>
<span class="text-sm font-bold uppercase tracking-wider text-indigo-200">ข้อความประกาศ ว.16 - ปิดการทดสอบ</span>
</div>
<button type="button" class="flex items-center gap-1.5 bg-indigo-800/80 hover:bg-indigo-700 text-xs px-3 py-1.5 rounded-lg border border-indigo-600/50 transition-all cursor-pointer font-medium" onclick="copyEndAnnouncement()">
<i data-lucide="copy" class="w-3.5 h-3.5"></i> คัดลอกบทพูด
</button>
</div>
<div class="bg-slate-950/50 p-4 rounded-xl border border-indigo-800/50 font-mono text-xs md:text-sm leading-relaxed whitespace-pre-line text-slate-100" id="announce-end-text"><?php echo $announceEnd; ?></div>
</div>
<!-- Footer Confirmation Bar -->
<div class="bg-slate-50 rounded-2xl p-4 md:p-5 border border-slate-200/80 flex flex-col sm:flex-row items-center justify-between gap-4">
<div class="flex items-center gap-3">
<div class="p-2 bg-indigo-100 rounded-xl text-indigo-700 border border-indigo-200/50">
<i data-lucide="check-circle" class="w-5 h-5"></i>
</div>
<div>
<h4 class="text-sm font-bold text-slate-800">ยืนยันและสรุปผลตรวจ ว.16</h4>
<p class="text-xs text-slate-400 mt-0.5 font-medium">เข้าร่วม <span id="summary-tested">16</span> สถานี | ติดต่อไม่ได้ <span id="summary-untested">0</span> สถานี | ผู้ทดสอบ: <?php echo htmlspecialchars($currentUserFullName); ?></p>
</div>
</div>
<button type="button" id="btn-save" class="w-full sm:w-auto flex items-center justify-center gap-2.5 bg-indigo-600 hover:bg-indigo-700 text-white font-bold text-sm px-6 py-3 rounded-xl shadow-md shadow-indigo-100 transition-all active:scale-95 cursor-pointer">
<i data-lucide="save" class="w-4 h-4"></i> บันทึกและส่งข้อมูลเข้ารายงานเวร
</button>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const updateCalculations = () => {
let testedCount = 0;
let untestedCount = 0;
document.querySelectorAll('.radio-row').forEach(row => {
const isExtra = row.classList.contains('extra-row');
let name = '';
if (isExtra) {
name = row.querySelector('.station-name-input').value.trim();
if (!name) return; // skip empty extra rows
}
const tx = row.querySelector('.tx-level').value;
const rx = row.querySelector('.rx-level').value;
if (tx === 'ติดต่อไม่ได้' && rx === 'ติดต่อไม่ได้') {
untestedCount++;
} else {
testedCount++;
}
});
document.getElementById('summary-tested').innerText = testedCount;
document.getElementById('announce-tested').innerText = testedCount;
document.getElementById('summary-untested').innerText = untestedCount;
};
// Colorize selects and update calculations
document.querySelectorAll('.tx-rx-select').forEach(select => {
select.addEventListener('change', function() {
this.classList.remove('bg-emerald-50', 'text-emerald-700', 'border-emerald-200', 'bg-rose-100', 'text-rose-700', 'border-rose-200');
if (this.value === '5') {
this.classList.add('bg-emerald-50', 'text-emerald-700', 'border-emerald-200');
} else if (this.value === 'ติดต่อไม่ได้') {
this.classList.add('bg-rose-100', 'text-rose-700', 'border-rose-200');
}
// Check row red background
const row = this.closest('tr');
if (row) {
const tx = row.querySelector('.tx-level').value;
const rx = row.querySelector('.rx-level').value;
if (tx === 'ติดต่อไม่ได้' && rx === 'ติดต่อไม่ได้') {
row.classList.add('bg-red-50/20');
} else {
row.classList.remove('bg-red-50/20');
}
}
updateCalculations();
});
});
// T/R buttons
document.querySelectorAll('.btn-channel-t').forEach(btn => {
btn.addEventListener('click', function() {
const hidden = this.parentElement.querySelector('.channel-type');
hidden.value = 'T';
this.classList.add('bg-indigo-600','text-white','shadow-sm');
this.classList.remove('text-slate-600','hover:text-slate-800');
this.nextElementSibling.classList.remove('bg-indigo-600','text-white','shadow-sm');
this.nextElementSibling.classList.add('text-slate-600','hover:text-slate-800');
});
});
document.querySelectorAll('.btn-channel-r').forEach(btn => {
btn.addEventListener('click', function() {
const hidden = this.parentElement.querySelector('.channel-type');
hidden.value = 'R';
this.classList.add('bg-indigo-600','text-white','shadow-sm');
this.classList.remove('text-slate-600','hover:text-slate-800');
this.previousElementSibling.classList.remove('bg-indigo-600','text-white','shadow-sm');
this.previousElementSibling.classList.add('text-slate-600','hover:text-slate-800');
});
});
// Extra stations
document.querySelectorAll('.station-name-input').forEach(input => {
input.addEventListener('input', function() {
const active = this.value.trim() !== '';
const selects = this.parentElement.parentElement.querySelectorAll('select, input[type=text]:not(.station-name-input)');
selects.forEach(el => el.disabled = !active);
updateCalculations();
});
});
window.copyEndAnnouncement = () => {
const text = document.getElementById('announce-end-text').innerText;
navigator.clipboard.writeText(text);
Swal.fire({title: 'สำเร็จ', text: 'คัดลอกข้อความ เรียบร้อยแล้ว', icon: 'success', timer: 1500, showConfirmButton: false});
};
// Save logic
document.getElementById('btn-save').addEventListener('click', async () => {
const btn = document.getElementById('btn-save');
btn.disabled = true;
const originalText = btn.innerHTML;
btn.innerHTML = 'กำลังบันทึก...';
let items = [];
document.querySelectorAll('.radio-row').forEach(row => {
const isExtra = row.classList.contains('extra-row');
let name = '';
if (isExtra) {
name = row.querySelector('.station-name-input').value.trim();
if (!name) return;
} else {
name = row.querySelector('.station-name').innerText.trim();
}
items.push({
station_id: row.dataset.id,
station_name: name,
tx_level: row.querySelector('.tx-level').value,
rx_level: row.querySelector('.rx-level').value,
channel_type: row.querySelector('.channel-type').value,
note: row.querySelector('.note-input').value.trim()
});
});
const payload = {
date: new Date().toISOString().split('T')[0],
time: '<?php echo $currentTime; ?>',
shift: '<?php echo $shift; ?>',
tested_count: document.getElementById('summary-tested').innerText,
untested_count: document.getElementById('summary-untested').innerText,
items: items
};
try {
const response = await fetch('api/save_radio_test.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
const data = await response.json();
if (data.success) {
Swal.fire({
title: 'สำเร็จ',
text: data.message,
icon: 'success',
confirmButtonColor: '#4f46e5'
}).then(() => {
window.scrollTo({top: 0, behavior: 'smooth'});
});
} else {
Swal.fire({
title: 'ข้อผิดพลาด',
text: data.message,
icon: 'error',
confirmButtonColor: '#ef4444'
});
}
} catch (error) {
console.error(error);
Swal.fire({
title: 'ข้อผิดพลาด',
text: 'เกิดข้อผิดพลาดในการเชื่อมต่อ',
icon: 'error',
confirmButtonColor: '#ef4444'
});
} finally {
btn.innerHTML = originalText;
btn.disabled = false;
}
});
});
</script>
<?php require_once 'includes/footer.php'; ?>
@@ -0,0 +1,281 @@
<?php
require_once 'includes/db.php';
require_once 'includes/auth.php';
requireLogin();
// Initialize default values to avoid errors
$totalCases = 0;
$totalFirstCalls = 0;
$totalCompleted = 0;
$totalPending = 0;
try {
// Fetch summary stats
$stmt = $pdo->query("SELECT COUNT(*) FROM incidents");
if ($stmt) {
$totalCases = $stmt->fetchColumn();
}
$stmt = $pdo->prepare("SELECT COUNT(*) FROM incidents WHERE channel LIKE :channel");
if ($stmt) {
$stmt->execute(['channel' => '%First Call%']);
$totalFirstCalls = $stmt->fetchColumn();
}
$stmt = $pdo->prepare("SELECT COUNT(*) FROM incidents WHERE status = :status");
if ($stmt) {
$stmt->execute(['status' => 'ปิดเคส']);
$totalCompleted = $stmt->fetchColumn();
}
$totalPending = max(0, $totalCases - $totalCompleted);
} catch (Exception $e) {
// Silently handle if incidents table doesn't exist yet
}
// Fetch Call Channels
$channelsQuery = "
SELECT
CASE
WHEN channel LIKE '%First Call%' THEN 'First Call (เบอร์ 1669 หลัก)'
WHEN channel LIKE '%Second Call%' THEN 'Second Call (สายซ้อนประสาน)'
WHEN channel LIKE '%วิทยุ%' THEN 'วิทยุสื่อสาร ว.6'
ELSE 'หมายเลขอื่น / ช่องทางอื่น ๆ'
END as channel_group,
COUNT(*) as count
FROM incidents
GROUP BY channel_group
";
$channelsResult = [];
try {
$stmt = $pdo->query($channelsQuery);
if ($stmt) {
$channelsResult = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
}
} catch (Exception $e) {}
// Fallback values if empty
$channels = [
'First Call (เบอร์ 1669 หลัก)' => $channelsResult['First Call (เบอร์ 1669 หลัก)'] ?? 0,
'Second Call (สายซ้อนประสาน)' => $channelsResult['Second Call (สายซ้อนประสาน)'] ?? 0,
'วิทยุสื่อสาร ว.6' => $channelsResult['วิทยุสื่อสาร ว.6'] ?? 0,
'หมายเลขอื่น / ช่องทางอื่น ๆ' => $channelsResult['หมายเลขอื่น / ช่องทางอื่น ๆ'] ?? 0,
];
// Fetch Phone Triage
$triageQuery = "
SELECT
CASE
WHEN phone_triage LIKE '%แดง%' THEN '🔴 สีแดง - วิกฤตสูงสุด'
WHEN phone_triage LIKE '%เหลือง%' THEN '🟡 สีเหลือง - เร่งด่วน'
WHEN phone_triage LIKE '%เขียว%' THEN '🟢 สีเขียว - เจ็บป่วยทั่วไป'
WHEN phone_triage LIKE '%ขาว%' THEN '⚪ สีขาว - ตรวจสุขภาพนัดส่งต่อ'
ELSE 'ไม่ระบุ'
END as triage_group,
COUNT(*) as count
FROM incidents
WHERE phone_triage IS NOT NULL AND phone_triage != ''
GROUP BY triage_group
";
$triageResult = [];
try {
$stmt = $pdo->query($triageQuery);
if ($stmt) {
$triageResult = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
}
} catch (Exception $e) {}
$triage = [
'🔴 สีแดง - วิกฤตสูงสุด' => $triageResult['🔴 สีแดง - วิกฤตสูงสุด'] ?? 0,
'🟡 สีเหลือง - เร่งด่วน' => $triageResult['🟡 สีเหลือง - เร่งด่วน'] ?? 0,
'🟢 สีเขียว - เจ็บป่วยทั่วไป' => $triageResult['🟢 สีเขียว - เจ็บป่วยทั่วไป'] ?? 0,
'⚪ สีขาว - ตรวจสุขภาพนัดส่งต่อ' => $triageResult['⚪ สีขาว - ตรวจสุขภาพนัดส่งต่อ'] ?? 0,
];
// Fetch Dispatcher Productivity
$productivity = [];
try {
$usersQuery = "SELECT id, username, full_name as name, role FROM users WHERE is_active = 1";
$stmt = $pdo->query($usersQuery);
if ($stmt) {
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($users as $user) {
// Calls & Cases Created
$stmt = $pdo->prepare("SELECT COUNT(*) FROM incidents WHERE created_by = :user_id");
$createdCount = 0;
if ($stmt) {
$stmt->execute(['user_id' => $user['id']]);
$createdCount = $stmt->fetchColumn();
}
// Assigned Cases (where they are completed_by)
$stmt = $pdo->prepare("SELECT COUNT(*) FROM incidents WHERE completed_by = :name OR completed_by = :username");
$assignedCount = 0;
if ($stmt) {
$stmt->execute(['name' => $user['name'], 'username' => $user['username']]);
$assignedCount = $stmt->fetchColumn();
}
// Completed Cases
$stmt = $pdo->prepare("SELECT COUNT(*) FROM incidents WHERE (completed_by = :name OR completed_by = :username) AND status = 'ปิดเคส'");
$resolvedCount = 0;
if ($stmt) {
$stmt->execute(['name' => $user['name'], 'username' => $user['username']]);
$resolvedCount = $stmt->fetchColumn();
}
$productivity[] = [
'fullName' => $user['name'],
'role' => $user['role'],
'createdCalls' => $createdCount,
'createdCases' => $createdCount,
'assignedCases' => $assignedCount,
'resolvedCases' => $resolvedCount,
];
}
}
} catch (Exception $e) {}
?>
<?php require_once 'includes/header.php'; ?>
<div class="space-y-6 animate-fadeIn pb-10">
<!-- Summary Cards -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="bg-white p-4 rounded-2xl shadow-sm border border-slate-100">
<div class="text-xs text-slate-400 font-bold">ยอดเคสสะสมในระบบ</div>
<div class="text-2xl font-black text-slate-800 mt-1"><?php echo $totalCases; ?> <span class="text-sm font-bold text-slate-500">เคส</span></div>
</div>
<div class="bg-white p-4 rounded-2xl shadow-sm border border-slate-100">
<div class="text-xs text-slate-400 font-bold">ยอดสายเรียกเข้าแรกรับ</div>
<div class="text-2xl font-black text-slate-800 mt-1"><?php echo $totalFirstCalls; ?> <span class="text-sm font-bold text-slate-500">สาย</span></div>
</div>
<div class="bg-white p-4 rounded-2xl shadow-sm border border-slate-100">
<div class="text-xs text-slate-400 font-bold">ประเมินเคสปิดสำเร็จ</div>
<div class="text-2xl font-black text-emerald-600 mt-1"><?php echo $totalCompleted; ?> <span class="text-sm font-bold text-slate-500">รายการ</span></div>
</div>
<div class="bg-white p-4 rounded-2xl shadow-sm border border-slate-100">
<div class="text-xs text-slate-400 font-bold font-sans">เคสตกค้าง/ยังไม่ปิด</div>
<div class="text-2xl font-black text-rose-600 mt-1"><?php echo $totalPending; ?> <span class="text-sm font-bold text-slate-500">รายการ</span></div>
</div>
</div>
<!-- Progress Bars Section -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Channels -->
<div class="bg-white rounded-2xl shadow-sm border border-slate-100 p-4 md:p-5">
<h3 class="text-sm font-bold text-slate-800 mb-4">สัดส่วนช่องทางการแจ้งเหตุ (Call Channels)</h3>
<div class="space-y-4">
<?php
$maxChannels = max(array_values($channels)) ?: 1; // Prevent div by zero
$channelColors = [
'First Call (เบอร์ 1669 หลัก)' => 'bg-blue-600',
'Second Call (สายซ้อนประสาน)' => 'bg-blue-500',
'วิทยุสื่อสาร ว.6' => 'bg-indigo-500',
'หมายเลขอื่น / ช่องทางอื่น ๆ' => 'bg-purple-500'
];
foreach($channels as $name => $count):
$percent = ($count / $maxChannels) * 100;
$color = $channelColors[$name];
?>
<div>
<div class="flex justify-between items-center text-xs font-bold mb-1.5">
<span class="text-slate-600"><?php echo $name; ?></span>
<span class="text-slate-700"><?php echo $count; ?> รายการ</span>
</div>
<div class="w-full bg-slate-100 rounded-full h-2">
<div class="<?php echo $color; ?> h-2 rounded-full transition-all duration-1000" style="width: <?php echo $percent; ?>%;"></div>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<!-- Triage -->
<div class="bg-white rounded-2xl shadow-sm border border-slate-100 p-4 md:p-5">
<h3 class="text-sm font-bold text-slate-800 mb-4">ระดับการประเมิน Phone Triage ฉุกเฉินคุกคามชีพ</h3>
<div class="space-y-4">
<?php
$maxTriage = max(array_values($triage)) ?: 1;
$triageColors = [
'🔴 สีแดง - วิกฤตสูงสุด' => 'bg-red-600',
'🟡 สีเหลือง - เร่งด่วน' => 'bg-amber-500',
'🟢 สีเขียว - เจ็บป่วยทั่วไป' => 'bg-emerald-500',
'⚪ สีขาว - ตรวจสุขภาพนัดส่งต่อ' => 'bg-slate-300'
];
foreach($triage as $name => $count):
$percent = ($count / $maxTriage) * 100;
$color = $triageColors[$name];
?>
<div>
<div class="flex justify-between items-center text-xs font-bold mb-1.5">
<span class="text-slate-600"><?php echo $name; ?></span>
<span class="text-slate-700"><?php echo $count; ?> รายการ</span>
</div>
<div class="w-full bg-slate-100 rounded-full h-2">
<div class="<?php echo $color; ?> h-2 rounded-full transition-all duration-1000" style="width: <?php echo $percent; ?>%;"></div>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
<!-- Productivity Table -->
<div class="bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden">
<div class="p-4 md:p-5 border-b border-slate-100 bg-slate-50 flex items-center justify-between">
<div>
<h3 class="text-base font-bold text-slate-800 flex items-center gap-1.5">
<i data-lucide="users" class="w-4.5 h-4.5 text-indigo-600"></i>
ดัชนีผลผลิตผู้ปฏิบัติการรับแจ้งเหตุและสั่งการ (Productivity ของเจ้าหน้าที่)
</h3>
<p class="text-xs text-slate-500 mt-1">คำนวณสถิติสรุปงานแยกรายเจ้าหน้าที่โดยอัตโนมัติอ้างอิงตาม username บันทึกข้อมูลจริงในข่าย</p>
</div>
</div>
<div class="overflow-x-auto">
<table class="w-full text-left border-collapse text-xs md:text-sm">
<thead>
<tr class="bg-slate-100/50 text-slate-600 font-bold border-b border-slate-100">
<th class="py-3 px-4">ชื่อเจ้าหน้าที่กู้ชีพกู้ภัย</th>
<th class="py-3 px-3 text-center">สิทธิ์ในระบบ</th>
<th class="py-3 px-3 text-center">รับสายโทรศัพท์ (สาย)</th>
<th class="py-3 px-3 text-center">สร้างเคสใหม่ (เคส)</th>
<th class="py-3 px-3 text-center">รับมอบ Complete (เคส)</th>
<th class="py-3 px-3 text-center">เคสที่ปิดแล้ว (เคส)</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100 text-slate-700 font-medium">
<?php foreach($productivity as $p): ?>
<tr class="hover:bg-slate-50/50 transition-colors">
<td class="py-3.5 px-4 font-bold text-slate-800"><?php echo htmlspecialchars($p['fullName']); ?></td>
<td class="py-3.5 px-3 text-center">
<span class="bg-slate-100 text-slate-600 px-2 py-0.5 rounded text-[10px] font-bold border border-slate-200 uppercase">
<?php echo htmlspecialchars($p['role']); ?>
</span>
</td>
<td class="py-3.5 px-3 text-center font-bold text-slate-700"><?php echo $p['createdCalls']; ?></td>
<td class="py-3.5 px-3 text-center font-bold text-slate-700"><?php echo $p['createdCases']; ?></td>
<td class="py-3.5 px-3 text-center font-bold text-slate-700"><?php echo $p['assignedCases']; ?></td>
<td class="py-3.5 px-3 text-center">
<span class="bg-emerald-50 text-emerald-700 font-black px-2 py-0.5 rounded text-xs">
<?php echo $p['resolvedCases']; ?> เคสสำเร็จ
</span>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<script>
lucide.createIcons();
</script>
<?php require_once 'includes/footer.php'; ?>
@@ -0,0 +1,168 @@
<?php
require_once 'includes/db.php';
require_once 'includes/auth.php';
requireAdmin(); // Admin only
// Handle actions
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['action'])) {
$action = $_POST['action'];
if ($action === 'create') {
$username = trim($_POST['username']);
$password = $_POST['password'];
$name = trim($_POST['name']);
$role = $_POST['role'];
$status = $_POST['status'];
// Check if username exists
$stmt = $pdo->prepare("SELECT id FROM users WHERE username = ?");
$stmt->execute([$username]);
if ($stmt->fetch()) {
$_SESSION['flash'] = ['type' => 'error', 'title' => 'ผิดพลาด', 'message' => 'ชื่อผู้ใช้นี้มีอยู่ในระบบแล้ว'];
} else {
$hashed_password = password_hash($password, PASSWORD_BCRYPT);
$stmt = $pdo->prepare("INSERT INTO users (username, password, name, role, status) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([$username, $hashed_password, $name, $role, $status]);
$_SESSION['flash'] = ['type' => 'success', 'title' => 'สำเร็จ', 'message' => 'เพิ่มผู้ใช้งานใหม่เรียบร้อยแล้ว'];
}
} elseif ($action === 'update_status') {
$id = $_POST['id'];
$status = $_POST['status'];
if ($id != $_SESSION['user_id']) { // prevent deactivating oneself
$stmt = $pdo->prepare("UPDATE users SET status = ? WHERE id = ?");
$stmt->execute([$status, $id]);
$_SESSION['flash'] = ['type' => 'success', 'title' => 'สำเร็จ', 'message' => 'อัปเดตสถานะเรียบร้อยแล้ว'];
} else {
$_SESSION['flash'] = ['type' => 'error', 'title' => 'ผิดพลาด', 'message' => 'ไม่สามารถระงับบัญชีของตัวเองได้'];
}
}
header("Location: users.php");
exit;
}
}
// Fetch all users
$stmt = $pdo->query("SELECT id, username, name, role, status, created_at FROM users ORDER BY created_at DESC");
$users = $stmt->fetchAll();
require_once 'includes/header.php';
?>
<div class="space-y-6">
<div class="flex flex-col sm:flex-row sm:items-center justify-between border-b border-slate-100 pb-3 gap-4">
<h2 class="text-xl font-black text-slate-800 flex items-center gap-2">
<i data-lucide="users" class="text-blue-500 w-5 h-5"></i> จัดการผู้ใช้งานระบบ
</h2>
<button onclick="document.getElementById('createUserModal').classList.remove('hidden')" class="bg-blue-600 hover:bg-blue-700 text-white text-xs font-bold py-2 px-4 rounded-xl shadow-sm transition-all flex items-center gap-2">
<i data-lucide="plus" class="w-4 h-4"></i> เพิ่มผู้ใช้งาน
</button>
</div>
<div class="bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full text-left border-collapse text-xs md:text-sm">
<thead>
<tr class="bg-slate-50 text-slate-500 font-bold border-b border-slate-200">
<th class="py-3 px-4 uppercase tracking-wider">ชื่อบัญชี</th>
<th class="py-3 px-4 uppercase tracking-wider">ชื่อ-นามสกุล</th>
<th class="py-3 px-4 uppercase tracking-wider">บทบาท</th>
<th class="py-3 px-4 uppercase tracking-wider">สถานะ</th>
<th class="py-3 px-4 uppercase tracking-wider text-right">จัดการ</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100">
<?php foreach ($users as $user): ?>
<tr class="hover:bg-slate-50 transition-colors">
<td class="py-3 px-4 font-bold text-slate-700"><?php echo htmlspecialchars($user['username']); ?></td>
<td class="py-3 px-4 text-slate-600"><?php echo htmlspecialchars($user['name']); ?></td>
<td class="py-3 px-4">
<?php if($user['role'] === 'admin'): ?>
<span class="bg-blue-100 text-blue-700 px-2 py-1 rounded-md text-[10px] font-bold">ผู้ดูแลระบบ</span>
<?php else: ?>
<span class="bg-slate-100 text-slate-600 px-2 py-1 rounded-md text-[10px] font-bold">ผู้ใช้งาน</span>
<?php endif; ?>
</td>
<td class="py-3 px-4">
<?php if($user['status'] === 'active'): ?>
<span class="text-emerald-500 font-bold flex items-center gap-1.5"><i data-lucide="circle" class="w-2 h-2 fill-emerald-500"></i> ใช้งานได้</span>
<?php else: ?>
<span class="text-rose-500 font-bold flex items-center gap-1.5"><i data-lucide="circle" class="w-2 h-2 fill-rose-500"></i> ระงับการใช้งาน</span>
<?php endif; ?>
</td>
<td class="py-3 px-4 text-right space-x-2">
<?php if ($user['id'] != $_SESSION['user_id']): ?>
<form method="POST" class="inline-block" onsubmit="event.preventDefault(); Swal.fire({title: 'ยืนยัน', text: 'ยืนยันการเปลี่ยนสถานะผู้ใช้นี้?', icon: 'warning', showCancelButton: true, confirmButtonColor: '#4f46e5', cancelButtonColor: '#ef4444', confirmButtonText: 'ใช่, เปลี่ยนสถานะ', cancelButtonText: 'ยกเลิก'}).then((result) => { if(result.isConfirmed) { this.submit(); } });">
<input type="hidden" name="action" value="update_status">
<input type="hidden" name="id" value="<?php echo $user['id']; ?>">
<input type="hidden" name="status" value="<?php echo $user['status'] === 'active' ? 'inactive' : 'active'; ?>">
<button type="submit" class="text-xs font-bold <?php echo $user['status'] === 'active' ? 'text-rose-500 hover:text-rose-700' : 'text-emerald-500 hover:text-emerald-700'; ?>">
<?php echo $user['status'] === 'active' ? 'ระงับ' : 'เปิดใช้งาน'; ?>
</button>
</form>
<?php else: ?>
<span class="text-slate-300 text-xs">-</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<!-- Modal: Create User -->
<div id="createUserModal" class="fixed inset-0 bg-slate-900/50 backdrop-blur-sm z-50 hidden flex items-center justify-center p-4">
<div class="bg-white rounded-2xl shadow-xl border border-slate-200 w-full max-w-md overflow-hidden animate-fadeIn">
<div class="p-5 border-b border-slate-100 flex justify-between items-center bg-slate-50">
<h3 class="font-black text-slate-800 text-lg">เพิ่มและจัดสร้างผู้ใช้ใหม่</h3>
<button type="button" onclick="document.getElementById('createUserModal').classList.add('hidden')" class="text-slate-400 hover:text-rose-500 transition-colors">
<i data-lucide="x" class="w-5 h-5"></i>
</button>
</div>
<form method="POST" action="users.php" class="p-5 space-y-4">
<input type="hidden" name="action" value="create">
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">ชื่อ-นามสกุล / ชื่อเรียก</label>
<input type="text" name="name" required class="w-full py-2 px-3 border border-slate-200 rounded-lg text-sm outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500">
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">ชื่อบัญชีผู้ใช้งาน (Username)</label>
<input type="text" name="username" required class="w-full py-2 px-3 border border-slate-200 rounded-lg text-sm outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500">
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">รหัสผ่าน</label>
<input type="password" name="password" required class="w-full py-2 px-3 border border-slate-200 rounded-lg text-sm outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500">
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">ระดับสิทธิ์</label>
<select name="role" class="w-full py-2 px-3 border border-slate-200 rounded-lg text-sm outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500">
<option value="user">ผู้ใช้งาน</option>
<option value="admin">ผู้ดูแลระบบ</option>
</select>
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-1">สถานะ</label>
<select name="status" class="w-full py-2 px-3 border border-slate-200 rounded-lg text-sm outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500">
<option value="active">ใช้งานได้</option>
<option value="inactive">ระงับการใช้งาน</option>
</select>
</div>
</div>
<div class="pt-4 flex justify-end gap-3 border-t border-slate-100">
<button type="button" onclick="document.getElementById('createUserModal').classList.add('hidden')" class="px-4 py-2 text-sm font-bold text-slate-600 bg-slate-100 hover:bg-slate-200 rounded-lg transition-colors">ยกเลิก</button>
<button type="submit" class="px-4 py-2 text-sm font-bold text-white bg-blue-600 hover:bg-blue-700 rounded-lg shadow-sm transition-colors">บันทึกข้อมูล</button>
</div>
</form>
</div>
</div>
<?php require_once 'includes/footer.php'; ?>