Marwan Alwali 610e165e17 update
2025-09-04 19:19:52 +03:00

471 lines
20 KiB
HTML

{% extends "base.html" %}
{% load static %}
{% block title %}Operating Theatre Dashboard - {{ 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 Theatre Dashboard
</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 active">Operating Theatre</li>
</ol>
</nav>
</div>
<div class="btn-group">
<a href="{% url 'operating_theatre:surgical_case_create' %}" class="btn btn-primary">
<i class="fas fa-plus me-2"></i>New Case
</a>
<a href="{% url 'operating_theatre:surgical_note_create' %}" class="btn btn-success">
<i class="fas fa-file-medical me-2"></i>New Note
</a>
</div>
</div>
<!-- Statistics Tiles (keep as cards for compact visuals) -->
<div class="row mb-4" hx-get="{% url 'operating_theatre:operating_theatre_stats' %}" hx-trigger="load, every 300s">
<!-- Room Status Stats -->
<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="h4 mb-1">{{ rooms_available|default:0 }}</div>
<div class="small">Rooms Available</div>
</div>
<div class="fa-2x"><i class="fas fa-door-open"></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="h4 mb-1">{{ rooms_in_use|default:0 }}</div>
<div class="small">Rooms In Use</div>
</div>
<div class="fa-2x"><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-info text-white">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="h4 mb-1">{{ rooms_maintenance|default:0 }}</div>
<div class="small">Maintenance</div>
</div>
<div class="fa-2x"><i class="fas fa-tools"></i></div>
</div>
</div>
</div>
</div>
<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="h4 mb-1">{{ total_rooms|default:0 }}</div>
<div class="small">Total Rooms</div>
</div>
<div class="fa-2x"><i class="fas fa-hospital"></i></div>
</div>
</div>
</div>
</div>
<!-- Case Statistics -->
<div class="col-xl-3 col-md-6 mb-3">
<div class="card bg-gradient-secondary text-white">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="h4 mb-1">{{ cases_today|default:0 }}</div>
<div class="small">Cases Today</div>
</div>
<div class="fa-2x"><i class="fas fa-calendar-day"></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="h4 mb-1">{{ cases_in_progress|default:0 }}</div>
<div class="small">Cases In Progress</div>
</div>
<div class="fa-2x"><i class="fas fa-play-circle"></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="h4 mb-1">{{ cases_completed_today|default:0 }}</div>
<div class="small">Completed Today</div>
</div>
<div class="fa-2x"><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-danger text-white">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="h4 mb-1">{{ emergency_cases_today|default:0 }}</div>
<div class="small">Emergency Cases</div>
</div>
<div class="fa-2x"><i class="fas fa-exclamation-triangle"></i></div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<!-- Today's Schedule -->
<div class="col-lg-8 mb-4">
<div class="panel panel-inverse">
<div class="panel-heading">
<h4 class="panel-title"><i class="fas fa-calendar-alt me-2"></i>Today's Schedule</h4>
<div class="panel-heading-btn">
<a href="{% url 'operating_theatre:surgical_case_list' %}" class="btn btn-xs btn-theme">View All</a>
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
</div>
</div>
<div class="panel-body">
{% if todays_schedule %}
<div class="table-responsive">
<table class="table table-hover">
<thead class="table-light">
<tr>
<th>Time</th>
<th>Patient</th>
<th>Procedure</th>
<th>Room</th>
<th>Surgeon</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for case in todays_schedule %}
<tr>
<td>
<div class="fw-semibold">{{ case.scheduled_start|date:"H:i" }}</div>
<div class="small text-muted">{{ case.estimated_duration }} min</div>
</td>
<td>
<div class="fw-semibold">{{ case.patient.get_full_name }}</div>
<div class="small text-muted">{{ case.patient.mrn }}</div>
</td>
<td>
<div>{{ case.primary_procedure|truncatechars:30 }}</div>
{% if case.case_type == 'EMERGENCY' %}
<span class="badge bg-danger">Emergency</span>
{% elif case.case_type == 'URGENT' %}
<span class="badge bg-warning">Urgent</span>
{% endif %}
</td>
<td>
{% if case.operating_room %}
<span class="badge bg-info">{{ case.operating_room.room_number }}</span>
{% else %}
<span class="text-muted">TBD</span>
{% endif %}
</td>
<td>
{% if case.primary_surgeon %}
<div class="small">{{ case.primary_surgeon.get_full_name }}</div>
{% else %}
<span class="text-muted">N/A</span>
{% endif %}
</td>
<td>
<span class="badge bg-{% if case.status == 'SCHEDULED' %}secondary{% elif case.status == 'IN_PROGRESS' %}warning{% elif case.status == 'COMPLETED' %}success{% elif case.status == 'CANCELLED' %}danger{% else %}info{% endif %}">
{{ case.get_status_display }}
</span>
</td>
<td>
<div class="btn-group btn-group-sm">
<a href="{% url 'operating_theatre:surgical_case_detail' case.pk %}" class="btn btn-outline-primary" title="View Details">
<i class="fas fa-eye"></i>
</a>
{% if case.status == 'SCHEDULED' %}
<button
type="button"
class="btn btn-outline-success"
title="Start Case"
data-start-url="{% url 'operating_theatre:start_case' case.pk %}"
onclick="startCase(this)">
<i class="fas fa-play"></i>
</button>
{% endif %}
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center py-4">
<i class="fas fa-calendar-times fa-3x text-muted mb-3"></i>
<p class="text-muted">No cases scheduled for today.</p>
<a href="{% url 'operating_theatre:surgical_case_create' %}" class="btn btn-primary">
<i class="fas fa-plus me-2"></i>Schedule a Case
</a>
</div>
{% endif %}
</div>
</div>
</div>
<!-- Room Status Overview -->
<div class="col-lg-4 mb-4">
<div class="panel panel-inverse">
<div class="panel-heading">
<h4 class="panel-title"><i class="fas fa-door-open me-2"></i>Room Status</h4>
<div class="panel-heading-btn">
<a href="{% url 'operating_theatre:operating_room_list' %}" class="btn btn-xs btn-theme">Manage</a>
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
</div>
</div>
<div class="panel-body">
{% if room_utilization %}
{% for room in room_utilization %}
<div class="d-flex align-items-center mb-3 p-3 rounded {% if room.status == 'AVAILABLE' %}bg-light-success{% elif room.status == 'OCCUPIED' %}bg-light-warning{% elif room.status == 'MAINTENANCE' %}bg-light-danger{% else %}bg-light-info{% endif %}">
<div class="me-3">
<div class="bg-{% if room.status == 'AVAILABLE' %}success{% elif room.status == 'OCCUPIED' %}warning{% elif room.status == 'MAINTENANCE' %}danger{% else %}info{% endif %} bg-gradient rounded-circle d-flex align-items-center justify-content-center" style="width: 40px; height: 40px;">
<i class="fas fa-{% if room.status == 'AVAILABLE' %}check{% elif room.status == 'OCCUPIED' %}user-md{% elif room.status == 'MAINTENANCE' %}tools{% else %}clock{% endif %} text-white"></i>
</div>
</div>
<div class="flex-grow-1">
<div class="fw-semibold">{{ room.room_number }} - {{ room.room_name }}</div>
<div class="small text-muted">
{{ room.get_status_display }}
{% if room.current_case %}
— {{ room.current_case.patient.get_full_name }}
{% endif %}
</div>
<div class="small text-muted">{{ room.cases_today|default:0 }} case{{ room.cases_today|pluralize }} today</div>
</div>
<div>
<a href="{% url 'operating_theatre:operating_room_detail' room.pk %}" class="btn btn-sm btn-outline-primary">
<i class="fas fa-eye"></i>
</a>
</div>
</div>
{% endfor %}
{% else %}
<div class="text-center py-4">
<i class="fas fa-door-closed fa-3x text-muted mb-3"></i>
<p class="text-muted">No operating rooms configured.</p>
<a href="{% url 'operating_theatre:operating_room_create' %}" class="btn btn-primary">
<i class="fas fa-plus me-2"></i>Add Room
</a>
</div>
{% endif %}
</div>
</div>
</div>
</div>
<div class="row">
<!-- Recent Activity -->
<div class="col-lg-8 mb-4">
<div class="panel panel-inverse h-100">
<div class="panel-heading">
<h4 class="panel-title"><i class="fas fa-history me-2"></i>Recent Activity</h4>
<div class="panel-heading-btn">
<a href="{% url 'operating_theatre:surgical_case_list' %}" class="btn btn-xs btn-theme">View All</a>
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
</div>
</div>
<div class="panel-body">
{% if recent_cases %}
{% for case in recent_cases %}
<div class="d-flex align-items-center mb-3">
<div class="bg-{% if case.status == 'COMPLETED' %}success{% elif case.status == 'IN_PROGRESS' %}warning{% elif case.status == 'CANCELLED' %}danger{% else %}secondary{% endif %} bg-gradient rounded-circle d-flex align-items-center justify-content-center me-3" style="width: 32px; height: 32px;">
<i class="fas fa-{% if case.status == 'COMPLETED' %}check{% elif case.status == 'IN_PROGRESS' %}play{% elif case.status == 'CANCELLED' %}times{% else %}clock{% endif %} text-white small"></i>
</div>
<div class="flex-grow-1">
<div class="fw-semibold">{{ case.patient.get_full_name }}</div>
<div class="small text-muted">{{ case.primary_procedure|truncatechars:40 }}</div>
<div class="small text-muted">{{ case.scheduled_start|date:"M d, H:i" }}</div>
</div>
<div>
<span class="badge bg-{% if case.status == 'COMPLETED' %}success{% elif case.status == 'IN_PROGRESS' %}warning{% elif case.status == 'CANCELLED' %}danger{% else %}secondary{% endif %}">
{{ case.get_status_display }}
</span>
</div>
</div>
{% endfor %}
{% else %}
<div class="text-center py-4">
<i class="fas fa-history fa-3x text-muted mb-3"></i>
<p class="text-muted">No recent activity.</p>
</div>
{% endif %}
</div>
</div>
</div>
<!-- Quick Actions -->
<div class="col-lg-4 mb-4">
<div class="panel panel-inverse h-100">
<div class="panel-heading">
<h4 class="panel-title"><i class="fas fa-bolt me-2"></i>Quick Actions</h4>
<div class="panel-heading-btn">
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
</div>
</div>
<div class="panel-body">
<div class="row g-3">
<div class="col-6">
<a href="{% url 'operating_theatre:surgical_case_list' %}" class="btn btn-outline-primary w-100 h-100 d-flex flex-column align-items-center justify-content-center">
<i class="fas fa-list-alt fa-2x mb-2"></i><span>View Cases</span>
</a>
</div>
<div class="col-6">
<a href="{% url 'operating_theatre:operating_room_list' %}" class="btn btn-outline-info w-100 h-100 d-flex flex-column align-items-center justify-content-center">
<i class="fas fa-door-open fa-2x mb-2"></i><span>Manage Rooms</span>
</a>
</div>
<div class="col-6">
<a href="{% url 'operating_theatre:or_block_list' %}" class="btn btn-outline-success w-100 h-100 d-flex flex-column align-items-center justify-content-center">
<i class="fas fa-calendar-alt fa-2x mb-2"></i><span>OR Blocks</span>
</a>
</div>
<div class="col-6">
<a href="{% url 'operating_theatre:surgical_note_list' %}" class="btn btn-outline-warning w-100 h-100 d-flex flex-column align-items-center justify-content-center">
<i class="fas fa-file-medical fa-2x mb-2"></i><span>Surgical Notes</span>
</a>
</div>
<div class="col-6">
<a href="{% url 'operating_theatre:equipment_list' %}" class="btn btn-outline-secondary w-100 h-100 d-flex flex-column align-items-center justify-content-center">
<i class="fas fa-tools fa-2x mb-2"></i><span>Equipment</span>
</a>
</div>
<div class="col-6">
<a href="{% url 'operating_theatre:surgical_note_template_list' %}" class="btn btn-outline-dark w-100 h-100 d-flex flex-column align-items-center justify-content-center">
<i class="fas fa-file-alt fa-2x mb-2"></i><span>Templates</span>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Performance Metrics -->
<div class="row">
<div class="col-12">
<div class="panel panel-inverse">
<div class="panel-heading">
<h4 class="panel-title"><i class="fas fa-chart-line me-2"></i>Performance Metrics</h4>
<div class="panel-heading-btn">
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
</div>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-3 text-center">
<div class="h4 text-primary">{{ performance_metrics.utilization_rate|default:0 }}%</div>
<div class="small text-muted">OR Utilization Rate</div>
</div>
<div class="col-md-3 text-center">
<div class="h4 text-success">{{ performance_metrics.on_time_starts|default:0 }}%</div>
<div class="small text-muted">On-Time Starts</div>
</div>
<div class="col-md-3 text-center">
<div class="h4 text-info">{{ performance_metrics.avg_turnover|default:0 }} min</div>
<div class="small text-muted">Avg Turnover Time</div>
</div>
<div class="col-md-3 text-center">
<div class="h4 text-warning">{{ performance_metrics.cancellation_rate|default:0 }}%</div>
<div class="small text-muted">Cancellation Rate</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// CSRF helper from cookie (consistent with other templates)
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
}
// Start case using data-start-url on the button
function startCase(btnEl) {
const url = btnEl.dataset.startUrl;
if (!url) return;
if (!confirm('Start this surgical case?')) return;
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCookie('csrftoken')
}
})
.then(r => r.json())
.then(data => data.success ? location.reload() : alert('Error starting case: ' + (data.error || 'Unknown error')))
.catch(() => alert('Network error starting case'));
}
// Optional: gently nudge stats refresh between HTMX polls
setInterval(function () {
const statsContainer = document.querySelector('[hx-get]');
if (statsContainer && window.htmx) {
htmx.trigger(statsContainer, 'refresh');
}
}, 30000);
</script>
<style>
/* Light contextual backgrounds for room status */
.bg-light-success { background-color: rgba(25, 135, 84, 0.1) !important; }
.bg-light-warning { background-color: rgba(255, 193, 7, 0.1) !important; }
.bg-light-danger { background-color: rgba(220, 53, 69, 0.1) !important; }
.bg-light-info { background-color: rgba(13, 202, 240, 0.1) !important; }
/* Subtle tile animation */
.card-body .btn { transition: all 0.2s ease-in-out; }
.card-body .btn:hover { transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0,0,0,0.1); }
.table-hover tbody tr:hover { background-color: rgba(0,0,0,0.025); }
/* Panel theme harmony */
{#.panel-title { color: #495057; }#}
.badge { font-size: .75rem; }
@media (max-width: 768px) {
.btn-group { display: flex; flex-direction: column; gap: .5rem; }
.col-xl-3, .col-md-6 { margin-bottom: 1rem; }
}
</style>
{% endblock %}