Fix IPD patient admit search error, add admission type filters to IPD patient list, remove redundant sidebar links, and add OPD Day Care template support

This commit is contained in:
DevSoftTech Server 2026-09-23 10:12:42 +05:30
parent ccb05389e1
commit 3f1e89d4be
13 changed files with 423 additions and 40 deletions

View File

@ -705,6 +705,12 @@ $routes->get('opd_print/invoice_print_pdf/(:num)', 'Opd::invoice_print_pdf/$1');
$routes->get('opd_print/opd_PDF_print/(:num)', 'Opd::opd_pdf_print/$1');
$routes->get('opd_print/opd_Cont_print/(:num)', 'Opd::opd_cont_print/$1');
$routes->get('opd_print/opd_blank_print/(:num)', 'Opd::opd_blank_print/$1');
$routes->get('opd_print/opd_day_care/(:num)/(:num)', 'Opd::opd_day_care/$1/$2');
$routes->get('opd_print/opd_day_care/(:num)', 'Opd::opd_day_care/$1');
$routes->get('Opd_print/opd_day_care/(:num)/(:num)', 'Opd::opd_day_care/$1/$2');
$routes->get('Opd_print/opd_day_care/(:num)', 'Opd::opd_day_care/$1');
$routes->get('Opd/opd_day_care/(:num)/(:num)', 'Opd::opd_day_care/$1/$2');
$routes->get('Opd/opd_day_care/(:num)', 'Opd::opd_day_care/$1');
$routes->get('Opd_prescription/Prescription/(:num)', 'Opd_prescription::Prescription/$1');
$routes->match(['GET', 'POST'], 'Opd_prescription/create_opd_queue/(:num)', 'Opd_prescription::create_opd_queue/$1');

View File

@ -229,9 +229,10 @@ class Ipd extends BaseController
}
$builder = $this->db->table('patient_master p');
$builder->select('p.id, p.p_code, p.p_fname as patient_name, p.gender, p.age, p.dob, p.mphone1, p.mphone2');
$builder->select('p.id, p.p_code, p.p_fname, p.p_rname, p.gender, p.age, p.dob, p.mphone1, p.mphone2');
$builder->groupStart()
->like('p.p_fname', $termClean)
->orLike('p.p_rname', $termClean)
->orLike('p.p_code', $termClean)
->orLike('p.mphone1', $termClean)
->orLike('p.mphone2', $termClean)
@ -243,12 +244,15 @@ class Ipd extends BaseController
$activeIpds = [];
if (! empty($patientIds)) {
$rows = $this->db->table('ipd_master')
->select('id, p_id, coalesce(ipd_code, pid) as ipd_code, admission_type, ipd_status')
->select('id, p_id, ipd_code, admission_type, ipd_status')
->whereIn('p_id', $patientIds)
->where('ipd_status', 0)
->get()
->getResultArray();
foreach ($rows as $r) {
if (empty($r['ipd_code'])) {
$r['ipd_code'] = '#' . $r['id'];
}
$activeIpds[(int) $r['p_id']] = $r;
}
}
@ -256,6 +260,8 @@ class Ipd extends BaseController
foreach ($results as &$pt) {
$genderVal = (int) ($pt['gender'] ?? 0);
$pt['gender_text'] = ($genderVal === 1) ? 'Male' : (($genderVal === 2) ? 'Female' : 'Other');
$fullName = trim(($pt['p_fname'] ?? '') . ' ' . ($pt['p_rname'] ?? ''));
$pt['patient_name'] = $fullName !== '' ? $fullName : 'Unnamed';
$pt['active_ipd'] = $activeIpds[(int) $pt['id']] ?? null;
}
unset($pt);

View File

