478 lines
24 KiB
HTML
478 lines
24 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}Bed Management{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="d-flex align-items-center mb-3">
|
|
<div>
|
|
<ol class="breadcrumb">
|
|
<li class="breadcrumb-item"><a href="{% url 'inpatients:dashboard' %}">Inpatients</a></li>
|
|
<li class="breadcrumb-item active">Bed Management</li>
|
|
</ol>
|
|
<h1 class="page-header mb-0">Bed Management</h1>
|
|
</div>
|
|
<div class="ms-auto">
|
|
<div class="btn-group">
|
|
<a href="{% url 'inpatients:bed_form' %}" class="btn btn-primary">
|
|
<i class="fas fa-plus me-2"></i>Add Bed
|
|
</a>
|
|
<button type="button" class="btn btn-outline-secondary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown">
|
|
<span class="visually-hidden">Toggle Dropdown</span>
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#" onclick="exportBeds()">
|
|
<i class="fas fa-download me-2"></i>Export List
|
|
</a></li>
|
|
<li><a class="dropdown-item" href="#" onclick="printBeds()">
|
|
<i class="fas fa-print me-2"></i>Print List
|
|
</a></li>
|
|
<li><hr class="dropdown-divider"></li>
|
|
<li><a class="dropdown-item" href="#" onclick="bulkUpdate()">
|
|
<i class="fas fa-edit me-2"></i>Bulk Update
|
|
</a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Statistics Cards -->
|
|
<div class="row mb-4">
|
|
<div class="col-xl-3 col-md-6">
|
|
<div class="card bg-primary text-white">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center">
|
|
<div class="flex-grow-1">
|
|
<div class="fs-6 text-white-75">Total Beds</div>
|
|
<div class="fs-2 fw-bold">{{ total_beds|default:0 }}</div>
|
|
</div>
|
|
<div class="flex-shrink-0">
|
|
<i class="fas fa-bed fa-2x text-white-50"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-xl-3 col-md-6">
|
|
<div class="card bg-success text-white">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center">
|
|
<div class="flex-grow-1">
|
|
<div class="fs-6 text-white-75">Available</div>
|
|
<div class="fs-2 fw-bold">{{ available_beds|default:0 }}</div>
|
|
</div>
|
|
<div class="flex-shrink-0">
|
|
<i class="fas fa-check-circle fa-2x text-white-50"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-xl-3 col-md-6">
|
|
<div class="card bg-warning text-white">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center">
|
|
<div class="flex-grow-1">
|
|
<div class="fs-6 text-white-75">Occupied</div>
|
|
<div class="fs-2 fw-bold">{{ occupied_beds|default:0 }}</div>
|
|
</div>
|
|
<div class="flex-shrink-0">
|
|
<i class="fas fa-user fa-2x text-white-50"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-xl-3 col-md-6">
|
|
<div class="card bg-info text-white">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center">
|
|
<div class="flex-grow-1">
|
|
<div class="fs-6 text-white-75">Occupancy Rate</div>
|
|
<div class="fs-2 fw-bold">{{ occupancy_rate|default:0 }}%</div>
|
|
</div>
|
|
<div class="flex-shrink-0">
|
|
<i class="fas fa-chart-pie fa-2x text-white-50"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">
|
|
<i class="fas fa-bed me-2"></i>
|
|
Bed List
|
|
</h4>
|
|
<div class="card-toolbar">
|
|
<div class="d-flex align-items-center">
|
|
<!-- View Toggle -->
|
|
<div class="btn-group btn-group-sm me-3" role="group">
|
|
<input type="radio" class="btn-check" name="viewType" id="gridView" autocomplete="off" checked>
|
|
<label class="btn btn-outline-secondary" for="gridView">
|
|
<i class="fas fa-th"></i>
|
|
</label>
|
|
<input type="radio" class="btn-check" name="viewType" id="listView" autocomplete="off">
|
|
<label class="btn btn-outline-secondary" for="listView">
|
|
<i class="fas fa-list"></i>
|
|
</label>
|
|
</div>
|
|
|
|
<!-- Filters -->
|
|
<div class="d-flex align-items-center">
|
|
<select class="form-select form-select-sm me-2" id="wardFilter" onchange="filterBeds()">
|
|
<option value="">All Wards</option>
|
|
{% for ward in wards %}
|
|
<option value="{{ ward.id }}">{{ ward.name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
<select class="form-select form-select-sm me-2" id="statusFilter" onchange="filterBeds()">
|
|
<option value="">All Status</option>
|
|
<option value="available">Available</option>
|
|
<option value="occupied">Occupied</option>
|
|
<option value="maintenance">Maintenance</option>
|
|
<option value="cleaning">Cleaning</option>
|
|
</select>
|
|
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="clearFilters()">
|
|
<i class="fas fa-times"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<!-- Grid View -->
|
|
<div id="gridViewContent">
|
|
{% if object_list %}
|
|
<div class="row" id="bedGrid">
|
|
{% for bed in object_list %}
|
|
<div class="col-xl-3 col-lg-4 col-md-6 mb-4 bed-item"
|
|
data-ward="{{ bed.ward.id }}"
|
|
data-status="{{ bed.status }}"
|
|
data-bed-type="{{ bed.bed_type }}">
|
|
<div class="card h-100 bed-card {% if bed.status == 'occupied' %}border-warning{% elif bed.status == 'available' %}border-success{% elif bed.status == 'maintenance' %}border-danger{% else %}border-info{% endif %}">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<h6 class="card-title mb-0">
|
|
<i class="fas fa-bed me-2"></i>
|
|
Bed {{ bed.bed_number }}
|
|
</h6>
|
|
<span class="badge bg-{% if bed.status == 'available' %}success{% elif bed.status == 'occupied' %}warning{% elif bed.status == 'maintenance' %}danger{% else %}info{% endif %}">
|
|
{{ bed.get_status_display }}
|
|
</span>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-2">
|
|
<small class="text-muted">Ward:</small>
|
|
<div class="fw-bold">{{ bed.ward.name }}</div>
|
|
</div>
|
|
<div class="mb-2">
|
|
<small class="text-muted">Room:</small>
|
|
<div>{{ bed.room_number|default:"Not assigned" }}</div>
|
|
</div>
|
|
<div class="mb-2">
|
|
<small class="text-muted">Type:</small>
|
|
<div>{{ bed.get_bed_type_display }}</div>
|
|
</div>
|
|
|
|
{% if bed.current_patient %}
|
|
<div class="mb-2">
|
|
<small class="text-muted">Patient:</small>
|
|
<div class="fw-bold text-primary">
|
|
<a href="{% url 'patients:patient_detail' bed.current_patient.pk %}">
|
|
{{ bed.current_patient.get_full_name }}
|
|
</a>
|
|
</div>
|
|
<small class="text-muted">{{ bed.current_patient.medical_record_number }}</small>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="mb-3">
|
|
{% if bed.has_oxygen %}
|
|
<span class="badge bg-info me-1">O2</span>
|
|
{% endif %}
|
|
{% if bed.has_suction %}
|
|
<span class="badge bg-info me-1">Suction</span>
|
|
{% endif %}
|
|
{% if bed.has_monitor %}
|
|
<span class="badge bg-info me-1">Monitor</span>
|
|
{% endif %}
|
|
{% if bed.is_isolation %}
|
|
<span class="badge bg-warning me-1">Isolation</span>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="card-footer">
|
|
<div class="d-flex justify-content-between">
|
|
<a href="{% url 'inpatients:bed_detail' bed.pk %}" class="btn btn-sm btn-outline-primary">
|
|
<i class="fas fa-eye me-1"></i>View
|
|
</a>
|
|
<div class="btn-group">
|
|
<a href="{% url 'inpatients:bed_form' bed.pk %}" class="btn btn-sm btn-outline-secondary">
|
|
<i class="fas fa-edit"></i>
|
|
</a>
|
|
<button type="button" class="btn btn-sm btn-outline-secondary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown">
|
|
<span class="visually-hidden">Toggle Dropdown</span>
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#" onclick="updateBedStatus('{{ bed.pk }}', 'available')">
|
|
<i class="fas fa-check text-success me-2"></i>Mark Available
|
|
</a></li>
|
|
<li><a class="dropdown-item" href="#" onclick="updateBedStatus('{{ bed.pk }}', 'maintenance')">
|
|
<i class="fas fa-tools text-warning me-2"></i>Maintenance
|
|
</a></li>
|
|
<li><a class="dropdown-item" href="#" onclick="updateBedStatus('{{ bed.pk }}', 'cleaning')">
|
|
<i class="fas fa-broom text-info me-2"></i>Cleaning
|
|
</a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<div class="text-center text-muted py-5">
|
|
<i class="fas fa-bed fa-3x mb-3"></i>
|
|
<h5>No Beds Found</h5>
|
|
<p>No beds match your current filters. Try adjusting your search criteria.</p>
|
|
<a href="{% url 'inpatients:bed_form' %}" class="btn btn-primary">
|
|
<i class="fas fa-plus me-2"></i>Add First Bed
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- List View -->
|
|
<div id="listViewContent" style="display: none;">
|
|
{% if object_list %}
|
|
<div class="table-responsive">
|
|
<table class="table table-hover" id="bedTable">
|
|
<thead>
|
|
<tr>
|
|
<th>
|
|
<input type="checkbox" id="selectAll" onchange="toggleSelectAll()">
|
|
</th>
|
|
<th>Bed Number</th>
|
|
<th>Ward</th>
|
|
<th>Room</th>
|
|
<th>Type</th>
|
|
<th>Status</th>
|
|
<th>Current Patient</th>
|
|
<th>Features</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for bed in object_list %}
|
|
<tr class="bed-row"
|
|
data-ward="{{ bed.ward.id }}"
|
|
data-status="{{ bed.status }}"
|
|
data-bed-type="{{ bed.bed_type }}">
|
|
<td>
|
|
<input type="checkbox" class="bed-checkbox" value="{{ bed.pk }}">
|
|
</td>
|
|
<td>
|
|
<a href="{% url 'inpatients:bed_detail' bed.pk %}" class="fw-bold">
|
|
{{ bed.bed_number }}
|
|
</a>
|
|
</td>
|
|
<td>{{ bed.ward.name }}</td>
|
|
<td>{{ bed.room_number|default:"-" }}</td>
|
|
<td>{{ bed.get_bed_type_display }}</td>
|
|
<td>
|
|
<span class="badge bg-{% if bed.status == 'available' %}success{% elif bed.status == 'occupied' %}warning{% elif bed.status == 'maintenance' %}danger{% else %}info{% endif %}">
|
|
{{ bed.get_status_display }}
|
|
</span>
|
|
</td>
|
|
<td>
|
|
{% if bed.current_patient %}
|
|
<a href="{% url 'patients:patient_detail' bed.current_patient.pk %}">
|
|
{{ bed.current_patient.get_full_name }}
|
|
</a>
|
|
<div class="small text-muted">{{ bed.current_patient.medical_record_number }}</div>
|
|
{% else %}
|
|
<span class="text-muted">-</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
{% if bed.has_oxygen %}
|
|
<span class="badge bg-info me-1">O2</span>
|
|
{% endif %}
|
|
{% if bed.has_suction %}
|
|
<span class="badge bg-info me-1">Suction</span>
|
|
{% endif %}
|
|
{% if bed.has_monitor %}
|
|
<span class="badge bg-info me-1">Monitor</span>
|
|
{% endif %}
|
|
{% if bed.is_isolation %}
|
|
<span class="badge bg-warning me-1">Isolation</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
<div class="btn-group btn-group-sm">
|
|
<a href="{% url 'inpatients:bed_detail' bed.pk %}" class="btn btn-outline-primary">
|
|
<i class="fas fa-eye"></i>
|
|
</a>
|
|
<a href="{% url 'inpatients:bed_form' bed.pk %}" class="btn btn-outline-secondary">
|
|
<i class="fas fa-edit"></i>
|
|
</a>
|
|
<button type="button" class="btn btn-outline-danger" onclick="deleteBed('{{ bed.pk }}')">
|
|
<i class="fas fa-trash"></i>
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- Pagination -->
|
|
{% if is_paginated %}
|
|
<nav aria-label="Bed pagination">
|
|
<ul class="pagination justify-content-center">
|
|
{% if page_obj.has_previous %}
|
|
<li class="page-item">
|
|
<a class="page-link" href="?page=1">« First</a>
|
|
</li>
|
|
<li class="page-item">
|
|
<a class="page-link" href="?page={{ page_obj.previous_page_number }}">Previous</a>
|
|
</li>
|
|
{% endif %}
|
|
|
|
<li class="page-item active">
|
|
<span class="page-link">
|
|
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
|
|
</span>
|
|
</li>
|
|
|
|
{% if page_obj.has_next %}
|
|
<li class="page-item">
|
|
<a class="page-link" href="?page={{ page_obj.next_page_number }}">Next</a>
|
|
</li>
|
|
<li class="page-item">
|
|
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}">Last »</a>
|
|
</li>
|
|
{% endif %}
|
|
</ul>
|
|
</nav>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// View toggle functionality
|
|
const gridViewRadio = document.getElementById('gridView');
|
|
const listViewRadio = document.getElementById('listView');
|
|
const gridViewContent = document.getElementById('gridViewContent');
|
|
const listViewContent = document.getElementById('listViewContent');
|
|
|
|
gridViewRadio.addEventListener('change', function() {
|
|
if (this.checked) {
|
|
gridViewContent.style.display = 'block';
|
|
listViewContent.style.display = 'none';
|
|
}
|
|
});
|
|
|
|
listViewRadio.addEventListener('change', function() {
|
|
if (this.checked) {
|
|
gridViewContent.style.display = 'none';
|
|
listViewContent.style.display = 'block';
|
|
}
|
|
});
|
|
});
|
|
|
|
function filterBeds() {
|
|
const wardFilter = document.getElementById('wardFilter').value;
|
|
const statusFilter = document.getElementById('statusFilter').value;
|
|
|
|
// Grid view filtering
|
|
const bedItems = document.querySelectorAll('.bed-item');
|
|
bedItems.forEach(item => {
|
|
const wardMatch = !wardFilter || item.dataset.ward === wardFilter;
|
|
const statusMatch = !statusFilter || item.dataset.status === statusFilter;
|
|
|
|
if (wardMatch && statusMatch) {
|
|
item.style.display = 'block';
|
|
} else {
|
|
item.style.display = 'none';
|
|
}
|
|
});
|
|
|
|
// List view filtering
|
|
const bedRows = document.querySelectorAll('.bed-row');
|
|
bedRows.forEach(row => {
|
|
const wardMatch = !wardFilter || row.dataset.ward === wardFilter;
|
|
const statusMatch = !statusFilter || row.dataset.status === statusFilter;
|
|
|
|
if (wardMatch && statusMatch) {
|
|
row.style.display = '';
|
|
} else {
|
|
row.style.display = 'none';
|
|
}
|
|
});
|
|
}
|
|
|
|
function clearFilters() {
|
|
document.getElementById('wardFilter').value = '';
|
|
document.getElementById('statusFilter').value = '';
|
|
filterBeds();
|
|
}
|
|
|
|
function toggleSelectAll() {
|
|
const selectAll = document.getElementById('selectAll');
|
|
const checkboxes = document.querySelectorAll('.bed-checkbox');
|
|
|
|
checkboxes.forEach(checkbox => {
|
|
checkbox.checked = selectAll.checked;
|
|
});
|
|
}
|
|
|
|
function updateBedStatus(bedId, status) {
|
|
if (confirm(`Are you sure you want to mark this bed as ${status}?`)) {
|
|
// In a real implementation, this would submit via AJAX
|
|
console.log(`Updating bed ${bedId} to status ${status}`);
|
|
location.reload();
|
|
}
|
|
}
|
|
|
|
function deleteBed(bedId) {
|
|
if (confirm('Are you sure you want to delete this bed? This action cannot be undone.')) {
|
|
// In a real implementation, this would submit via AJAX
|
|
window.location.href = `/inpatients/beds/${bedId}/delete/`;
|
|
}
|
|
}
|
|
|
|
function exportBeds() {
|
|
// In a real implementation, this would export the bed list
|
|
alert('Export functionality would be implemented here.');
|
|
}
|
|
|
|
function printBeds() {
|
|
window.print();
|
|
}
|
|
|
|
function bulkUpdate() {
|
|
const selectedBeds = document.querySelectorAll('.bed-checkbox:checked');
|
|
if (selectedBeds.length === 0) {
|
|
alert('Please select at least one bed to update.');
|
|
return;
|
|
}
|
|
|
|
// In a real implementation, this would open a bulk update modal
|
|
alert(`Bulk update functionality for ${selectedBeds.length} beds would be implemented here.`);
|
|
}
|
|
</script>
|
|
{% endblock %}
|
|
|