From 38573f5b152770595dc6d1bf524355e54ca3e5f5 Mon Sep 17 00:00:00 2001 From: DevSoftTech Server Date: Sat, 29 Aug 2026 04:25:57 +0530 Subject: [PATCH] fix(nursing): resolve SQL column errors in opdList query, add Doctor filter dropdown, and Vitals Pending/Done status filter buttons --- app/Controllers/Api/v1/NursingApi.php | 30 +++++++-- public/App/Nursing/index.html | 94 +++++++++++++++++++++++---- 2 files changed, 106 insertions(+), 18 deletions(-) diff --git a/app/Controllers/Api/v1/NursingApi.php b/app/Controllers/Api/v1/NursingApi.php index e421ba2..b4836b7 100644 --- a/app/Controllers/Api/v1/NursingApi.php +++ b/app/Controllers/Api/v1/NursingApi.php @@ -247,16 +247,17 @@ class NursingApi extends BaseController $dateMode = $this->request->getGet('date_mode') ?? 'today'; $docId = (int) ($this->request->getGet('doctor_id') ?? 0); + $vitalsFilter = $this->request->getGet('vitals_status') ?? 'all'; // 'all', 'pending', 'done' $whereClause = "WHERE 1=1"; if ($dateMode === 'today') { - $whereClause .= " AND DATE(o.date_of_assign) = CURDATE()"; + $whereClause .= " AND DATE(o.apointment_date) = CURDATE()"; } if ($docId > 0) { $whereClause .= " AND o.doc_id = " . $docId; } - $sql = "SELECT o.opd_id, o.opd_code, o.opd_no, o.p_id, o.doc_id, o.date_of_assign, o.opd_status, o.opd_type, + $sql = "SELECT o.opd_id, o.opd_code, o.opd_no, o.p_id, o.doc_id, o.apointment_date, o.opd_status, coalesce(o.opd_fee_type, 'Cash') as opd_type, p.p_fname as fname, p.p_rname as rname, p.p_code as uhid, p.mphone1, p.gender, p.age, p.age_in_month, p.estimate_dob, p.dob, concat('Dr. ', d.p_fname, ' ', coalesce(d.p_lname, '')) as doctor_name, pr.temp, pr.pulse, pr.bp, pr.diastolic, pr.spo2, pr.weight, pr.height, pr.rr_min @@ -270,10 +271,14 @@ class NursingApi extends BaseController $query = $db->query($sql); $records = $query->getResultArray(); - $todayTotalCount = (int) $db->query("SELECT count(*) as c FROM opd_master WHERE DATE(date_of_assign) = CURDATE()")->getRow()->c; + $todayTotalCount = (int) $db->query("SELECT count(*) as c FROM opd_master WHERE DATE(apointment_date) = CURDATE()")->getRow()->c; $allTotalCount = (int) $db->query("SELECT count(*) as c FROM opd_master")->getRow()->c; - $counts = ['all' => 0, 'waiting' => 0, 'visited' => 0, 'booked' => 0, 'cancelled' => 0, 'today_total' => $todayTotalCount, 'all_total' => $allTotalCount]; + $counts = [ + 'all' => 0, 'waiting' => 0, 'visited' => 0, 'booked' => 0, 'cancelled' => 0, + 'today_total' => $todayTotalCount, 'all_total' => $allTotalCount, + 'pending_vitals' => 0, 'done_vitals' => 0 + ]; $appointments = []; foreach ($records as $r) { @@ -291,6 +296,21 @@ class NursingApi extends BaseController $statusLabel = 'Booked'; } + $hasVitals = !empty($r['temp']) || !empty($r['pulse']) || !empty($r['bp']) || !empty($r['spo2']) || !empty($r['weight']); + + if ($hasVitals) { + $counts['done_vitals']++; + } else { + $counts['pending_vitals']++; + } + + if ($vitalsFilter === 'pending' && $hasVitals) { + continue; + } + if ($vitalsFilter === 'done' && !$hasVitals) { + continue; + } + $counts['all']++; if (isset($counts[$statusKey])) { $counts[$statusKey]++; @@ -303,8 +323,6 @@ class NursingApi extends BaseController $ageDisplay = $r['age'] . ' Year'; } - $hasVitals = !empty($r['temp']) || !empty($r['pulse']) || !empty($r['bp']) || !empty($r['spo2']) || !empty($r['weight']); - $r['status_key'] = $statusKey; $r['status_label'] = $statusLabel; $r['age_display'] = $ageDisplay; diff --git a/public/App/Nursing/index.html b/public/App/Nursing/index.html index 5561acf..0066014 100644 --- a/public/App/Nursing/index.html +++ b/public/App/Nursing/index.html @@ -232,9 +232,12 @@ // OPD Patients State const [opdAppointments, setOpdAppointments] = useState([]); - const [opdCounts, setOpdCounts] = useState({ all: 0, waiting: 0, visited: 0, booked: 0, cancelled: 0 }); + const [opdCounts, setOpdCounts] = useState({ all: 0, waiting: 0, visited: 0, booked: 0, cancelled: 0, pending_vitals: 0, done_vitals: 0 }); const [opdFilter, setOpdFilter] = useState('all'); const [opdDateMode, setOpdDateMode] = useState('today'); + const [doctors, setDoctors] = useState([]); + const [selectedDoctorId, setSelectedDoctorId] = useState('0'); + const [vitalsFilter, setVitalsFilter] = useState('all'); // 'all', 'pending', 'done' // Modals & Action State const [activeOpdForVitals, setActiveOpdForVitals] = useState(null); @@ -287,10 +290,25 @@ } }; - const fetchOpdAppointments = async (dateModeOverride) => { + const fetchDoctors = async () => { try { - const mode = dateModeOverride || opdDateMode; - const res = await fetch(`/api/v1/nursing/opd/list?date_mode=${mode}`); + const res = await fetch('/api/v1/doctor/list'); + const json = await res.json(); + if (json.status === 1 && json.data) { + setDoctors(json.data); + } + } catch (err) { + console.error('Failed to load doctors', err); + } + }; + + const fetchOpdAppointments = async (dateModeOverride, docIdOverride, vitalsOverride) => { + try { + const mode = dateModeOverride !== undefined ? dateModeOverride : opdDateMode; + const docId = docIdOverride !== undefined ? docIdOverride : selectedDoctorId; + const vFilter = vitalsOverride !== undefined ? vitalsOverride : vitalsFilter; + + const res = await fetch(`/api/v1/nursing/opd/list?date_mode=${mode}&doctor_id=${docId}&vitals_status=${vFilter}`); const json = await res.json(); if (json.status === 1) { setOpdAppointments(json.appointments || []); @@ -332,7 +350,7 @@ if (parsed && parsed.nurse && parsed.expires_at > Date.now()) { setAuthenticatedNurse(parsed.nurse); fetchBeds(); - fetchOpdAppointments(opdDateMode); + fetchOpdAppointments(opdDateMode, selectedDoctorId, vitalsFilter); } else { localStorage.removeItem(DEVICE_AUTH_KEY); } @@ -340,6 +358,7 @@ } fetchBeds(); fetchNurses(); + fetchDoctors(); }, []); const handleVerifyPin = async () => { @@ -825,18 +844,18 @@ OPD PATIENTS TAB (VITALS & DOCUMENT SCANNING) ------------------------------------------------------------- */
- {/* Date Mode Segmented Controller */} + {/* Date Mode Segmented Controller & Filters */}
@@ -846,16 +865,67 @@
- {/* Status Filters */} + {/* Doctor Filter & Vitals Filter Controls Box */} +
+
+
+ + +
+ +
+ +
+ + + +
+
+
+
+ + {/* Visit Status Filter Pills */}