@ -55,7 +55,22 @@ class IpdPatient extends BaseController
'cleaning' => 0,
'total_admitted' => count($records),
'nursing_stations' => 0,
'count_ipd' => 0,
'count_daycare' => 0,
'count_emergency' => 0,
];
foreach ($records as $rec) {
$admType = strtolower(trim((string) ($rec->admission_type ?? 'ipd')));
if ($admType === 'emergency') {
$stats['count_emergency']++;
} elseif ($admType === 'daycare') {
$stats['count_daycare']++;
} else {
$stats['count_ipd']++;
}
}
$floors = [];
$wards = [];
@ -83,7 +98,7 @@ class IpdPatient extends BaseController
if ($this->db->tableExists('ipd_master')) {
$builder
->select('i.id as ipd_id, i.ipd_code, i.register_date, i.r_doc_name')
->select('i.id as ipd_id, i.ipd_code, i.register_date, i.r_doc_name, i.admission_type')
->join('ipd_master i', 'i.id = b.current_ipd_id AND i.ipd_status = 0', 'left', false);
if ($this->db->tableExists('patient_master')) {
@ -145,6 +160,7 @@ class IpdPatient extends BaseController
'doctor_name' => trim((string) ($row->r_doc_name ?? '')),
'ipd_code' => (string) ($row->ipd_code ?? ''),
'ipd_id' => (int) ($row->ipd_id ?? 0),
'admission_type' => strtolower(trim((string) ($row->admission_type ?? 'ipd'))),
'admit_date' => (string) ($row->register_date ?? ''),
'days_admitted' => $daysAdmitted,
'has_oxygen' => (bool) ($row->has_oxygen ?? false),

View File

@ -2535,6 +2535,18 @@ class Opd extends BaseController
return redirect()->to($url);
}
public function opd_day_care(int $opdId, int $mode = 0)
{
$printConfig = $this->resolveDoctorPrintConfigByField($opdId, 'opd_day_care_template', 'day_care_format');
$url = base_url('Opd/opd_lettre_pdf/' . (int) $opdId);
if ($printConfig['template'] !== '') {
$url .= '?template=' . urlencode($printConfig['template']);
} else {
$url .= '?template=day_care_format';
}
return redirect()->to($url);
}
/**
* @return array{layout:string,template:string}
*/
@ -2547,6 +2559,10 @@ class Opd extends BaseController
$fallbackLayout = 'full';
}
if (! $this->db->tableExists('doctor_master') || ! $this->db->fieldExists($fieldName, 'doctor_master')) {
return ['layout' => $fallbackLayout, 'template' => ''];
}
$query = $this->db->query(
'SELECT d.' . $fieldName . ' AS layout_field
FROM opd_master o

View File

@ -106,6 +106,7 @@ class Doctor extends BaseController
'opd_print_format' => 'tmpl_opd_print_format',
'opd_blank_print' => 'tmpl_opd_blank_print',
'opd_cont_paper_print' => 'tmpl_opd_cont_paper_print',
'opd_day_care_template' => 'tmpl_opd_day_care_template',
'rx_pre_print_letter_head_format' => 'tmpl_rx_pre_print_letter_head_format',
'rx_blank_letter_head' => 'tmpl_rx_blank_letter_head',
'rx_plain_paper' => 'tmpl_rx_plain_paper',
@ -229,6 +230,7 @@ class Doctor extends BaseController
'opd_print_format' => 'tmpl_opd_print_format',
'opd_blank_print' => 'tmpl_opd_blank_print',
'opd_cont_paper_print' => 'tmpl_opd_cont_paper_print',
'opd_day_care_template' => 'tmpl_opd_day_care_template',
'rx_pre_print_letter_head_format' => 'tmpl_rx_pre_print_letter_head_format',
'rx_blank_letter_head' => 'tmpl_rx_blank_letter_head',
'rx_plain_paper' => 'tmpl_rx_plain_paper',
@ -671,6 +673,7 @@ class Doctor extends BaseController
'opd_print_format',
'opd_blank_print',
'opd_cont_paper_print',
'opd_day_care_template',
'rx_pre_print_letter_head_format',
'rx_blank_letter_head',
'rx_plain_paper',
@ -681,6 +684,23 @@ class Doctor extends BaseController
}
$doctorFields = $this->db->getFieldNames('doctor_master') ?? [];
if (! in_array('opd_day_care_template', $doctorFields, true)) {
try {
$forge = \Config\Database::forge();
$forge->addColumn('doctor_master', [
'opd_day_care_template' => [
'type' => 'VARCHAR',
'constraint' => 100,
'null' => true,
'default' => null,
'after' => 'opd_cont_paper_print',
],
]);
$doctorFields[] = 'opd_day_care_template';
} catch (\Throwable $e) {
// Ignore if unable to add dynamically
}
}
$availableFields = array_values(array_intersect($allTemplateFields, $doctorFields));
$options = $this->collectStoredTemplateOptions();
@ -737,6 +757,19 @@ class Doctor extends BaseController
}
}
$fsDir = APPPATH . 'Views/billing/opd_templates/';
if (is_dir($fsDir)) {
$files = glob($fsDir . '*.html');
if ($files) {
foreach ($files as $file) {
$templateId = $this->normalizeTemplateId(basename($file, '.html'));
if ($templateId !== '') {
$options[] = $templateId;
}
}
}
}
return $options;
}

