2025-08-12 13:33:25 +03:00

507 lines
24 KiB
HTML

{% extends "base.html" %}
{% load static %}
{% block title %}Operating Rooms - {{ block.super }}{% endblock %}
{% block content %}
<div class="container-fluid">
<!-- Page Header -->
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h1 class="h3 mb-1">
<i class="fas fa-procedures me-2"></i>Operating Rooms
</h1>
<nav aria-label="breadcrumb">
<ol class="breadcrumb mb-0">
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
<li class="breadcrumb-item"><a href="{% url 'operating_theatre:dashboard' %}">Operating Theatre</a></li>
<li class="breadcrumb-item active">Operating Rooms</li>
</ol>
</nav>
</div>
<div class="btn-group">
<a href="{% url 'operating_theatre:operating_room_create' %}" class="btn btn-primary">
<i class="fas fa-plus me-2"></i>Add Operating Room
</a>
<div class="btn-group">
<button type="button" class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown">
<i class="fas fa-cog me-2"></i>Actions
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#" onclick="exportData('csv')">
<i class="fas fa-file-csv me-2"></i>Export CSV
</a></li>
<li><a class="dropdown-item" href="#" onclick="exportData('pdf')">
<i class="fas fa-file-pdf me-2"></i>Export PDF
</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#" onclick="bulkStatusUpdate()">
<i class="fas fa-edit me-2"></i>Bulk Status Update
</a></li>
</ul>
</div>
</div>
</div>
<!-- Statistics Cards -->
<div class="row mb-4" hx-get="{% url 'operating_theatre:operating_theatre_stats' %}" hx-trigger="load, every 30s">
<div class="col-xl-3 col-md-6 mb-3">
<div class="card bg-gradient-primary text-white">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="h2 mb-1">{{ total_rooms|default:0 }}</div>
<div class="small">Total Rooms</div>
</div>
<div class="fa-3x opacity-50">
<i class="fas fa-procedures"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6 mb-3">
<div class="card bg-gradient-success text-white">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="h2 mb-1">{{ available_rooms|default:0 }}</div>
<div class="small">Available</div>
</div>
<div class="fa-3x opacity-50">
<i class="fas fa-check-circle"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6 mb-3">
<div class="card bg-gradient-warning text-white">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="h2 mb-1">{{ occupied_rooms|default:0 }}</div>
<div class="small">Occupied</div>
</div>
<div class="fa-3x opacity-50">
<i class="fas fa-user-md"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6 mb-3">
<div class="card bg-gradient-danger text-white">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="h2 mb-1">{{ maintenance_rooms|default:0 }}</div>
<div class="small">Maintenance</div>
</div>
<div class="fa-3x opacity-50">
<i class="fas fa-tools"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Filters and Search -->
<div class="card mb-4">
<div class="card-body">
<form method="get" class="row g-3" id="filterForm">
<div class="col-md-3">
<label for="search" class="form-label">Search</label>
<input type="text" class="form-control" id="search" name="search"
value="{{ request.GET.search }}" placeholder="Room number, name...">
</div>
<div class="col-md-2">
<label for="status" class="form-label">Status</label>
<select class="form-select" id="status" name="status">
<option value="">All Statuses</option>
<option value="AVAILABLE" {% if request.GET.status == 'AVAILABLE' %}selected{% endif %}>Available</option>
<option value="OCCUPIED" {% if request.GET.status == 'OCCUPIED' %}selected{% endif %}>Occupied</option>
<option value="CLEANING" {% if request.GET.status == 'CLEANING' %}selected{% endif %}>Cleaning</option>
<option value="MAINTENANCE" {% if request.GET.status == 'MAINTENANCE' %}selected{% endif %}>Maintenance</option>
<option value="OUT_OF_ORDER" {% if request.GET.status == 'OUT_OF_ORDER' %}selected{% endif %}>Out of Order</option>
</select>
</div>
<div class="col-md-2">
<label for="room_type" class="form-label">Type</label>
<select class="form-select" id="room_type" name="room_type">
<option value="">All Types</option>
<option value="GENERAL" {% if request.GET.room_type == 'GENERAL' %}selected{% endif %}>General Surgery</option>
<option value="CARDIAC" {% if request.GET.room_type == 'CARDIAC' %}selected{% endif %}>Cardiac Surgery</option>
<option value="NEURO" {% if request.GET.room_type == 'NEURO' %}selected{% endif %}>Neurosurgery</option>
<option value="ORTHOPEDIC" {% if request.GET.room_type == 'ORTHOPEDIC' %}selected{% endif %}>Orthopedic</option>
<option value="TRAUMA" {% if request.GET.room_type == 'TRAUMA' %}selected{% endif %}>Trauma</option>
<option value="EMERGENCY" {% if request.GET.room_type == 'EMERGENCY' %}selected{% endif %}>Emergency</option>
</select>
</div>
<div class="col-md-2">
<label for="floor" class="form-label">Floor</label>
<select class="form-select" id="floor" name="floor">
<option value="">All Floors</option>
{% for floor in available_floors %}
<option value="{{ floor }}" {% if request.GET.floor == floor|stringformat:"s" %}selected{% endif %}>Floor {{ floor }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-3">
<label class="form-label">&nbsp;</label>
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">
<i class="fas fa-search me-2"></i>Filter
</button>
<a href="{% url 'operating_theatre:operating_room_list' %}" class="btn btn-outline-secondary">
<i class="fas fa-times me-2"></i>Clear
</a>
</div>
</div>
</form>
</div>
</div>
<!-- Operating Rooms List -->
<div class="card">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h5 class="mb-0">
<i class="fas fa-list me-2"></i>Operating Rooms
<span class="badge bg-secondary ms-2">{{ page_obj.paginator.count }} total</span>
</h5>
<div class="d-flex gap-2">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="autoRefresh">
<label class="form-check-label" for="autoRefresh">Auto Refresh</label>
</div>
<button class="btn btn-outline-primary btn-sm" onclick="refreshData()">
<i class="fas fa-sync-alt"></i>
</button>
</div>
</div>
</div>
<div class="card-body p-0">
{% if object_list %}
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead class="table-light">
<tr>
<th>
<input type="checkbox" id="selectAll" class="form-check-input">
</th>
<th>Room</th>
<th>Type</th>
<th>Status</th>
<th>Current Case</th>
<th>Capabilities</th>
<th>Floor</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for room in object_list %}
<tr>
<td>
<input type="checkbox" class="form-check-input room-checkbox" value="{{ room.pk }}">
</td>
<td>
<div class="d-flex align-items-center">
<div class="bg-primary bg-gradient rounded-circle d-flex align-items-center justify-content-center me-3" style="width: 40px; height: 40px;">
<i class="fas fa-procedures text-white"></i>
</div>
<div>
<div class="fw-semibold">{{ room.room_number }}</div>
<small class="text-muted">{{ room.room_name }}</small>
</div>
</div>
</td>
<td>
<span class="badge bg-info">{{ room.get_room_type_display }}</span>
</td>
<td>
<span class="badge bg-{% if room.status == 'AVAILABLE' %}success{% elif room.status == 'OCCUPIED' %}warning{% elif room.status == 'MAINTENANCE' %}danger{% else %}secondary{% endif %}">
{{ room.get_status_display }}
</span>
</td>
<td>
{% if room.current_case %}
<div class="small">
<div class="fw-semibold">{{ room.current_case.primary_procedure|truncatechars:30 }}</div>
<div class="text-muted">{{ room.current_case.patient.get_full_name }}</div>
</div>
{% else %}
<span class="text-muted">No active case</span>
{% endif %}
</td>
<td>
<div class="d-flex gap-1">
{% if room.supports_robotic %}
<span class="badge bg-primary" title="Robotic Surgery">R</span>
{% endif %}
{% if room.supports_laparoscopic %}
<span class="badge bg-info" title="Laparoscopic">L</span>
{% endif %}
{% if room.has_c_arm %}
<span class="badge bg-warning" title="C-Arm">C</span>
{% endif %}
{% if room.supports_microscopy %}
<span class="badge bg-success" title="Microscopy">M</span>
{% endif %}
</div>
</td>
<td>
<span class="badge bg-secondary">Floor {{ room.floor_number }}</span>
</td>
<td>
<div class="btn-group">
<a href="{% url 'operating_theatre:operating_room_detail' room.pk %}"
class="btn btn-outline-primary btn-sm" title="View Details">
<i class="fas fa-eye"></i>
</a>
<a href="{% url 'operating_theatre:operating_room_update' room.pk %}"
class="btn btn-outline-secondary btn-sm" title="Edit">
<i class="fas fa-edit"></i>
</a>
<div class="btn-group">
<button type="button" class="btn btn-outline-secondary btn-sm 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="updateRoomStatus({{ room.pk }}, 'AVAILABLE')">
<i class="fas fa-check-circle me-2 text-success"></i>Set Available
</a></li>
<li><a class="dropdown-item" href="#" onclick="updateRoomStatus({{ room.pk }}, 'CLEANING')">
<i class="fas fa-broom me-2 text-info"></i>Set Cleaning
</a></li>
<li><a class="dropdown-item" href="#" onclick="updateRoomStatus({{ room.pk }}, 'MAINTENANCE')">
<i class="fas fa-tools me-2 text-warning"></i>Set Maintenance
</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item text-danger" href="{% url 'operating_theatre:operating_room_delete' room.pk %}">
<i class="fas fa-trash me-2"></i>Delete
</a></li>
</ul>
</div>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- Pagination -->
{% if is_paginated %}
<div class="card-footer">
<div class="d-flex justify-content-between align-items-center">
<div class="text-muted">
Showing {{ page_obj.start_index }} to {{ page_obj.end_index }} of {{ page_obj.paginator.count }} rooms
</div>
<nav>
<ul class="pagination pagination-sm mb-0">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page=1">First</a>
</li>
<li class="page-item">
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page={{ page_obj.previous_page_number }}">Previous</a>
</li>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<li class="page-item active">
<span class="page-link">{{ num }}</span>
</li>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<li class="page-item">
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page={{ num }}">{{ num }}</a>
</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page={{ page_obj.next_page_number }}">Next</a>
</li>
<li class="page-item">
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page={{ page_obj.paginator.num_pages }}">Last</a>
</li>
{% endif %}
</ul>
</nav>
</div>
</div>
{% endif %}
{% else %}
<div class="text-center py-5">
<i class="fas fa-procedures fa-3x text-muted mb-3"></i>
<h5 class="text-muted">No Operating Rooms Found</h5>
<p class="text-muted">No operating rooms match your current filters.</p>
<a href="{% url 'operating_theatre:operating_room_create' %}" class="btn btn-primary">
<i class="fas fa-plus me-2"></i>Add First Operating Room
</a>
</div>
{% endif %}
</div>
</div>
</div>
<script>
// Auto-refresh functionality
let autoRefreshInterval;
document.getElementById('autoRefresh').addEventListener('change', function() {
if (this.checked) {
autoRefreshInterval = setInterval(refreshData, 30000);
} else {
clearInterval(autoRefreshInterval);
}
});
function refreshData() {
htmx.trigger('[hx-get]', 'refresh');
location.reload();
}
// Select all functionality
document.getElementById('selectAll').addEventListener('change', function() {
const checkboxes = document.querySelectorAll('.room-checkbox');
checkboxes.forEach(checkbox => {
checkbox.checked = this.checked;
});
});
// Export functionality
function exportData(format) {
const selectedRooms = Array.from(document.querySelectorAll('.room-checkbox:checked')).map(cb => cb.value);
const params = new URLSearchParams(window.location.search);
params.set('export', format);
if (selectedRooms.length > 0) {
params.set('selected', selectedRooms.join(','));
}
window.open(`${window.location.pathname}?${params.toString()}`);
}
// Bulk status update
function bulkStatusUpdate() {
const selectedRooms = Array.from(document.querySelectorAll('.room-checkbox:checked')).map(cb => cb.value);
if (selectedRooms.length === 0) {
alert('Please select at least one room.');
return;
}
const status = prompt('Enter new status (AVAILABLE, CLEANING, MAINTENANCE, OUT_OF_ORDER):');
if (status) {
// Implementation for bulk status update
console.log('Bulk update rooms:', selectedRooms, 'to status:', status);
}
}
// Update room status
function updateRoomStatus(roomId, status) {
if (confirm(`Are you sure you want to set this room to ${status}?`)) {
fetch(`{% url 'operating_theatre:update_room_status' 0 %}`.replace('0', roomId), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
},
body: JSON.stringify({status: status})
})
.then(response => response.json())
.then(data => {
if (data.success) {
location.reload();
} else {
alert('Error updating room status: ' + data.error);
}
})
.catch(error => {
console.error('Error:', error);
alert('Error updating room status');
});
}
}
// Real-time search
document.getElementById('search').addEventListener('input', function() {
clearTimeout(this.searchTimeout);
this.searchTimeout = setTimeout(() => {
document.getElementById('filterForm').submit();
}, 500);
});
// Keyboard shortcuts
document.addEventListener('keydown', function(e) {
if (e.ctrlKey || e.metaKey) {
switch(e.key) {
case 'n':
e.preventDefault();
window.location.href = "{% url 'operating_theatre:operating_room_create' %}";
break;
case 'r':
e.preventDefault();
refreshData();
break;
}
}
});
</script>
<style>
.bg-gradient {
background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
}
.opacity-50 {
opacity: 0.5;
}
.btn:hover {
transform: translateY(-1px);
transition: transform 0.2s ease-in-out;
}
.table th {
border-top: none;
font-weight: 600;
text-transform: uppercase;
font-size: 0.75rem;
letter-spacing: 0.5px;
}
.badge {
font-size: 0.7rem;
font-weight: 500;
}
@media (max-width: 768px) {
.d-flex.justify-content-between {
flex-direction: column;
gap: 1rem;
}
.btn-group {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.table-responsive {
font-size: 0.875rem;
}
.fa-3x {
font-size: 2em;
}
}
</style>
{% endblock %}