View File

@ -0,0 +1,35 @@
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class AddOpdDayCareTemplateToDoctorMaster extends Migration
{
public function up()
{
if ($this->db->tableExists('doctor_master')) {
$fields = [];
if (! $this->db->fieldExists('opd_day_care_template', 'doctor_master')) {
$fields['opd_day_care_template'] = [
'type' => 'VARCHAR',
'constraint' => 100,
'null' => true,
'default' => null,
'after' => 'opd_cont_paper_print',
];
}
if (! empty($fields)) {
$this->forge->addColumn('doctor_master', $fields);
}
}
}
public function down()
{
if ($this->db->tableExists('doctor_master') && $this->db->fieldExists('opd_day_care_template', 'doctor_master')) {
$this->forge->dropColumn('doctor_master', 'opd_day_care_template');
}
}
}

View File

@ -4919,6 +4919,17 @@
"Privileges": "select,insert,update,references",
"Comment": ""
},
"opd_day_care_template": {
"Field": "opd_day_care_template",
"Type": "varchar(100)",
"Collation": "utf8mb3_unicode_ci",
"Null": "YES",
"Key": "",
"Default": null,
"Extra": "",
"Privileges": "select,insert,update,references",
"Comment": ""
},
"opd_valid_no_days": {
"Field": "opd_valid_no_days",
"Type": "int",

View File

@ -134,6 +134,18 @@
</div>
<?php endif; ?>
<?php if (isset($templateFieldSet['opd_day_care_template'])) : ?>
<div class="col-md-4">
<label class="form-label">Daycare Template</label>
<select class="form-select" name="tmpl_opd_day_care_template">
<option value="">-- Select Template --</option>
<?php foreach ($templateOptions as $tmpl) : ?>
<option value="<?= esc($tmpl) ?>" <?= combo_checked($tmpl, strtolower(trim((string) ($formData['tmpl_opd_day_care_template'] ?? '')))) ?>><?= esc($tmpl) ?></option>
<?php endforeach; ?>
</select>
</div>
<?php endif; ?>
<?php if (isset($templateFieldSet['rx_pre_print_letter_head_format'])) : ?>
<div class="col-md-4">
<label class="form-label">Rx Pre-Print Letterhead</label>
@ -147,7 +159,7 @@
<?php endif; ?>
<?php if (isset($templateFieldSet['rx_blank_letter_head'])) : ?>
<div class="col-md-6">
<div class="col-md-4">
<label class="form-label">Rx Blank Letterhead</label>
<select class="form-select" name="tmpl_rx_blank_letter_head">
<option value="">-- Select Template --</option>

View File

@ -175,6 +175,18 @@ if (!empty($data) && !empty($data[0]) && !empty($data[0]->dob)) {
</div>
<?php endif; ?>
<?php if (isset($templateFieldSet['opd_day_care_template'])) : ?>
<div class="col-md-4">
<label class="form-label">Daycare Template</label>
<select class="form-select" name="tmpl_opd_day_care_template">
<option value="">-- Select Template --</option>
<?php foreach ($templateOptions as $tmpl) : ?>
<option value="<?= esc($tmpl) ?>" <?= combo_checked($tmpl, strtolower(trim((string) ($data[0]->opd_day_care_template ?? '')))) ?>><?= esc($tmpl) ?></option>
<?php endforeach; ?>
</select>
</div>
<?php endif; ?>
<?php if (isset($templateFieldSet['rx_pre_print_letter_head_format'])) : ?>
<div class="col-md-4">
<label class="form-label">Rx Pre-Print Letterhead</label>
@ -188,7 +200,7 @@ if (!empty($data) && !empty($data[0]) && !empty($data[0]->dob)) {
<?php endif; ?>
<?php if (isset($templateFieldSet['rx_blank_letter_head'])) : ?>
<div class="col-md-6">
<div class="col-md-4">
<label class="form-label">Rx Blank Letterhead</label>
<select class="form-select" name="tmpl_rx_blank_letter_head">
<option value="">-- Select Template --</option>

View File

@ -376,7 +376,7 @@ foreach ($placeholderGroups as $groupName => $groupValues) {
<div class="alert alert-info">
<strong>Old-style (recommended):</strong> save a name (example: <strong>opd_print_parcha_chamunda_hospital_ksp</strong>), then set that name in doctor master fields:<br>
<code>opd_print_format</code>, <code>opd_blank_print</code>, <code>rx_pre_print_letter_head_format</code>, <code>rx_blank_letter_head</code>, <code>rx_plain_paper</code>.<br><br>
<code>opd_print_format</code>, <code>opd_blank_print</code>, <code>opd_cont_paper_print</code>, <code>opd_day_care_template</code>, <code>rx_pre_print_letter_head_format</code>, <code>rx_blank_letter_head</code>, <code>rx_plain_paper</code>.<br><br>
<strong>Optional composed mode:</strong> use <code>compose_default</code> with type-specific parts.
</div>
</div>

View File

@ -0,0 +1,127 @@
<style>
@page {
margin-top: 3.5cm;
margin-bottom: 1.5cm;
margin-left: 0.7cm;
margin-right: 0.7cm;
margin-header: 0.5cm;
margin-footer: 0.5cm;
header: html_myHeader;
footer: html_myFooter;
}
body {
font-family: sans-serif;
font-size: 11px;
color: #111;
}
table {
border-collapse: collapse;
}
h1.doc-title {
font-size: 17px;
font-weight: bold;
text-align: center;
letter-spacing: 0.05em;
margin: 4px 0;
text-transform: uppercase;
}
.section-title {
font-size: 12px;
font-weight: bold;
color: #111;
border-bottom: 1px solid #333;
padding-bottom: 3px;
margin-top: 15px;
margin-bottom: 8px;
text-transform: uppercase;
}
.meta-table td {
padding: 2px 4px;
vertical-align: top;
font-size: 11px;
}
</style>
<htmlpageheader name="myHeader">
<table width="100%" style="font-size: 10px; border-bottom: 2px solid #333; padding-bottom: 4px;">
<tr>
<td style="width: 15%; vertical-align: middle;">
<img style="max-height: 55px; max-width: 90px;" src="{{H_logo_abs}}" />
</td>
<td style="width: 55%; vertical-align: top; text-align: center;">
<div style="font-size: 16px; font-weight: bold;">{{H_Name}}</div>
<div style="font-size: 10px; color: #444;">{{H_address_1}} {{H_address_2}}</div>
<div style="font-size: 10px; color: #444;">Phone: {{H_phone_No}}</div>
<div class="doc-title">DAY CARE DISCHARGE SUMMARY</div>
</td>
<td style="width: 30%; vertical-align: top; text-align: right;">
<div style="font-size: 13px; font-weight: bold;">Dr. {{doctor_name}}</div>
<div style="font-size: 10px; color: #333;">{{doctor_short_description}}</div>
<div style="font-size: 9px; color: #666;">{{SpecName}}</div>
</td>
</tr>
</table>
</htmlpageheader>
<htmlpagefooter name="myFooter">
<table width="100%" style="font-size: 9px; border-top: 1px solid #999; padding-top: 4px;">
<tr>
<td width="50%">
Printed on: {{print_time}} | OPD No: {{opd_no}}
</td>
<td width="50%" align="right">
Authorized Signature: _______________________
</td>
</tr>
</table>
</htmlpagefooter>
<table class="meta-table" width="100%" style="border-bottom: 1px solid #bbb; padding-bottom: 6px; margin-bottom: 8px;">
<tr>
<td width="50%">
<strong>UHID:</strong> {{uhid_no}}<br/>
<strong>Patient Name:</strong> <strong>{{pName}}</strong><br/>
<strong>Relation:</strong> {{pRelative}}<br/>
<strong>Sex / Age:</strong> {{age_sex}}<br/>
<strong>Mobile:</strong> {{phoneno}}<br/>
<strong>Address:</strong> {{p_address}}
</td>
<td width="50%">
<strong>Date:</strong> {{opd_date}}<br/>
<strong>OPD No:</strong> {{opd_no}}<br/>
<strong>Consultant:</strong> Dr. {{doctor_name}}<br/>
<strong>Admit Time:</strong> <span style="letter-spacing: 2px;">____________________</span><br/>
<strong>Discharge Time:</strong> <span style="letter-spacing: 2px;">____________________</span><br/>
<strong>Diagnosis:</strong> {{diagnosis}}
</td>
</tr>
</table>
<div class="section-title">Course / Treatment in the Hospital</div>
<div style="min-height: 140px; font-size: 11px; line-height: 1.6; padding: 4px 0;">
{{complaint}}
<br/><br/><br/><br/><br/><br/><br/>
</div>
<div class="section-title">Treatment Advice on Discharge</div>
<div style="min-height: 180px; font-size: 11px; line-height: 1.6; padding: 4px 0;">
{{medical}}
{{advice}}
<br/><br/><br/><br/><br/>
</div>
<div style="margin-top: 20px;">
<table width="100%" style="font-size: 11px;">
<tr>
<td width="50%" style="vertical-align: bottom;">
<strong>Next Follow-up / Visit:</strong> {{next_visit}}<br/>
<em>In case of any emergency, please visit the emergency department immediately.</em>
</td>
<td width="50%" align="right" style="vertical-align: bottom;">
<br/><br/>
<strong>Dr. {{doctor_name}}</strong><br/>
<span>Doctor's Signature</span>
</td>
</tr>
</table>
</div>

View File

@ -49,7 +49,12 @@
<div class="col-6 col-sm-4 col-md-2">
<div class="card border-0 shadow-sm text-center py-2 bg-info-subtle text-info-emphasis rounded-3 border border-info-subtle">
<div class="fs-4 fw-bold mb-0"><?= (int)($stats['total_admitted'] ?? 0) ?></div>
<div class="small">Admitted Patients</div>
<div class="small fw-semibold">Admitted Patients</div>
<div class="d-flex justify-content-center gap-1 mt-1 flex-wrap" style="font-size:10px;">
<span class="badge bg-primary px-1" title="Regular Inpatient (IPD)">IPD: <?= (int)($stats['count_ipd'] ?? 0) ?></span>
<span class="badge bg-warning text-dark px-1 border border-warning-subtle" title="Day Care Unit (< 24h)">Day Care: <?= (int)($stats['count_daycare'] ?? 0) ?></span>
<span class="badge bg-danger px-1" title="Emergency / Casualty">Cas: <?= (int)($stats['count_emergency'] ?? 0) ?></span>
</div>
</div>
</div>
</div>
@ -58,14 +63,22 @@
<div class="card shadow-sm border-0 mb-3">
<div class="card-body py-2 px-3">
<div class="row g-2 align-items-center">
<div class="col-md-4">
<div class="col-md-12 col-lg-3">
<div class="input-group input-group-sm">
<span class="input-group-text bg-light border-end-0"><i class="bi bi-search text-muted"></i></span>
<input type="text" class="form-control border-start-0" id="nursing_search_input" placeholder="Search patient name, IPD code, bed..." onkeyup="filterNursingBeds()">
<input type="text" class="form-control border-start-0" id="nursing_search_input" placeholder="Search patient, IPD code, bed..." onkeyup="filterNursingBeds()">
<button class="btn btn-outline-secondary" type="button" onclick="$('#nursing_search_input').val(''); filterNursingBeds();">&times;</button>
</div>
</div>
<div class="col-md-3">
<div class="col-sm-6 col-md-3 col-lg-2">
<select class="form-select form-select-sm" id="filter_admission_type" onchange="onAdmissionTypeDropdownChange()">
<option value="">All Admission Types</option>
<option value="ipd">Regular IPD (<?= (int)($stats['count_ipd'] ?? 0) ?>)</option>
<option value="daycare">Day Care Unit (<?= (int)($stats['count_daycare'] ?? 0) ?>)</option>
<option value="emergency">Emergency / Casualty (<?= (int)($stats['count_emergency'] ?? 0) ?>)</option>
</select>
</div>
<div class="col-sm-6 col-md-3 col-lg-2">
<select class="form-select form-select-sm" id="filter_nursing_station" onchange="filterNursingBeds()">
<option value="">All Nursing Stations</option>
<?php foreach (($nursingStations ?? []) as $st): ?>
@ -73,7 +86,7 @@
<?php endforeach; ?>
</select>
</div>
<div class="col-md-3">
<div class="col-sm-6 col-md-3 col-lg-2">
<select class="form-select form-select-sm" id="filter_nursing_ward" onchange="filterNursingBeds()">
<option value="">All Wards</option>
<?php foreach (($wards ?? []) as $wId => $wName): ?>
@ -81,7 +94,7 @@
<?php endforeach; ?>
</select>
</div>
<div class="col-md-2 text-end">
<div class="col-sm-6 col-md-3 col-lg-3 text-end">
<div class="btn-group btn-group-sm" role="group" aria-label="Status Filters">
<button type="button" class="btn btn-outline-secondary active btn-status-filter" data-status="all" onclick="setStatusFilter('all', this)">All</button>
<button type="button" class="btn btn-outline-success btn-status-filter" data-status="available" onclick="setStatusFilter('available', this)">Free</button>
@ -89,6 +102,25 @@
</div>
</div>
</div>
<!-- Quick Filter by Admission Type Row -->
<div class="d-flex align-items-center gap-2 flex-wrap pt-2 border-top mt-2">
<span class="small fw-bold text-muted text-uppercase" style="font-size:11px; letter-spacing:0.5px;">Quick Filter by Type:</span>
<div class="btn-group btn-group-sm" role="group" aria-label="Admission Type Quick Filters">
<button type="button" class="btn btn-secondary btn-sm active btn-type-filter" data-type="all" onclick="setTypeFilter('all', this)">
All (<?= (int)($stats['total_admitted'] ?? 0) ?>)
</button>
<button type="button" class="btn btn-outline-primary btn-sm btn-type-filter" data-type="ipd" onclick="setTypeFilter('ipd', this)">
<i class="bi bi-hospital me-1"></i>Regular IPD (<?= (int)($stats['count_ipd'] ?? 0) ?>)
</button>
<button type="button" class="btn btn-outline-warning text-dark btn-sm btn-type-filter" data-type="daycare" onclick="setTypeFilter('daycare', this)">
<i class="bi bi-clock-history me-1"></i>Day Care (< 24h) (<?= (int)($stats['count_daycare'] ?? 0) ?>)
</button>
<button type="button" class="btn btn-outline-danger btn-sm btn-type-filter" data-type="emergency" onclick="setTypeFilter('emergency', this)">
<i class="bi bi-ambulance me-1"></i>Emergency / Casualty (<?= (int)($stats['count_emergency'] ?? 0) ?>)
</button>
</div>
</div>
</div>
</div>
@ -173,10 +205,13 @@
$statusLabel = ucfirst($bed['bed_status']);
}
$searchText = strtolower($bed['bed_number'] . ' ' . $bed['bed_code'] . ' ' . $bed['patient_name'] . ' ' . $bed['doctor_name'] . ' ' . $bed['ipd_code'] . ' ' . $wardInfo['ward_name'] . ' ' . $bed['station_name']);
$admType = strtolower(trim((string)($bed['admission_type'] ?? 'ipd')));
$admTypeLabel = ($admType === 'emergency') ? 'emergency casualty' : (($admType === 'daycare') ? 'daycare day care' : 'ipd inpatient regular');
$searchText = strtolower($bed['bed_number'] . ' ' . $bed['bed_code'] . ' ' . $bed['patient_name'] . ' ' . $bed['doctor_name'] . ' ' . $bed['ipd_code'] . ' ' . $wardInfo['ward_name'] . ' ' . $bed['station_name'] . ' ' . $admTypeLabel);
?>
<div class="col-6 col-sm-4 col-md-3 col-lg-2 bed-card-col"
data-status="<?= esc($bed['bed_status']) ?>"
data-admission-type="<?= esc($admType) ?>"
data-ward="<?= esc($wardInfo['ward_name']) ?>"
data-station="<?= esc($bed['station_name']) ?>"
data-search="<?= esc($searchText) ?>">
@ -196,11 +231,26 @@
<?= esc($bed['doctor_name']) ?>
</div>
<?php endif; ?>
<?php if ($bed['days_admitted'] !== null): ?>
<span class="badge bg-light text-dark border border-secondary-subtle mt-1" style="font-size: 10px;">
<i class="bi bi-clock-history me-1"></i><?= $bed['days_admitted'] ?> days
</span>
<?php endif; ?>
<div class="d-flex justify-content-center align-items-center gap-1 flex-wrap mt-1">
<?php if ($bed['days_admitted'] !== null): ?>
<span class="badge bg-light text-dark border border-secondary-subtle" style="font-size: 10px;">
<i class="bi bi-clock-history me-1"></i><?= $bed['days_admitted'] ?>d
</span>
<?php endif; ?>
<?php if ($admType === 'emergency'): ?>
<span class="badge bg-danger" style="font-size: 10px;" title="Emergency / Casualty">
<i class="bi bi-ambulance me-1"></i>Casualty
</span>
<?php elseif ($admType === 'daycare'): ?>
<span class="badge bg-warning text-dark border border-warning-subtle" style="font-size: 10px;" title="Day Care Unit (< 24h)">
<i class="bi bi-clock-history me-1"></i>Day Care
</span>
<?php else: ?>
<span class="badge bg-primary-subtle text-primary border border-primary-subtle" style="font-size: 10px;" title="Regular Inpatient (IPD)">
<i class="bi bi-hospital me-1"></i>IPD
</span>
<?php endif; ?>
</div>
</div>
<?php else: ?>
<div class="my-2 text-success small fw-semibold">
@ -252,6 +302,7 @@
<th>IPD Code</th>
<th>UHID</th>
<th>Patient Name</th>
<th>Type</th>
<th>Bed &amp; Ward Location</th>
<th>Doctor</th>
<th>Admit Date</th>
@ -262,17 +313,27 @@
<tbody>
<?php if (empty($records)): ?>
<tr>
<td colspan="9" class="text-center py-4 text-muted">
<td colspan="10" class="text-center py-4 text-muted">
<i class="bi bi-person-x fs-3 d-block mb-1"></i> No current IPD admissions found.
</td>
</tr>
<?php else: ?>
<?php foreach ($records as $idx => $row) : ?>
<tr>
<?php $rowType = strtolower(trim((string) ($row->admission_type ?? 'ipd'))); ?>
<tr class="table-row-admission" data-admission-type="<?= esc($rowType) ?>">
<td class="fw-bold text-secondary ps-3"><?= $idx + 1 ?></td>
<td><span class="badge bg-light text-dark border"><?= esc($row->ipd_code ?? '') ?></span></td>
<td><code><?= esc($row->p_code ?? '') ?></code></td>
<td class="fw-semibold text-primary"><?= esc(trim((string) (($row->p_fname ?? '') . ' ' . ($row->p_rname ?? '')))) ?></td>
<td>
<?php if ($rowType === 'emergency'): ?>
<span class="badge bg-danger"><i class="bi bi-ambulance me-1"></i>Casualty</span>
<?php elseif ($rowType === 'daycare'): ?>
<span class="badge bg-warning text-dark border border-warning-subtle"><i class="bi bi-clock-history me-1"></i>Day Care</span>
<?php else: ?>
<span class="badge bg-primary"><i class="bi bi-hospital me-1"></i>Regular IPD</span>
<?php endif; ?>
</td>
<td>
<span class="badge bg-info-subtle text-info-emphasis border border-info-subtle">
<i class="bi bi-hospital me-1"></i><?= esc($row->Bed_Desc ?? '') ?>
@ -298,6 +359,7 @@
<script>
var currentStatusFilter = 'all';
var currentTypeFilter = 'all';
function switchNursingView(mode) {
if (mode === 'grid') {
@ -319,7 +381,45 @@ function switchNursingView(mode) {
function setStatusFilter(status, btn) {
currentStatusFilter = status;
$('.btn-status-filter').removeClass('active btn-secondary btn-success btn-danger').addClass('btn-outline-secondary');
$(btn).removeClass('btn-outline-secondary').addClass('active');
if (status === 'available') {
$(btn).removeClass('btn-outline-secondary').addClass('active btn-success');
} else if (status === 'occupied') {
$(btn).removeClass('btn-outline-secondary').addClass('active btn-danger');
} else {
$(btn).removeClass('btn-outline-secondary').addClass('active btn-secondary');
}
filterNursingBeds();
}
function setTypeFilter(type, btn) {
currentTypeFilter = type;
$('#filter_admission_type').val(type === 'all' ? '' : type);
$('.btn-type-filter').removeClass('active btn-secondary btn-primary btn-warning text-dark btn-danger').addClass('btn-outline-secondary');
if (type === 'ipd') {
$(btn).removeClass('btn-outline-secondary').addClass('active btn-primary');
} else if (type === 'daycare') {
$(btn).removeClass('btn-outline-secondary').addClass('active btn-warning text-dark');
} else if (type === 'emergency') {
$(btn).removeClass('btn-outline-secondary').addClass('active btn-danger');
} else {
$(btn).removeClass('btn-outline-secondary').addClass('active btn-secondary');
}
filterNursingBeds();
}
function onAdmissionTypeDropdownChange() {
var val = $('#filter_admission_type').val() || 'all';
currentTypeFilter = val;
$('.btn-type-filter').removeClass('active btn-secondary btn-primary btn-warning text-dark btn-danger').addClass('btn-outline-secondary');
if (val === 'ipd') {
$('.btn-type-filter[data-type="ipd"]').removeClass('btn-outline-secondary').addClass('active btn-primary');
} else if (val === 'daycare') {
$('.btn-type-filter[data-type="daycare"]').removeClass('btn-outline-secondary').addClass('active btn-warning text-dark');
} else if (val === 'emergency') {
$('.btn-type-filter[data-type="emergency"]').removeClass('btn-outline-secondary').addClass('active btn-danger');
} else {
$('.btn-type-filter[data-type="all"]').removeClass('btn-outline-secondary').addClass('active btn-secondary');
}
filterNursingBeds();
}
@ -327,10 +427,13 @@ function filterNursingBeds() {
var search = ($('#nursing_search_input').val() || '').toLowerCase().trim();
var station = ($('#filter_nursing_station').val() || '').toLowerCase().trim();
var ward = ($('#filter_nursing_ward').val() || '').toLowerCase().trim();
var admType = currentTypeFilter;
// Filter Visual Bed Grid
$('.bed-card-col').each(function() {
var $col = $(this);
var bStatus = ($col.data('status') || '').toLowerCase();
var bAdmType = ($col.data('admission-type') || '').toLowerCase();
var bWard = ($col.data('ward') || '').toLowerCase();
var bStation = ($col.data('station') || '').toLowerCase();
var bSearch = ($col.data('search') || '').toLowerCase();
@ -340,13 +443,19 @@ function filterNursingBeds() {
var matchWard = (ward === '' || bWard.indexOf(ward) !== -1);
var matchStatus = (currentStatusFilter === 'all' || bStatus === currentStatusFilter);
if (matchSearch && matchStation && matchWard && matchStatus) {
var matchAdmType = true;
if (admType !== 'all' && admType !== '') {
matchAdmType = (bStatus === 'occupied' && bAdmType === admType);
}
if (matchSearch && matchStation && matchWard && matchStatus && matchAdmType) {
$col.removeClass('d-none');
} else {
$col.addClass('d-none');
}
});
// Hide empty ward blocks
$('.ward-block-card').each(function() {
var $card = $(this);
var visibleBeds = $card.find('.bed-card-col:not(.d-none)').length;
@ -356,5 +465,21 @@ function filterNursingBeds() {
$card.removeClass('d-none');
}
});
// Filter Table View rows
$('#ipdNursingListTable tbody tr.table-row-admission').each(function() {
var $tr = $(this);
var rowType = ($tr.data('admission-type') || '').toLowerCase();
var rowSearch = $tr.text().toLowerCase();
var matchSearch = (search === '' || rowSearch.indexOf(search) !== -1);
var matchType = (admType === 'all' || admType === '' || rowType === admType);
if (matchSearch && matchType) {
$tr.removeClass('d-none');
} else {
$tr.addClass('d-none');
}
});
}
</script>

View File

@ -238,18 +238,7 @@ if (! $canChargesSettings && $user && method_exists($user, 'inGroup')) {
<span>IPD Billing</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link collapsed" href="javascript:load_form('<?= base_url('/billing/ipd/admit?type=emergency') ?>','Emergency / Casualty Admission')">
<i class="bi bi-ambulance text-danger"></i>
<span>Emergency / Casualty</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link collapsed" href="javascript:load_form('<?= base_url('/billing/ipd/admit?type=daycare') ?>','Day Care Admission')">
<i class="bi bi-clock-history text-warning"></i>
<span>Day Care Unit</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link collapsed" href="javascript:load_form('<?= base_url('Orgcase/search_all') ?>','Org. OPD\'s Invoice')">
<i class="bi bi-receipt-cutoff"></i>
@ -348,12 +337,7 @@ if (! $canChargesSettings && $user && method_exists($user, 'inGroup')) {
<?php if ($canIpdNursing || $canIpdDischarge || $canIpdOt) { ?>
<li class="nav-heading">In-Patient & Nursing Care</li>
<?php if ($canIpdNursing) { ?>
<li class="nav-item">
<a class="nav-link collapsed" href="javascript:load_form('<?= base_url('billing/ipd/admit') ?>','Admit Patient Desk')">
<i class="bi bi-person-plus text-success"></i>
<span>Admit Patient Desk</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link collapsed" href="javascript:load_form('<?= base_url('/ipd/patient') ?>','IPD Patient List')">
<i class="bi bi-person-vcard"></i>