Marwan Alwali beba30e532 update
2025-09-11 20:32:09 +03:00

489 lines
21 KiB
HTML

{% extends "base.html" %}
{% load static %}
{% block title %}Patient Management Dashboard{% endblock %}
{% block extra_css %}
<link href="{% static 'assets/plugins/jvectormap-next/jquery-jvectormap.css' %}" rel="stylesheet" />
<link href="{% static 'assets/plugins/datatables.net-bs5/css/dataTables.bootstrap5.min.css' %}" rel="stylesheet" />
<link href="{% static 'assets/plugins/datatables.net-responsive-bs5/css/responsive.bootstrap5.min.css' %}" rel="stylesheet" />
<style>
.metric-card {
transition: transform 0.2s;
}
.metric-card:hover {
transform: translateY(-2px);
}
.patient-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
color: white;
}
.priority-high { border-left: 4px solid #dc3545; }
.priority-medium { border-left: 4px solid #ffc107; }
.priority-low { border-left: 4px solid #28a745; }
.chart-container {
position: relative;
height: 300px;
}
</style>
{% endblock %}
{% block content %}
<!-- BEGIN breadcrumb -->
<ol class="breadcrumb float-xl-end">
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Home</a></li>
<li class="breadcrumb-item active">Patient Management</li>
</ol>
<!-- END breadcrumb -->
<!-- BEGIN page-header -->
<h1 class="page-header">
<i class="fas fa-users text-primary me-2"></i>
Patient Management Dashboard
<small class="text-muted ms-2">Comprehensive overview of patient care and management</small>
</h1>
<!-- END page-header -->
<!-- BEGIN statistics cards -->
<div class="row mb-4">
<div class="col-xl-3 col-md-6">
<div class="card bg-primary text-white metric-card">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<h6 class="card-title mb-1">Total Patients</h6>
<h3 class="mb-0" id="total-patients">{{ stats.total_patients|default:0 }}</h3>
<small class="opacity-75">Active registrations</small>
</div>
<div class="flex-shrink-0">
<i class="fas fa-users fa-2x opacity-75"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6">
<div class="card bg-success text-white metric-card">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<h6 class="card-title mb-1">Active Inpatients</h6>
<h3 class="mb-0" id="active-inpatients">{{ stats.active_inpatients|default:0 }}</h3>
<small class="opacity-75">Currently admitted</small>
</div>
<div class="flex-shrink-0">
<i class="fas fa-bed fa-2x opacity-75"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6">
<div class="card bg-warning text-white metric-card">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<h6 class="card-title mb-1">Today's Visits</h6>
<h3 class="mb-0" id="todays-visits">{{ stats.todays_visits|default:0 }}</h3>
<small class="opacity-75">Outpatient visits</small>
</div>
<div class="flex-shrink-0">
<i class="fas fa-calendar-check fa-2x opacity-75"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6">
<div class="card bg-info text-white metric-card">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<h6 class="card-title mb-1">Critical Alerts</h6>
<h3 class="mb-0" id="critical-alerts">{{ stats.critical_alerts|default:0 }}</h3>
<small class="opacity-75">Require attention</small>
</div>
<div class="flex-shrink-0">
<i class="fas fa-exclamation-triangle fa-2x opacity-75"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- END statistics cards -->
<!-- BEGIN quick actions -->
<div class="row mb-4">
<div class="col-md-12">
<div class="panel panel-inverse">
<div class="panel-heading">
<h4 class="panel-title">
<i class="fas fa-bolt me-2"></i>Quick Actions
</h4>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-2 col-sm-4 col-6 mb-3">
<a href="{% url 'patients:patient_create' %}" class="btn btn-outline-primary w-100 py-3">
<i class="fas fa-user-plus fa-2x mb-2"></i>
<div>Register Patient</div>
</a>
</div>
<div class="col-md-2 col-sm-4 col-6 mb-3">
<a href="{% url 'patients:patient_search' %}" class="btn btn-outline-info w-100 py-3">
<i class="fas fa-search fa-2x mb-2"></i>
<div>Search Patients</div>
</a>
</div>
<div class="col-md-2 col-sm-4 col-6 mb-3">
<a href="{% url 'appointments:appointment_create' %}" class="btn btn-outline-success w-100 py-3">
<i class="fas fa-calendar-plus fa-2x mb-2"></i>
<div>Schedule Visit</div>
</a>
</div>
<div class="col-md-2 col-sm-4 col-6 mb-3">
<a href="{% url 'inpatients:admission_create' %}" class="btn btn-outline-warning w-100 py-3">
<i class="fas fa-hospital fa-2x mb-2"></i>
<div>Admit Patient</div>
</a>
</div>
<div class="col-md-2 col-sm-4 col-6 mb-3">
<a href="{% url 'patients:emergency_registration' %}" class="btn btn-outline-danger w-100 py-3">
<i class="fas fa-ambulance fa-2x mb-2"></i>
<div>Emergency Reg.</div>
</a>
</div>
<div class="col-md-2 col-sm-4 col-6 mb-3">
<a href="{% url 'patients:patient_reports' %}" class="btn btn-outline-secondary w-100 py-3">
<i class="fas fa-chart-bar fa-2x mb-2"></i>
<div>Reports</div>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- END quick actions -->
<!-- BEGIN main content -->
<div class="row">
<!-- LEFT COLUMN -->
<div class="col-xl-8">
<!-- Recent Admissions -->
<div class="panel panel-inverse mb-4">
<div class="panel-heading">
<h4 class="panel-title">
<i class="fas fa-hospital-user me-2"></i>Recent Admissions
</h4>
<div class="panel-heading-btn">
<a href="{% url 'inpatients:admission_list' %}" class="btn btn-outline-primary btn-sm">
<i class="fas fa-eye me-1"></i>View All
</a>
</div>
</div>
<div class="panel-body">
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead class="table-dark">
<tr>
<th>Patient</th>
<th>Room</th>
<th>Admission Date</th>
<th>Attending Physician</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for admission in recent_admissions %}
<tr class="{% if admission.priority == 'HIGH' %}priority-high{% elif admission.priority == 'MEDIUM' %}priority-medium{% else %}priority-low{% endif %}">
<td>
<div class="d-flex align-items-center">
<div class="patient-avatar bg-primary me-2">
{{ admission.patient.first_name|first }}{{ admission.patient.last_name|first }}
</div>
<div>
<div class="fw-bold">{{ admission.patient.get_full_name }}</div>
<small class="text-muted">MRN: {{ admission.patient.mrn }}</small>
</div>
</div>
</td>
<td>
<span class="badge bg-info">{{ admission.room.number }}</span>
<small class="d-block text-muted">{{ admission.room.ward.name }}</small>
</td>
<td>{{ admission.admission_date|date:"M d, Y H:i" }}</td>
<td>{{ admission.attending_physician.get_full_name }}</td>
<td>
{% if admission.status == 'ACTIVE' %}
<span class="badge bg-success">Active</span>
{% elif admission.status == 'PENDING' %}
<span class="badge bg-warning">Pending</span>
{% else %}
<span class="badge bg-secondary">{{ admission.get_status_display }}</span>
{% endif %}
</td>
<td>
<div class="btn-group" role="group">
<a href="{% url 'patients:patient_detail' admission.patient.pk %}"
class="btn btn-outline-primary btn-sm" title="View Patient">
<i class="fas fa-eye"></i>
</a>
<a href="{% url 'inpatients:admission_detail' admission.pk %}"
class="btn btn-outline-info btn-sm" title="View Admission">
<i class="fas fa-hospital"></i>
</a>
</div>
</td>
</tr>
{% empty %}
<tr>
<td colspan="6" class="text-center py-4 text-muted">
<i class="fas fa-inbox fa-2x mb-2"></i>
<p class="mb-0">No recent admissions</p>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<!-- Patient Activity Chart -->
<div class="panel panel-inverse">
<div class="panel-heading">
<h4 class="panel-title">
<i class="fas fa-chart-line me-2"></i>Patient Activity Trends
</h4>
<div class="panel-heading-btn">
<select class="form-select form-select-sm" id="chart-period">
<option value="7">Last 7 days</option>
<option value="30" selected>Last 30 days</option>
<option value="90">Last 90 days</option>
</select>
</div>
</div>
<div class="panel-body">
<div class="chart-container">
<canvas id="patientActivityChart"></canvas>
</div>
</div>
</div>
</div>
<!-- RIGHT COLUMN -->
<div class="col-xl-4">
<!-- Critical Alerts -->
<div class="panel panel-inverse mb-4">
<div class="panel-heading">
<h4 class="panel-title">
<i class="fas fa-exclamation-triangle me-2"></i>Critical Alerts
</h4>
<div class="panel-heading-btn">
<button class="btn btn-outline-secondary btn-sm" onclick="refreshAlerts()">
<i class="fas fa-sync-alt"></i>
</button>
</div>
</div>
<div class="panel-body" style="max-height: 300px; overflow-y: auto;">
{% for alert in critical_alerts %}
<div class="alert alert-{% if alert.severity == 'CRITICAL' %}danger{% elif alert.severity == 'HIGH' %}warning{% else %}info{% endif %} alert-dismissible fade show mb-2">
<div class="d-flex align-items-start">
<div class="flex-grow-1">
<h6 class="alert-heading mb-1">{{ alert.title }}</h6>
<p class="mb-1">{{ alert.message }}</p>
<small class="text-muted">
<i class="fas fa-clock me-1"></i>{{ alert.created_at|timesince }} ago
</small>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
</div>
{% empty %}
<div class="text-center text-muted py-4">
<i class="fas fa-check-circle fa-2x mb-2"></i>
<p class="mb-0">No critical alerts</p>
</div>
{% endfor %}
</div>
</div>
<!-- Today's Schedule -->
<div class="panel panel-inverse mb-4">
<div class="panel-heading">
<h4 class="panel-title">
<i class="fas fa-calendar-day me-2"></i>Today's Schedule
</h4>
<div class="panel-heading-btn">
<a href="{% url 'appointments:appointment_list' %}" class="btn btn-outline-primary btn-sm">
<i class="fas fa-calendar me-1"></i>Full Calendar
</a>
</div>
</div>
<div class="panel-body" style="max-height: 300px; overflow-y: auto;">
{% for appointment in todays_appointments %}
<div class="d-flex align-items-center mb-3 pb-3 border-bottom">
<div class="patient-avatar bg-primary me-3">
{{ appointment.patient.first_name|first }}{{ appointment.patient.last_name|first }}
</div>
<div class="flex-grow-1">
<div class="fw-bold">{{ appointment.patient.get_full_name }}</div>
<small class="text-muted">{{ appointment.get_appointment_type_display }}</small>
<div class="text-primary">
<i class="fas fa-clock me-1"></i>{{ appointment.appointment_time|time:"g:i A" }}
</div>
</div>
<div class="text-end">
<span class="badge bg-{% if appointment.status == 'CONFIRMED' %}success{% elif appointment.status == 'PENDING' %}warning{% else %}secondary{% endif %}">
{{ appointment.get_status_display }}
</span>
</div>
</div>
{% empty %}
<div class="text-center text-muted py-4">
<i class="fas fa-calendar-times fa-2x mb-2"></i>
<p class="mb-0">No appointments scheduled for today</p>
</div>
{% endfor %}
</div>
</div>
<!-- Department Occupancy -->
<div class="panel panel-inverse">
<div class="panel-heading">
<h4 class="panel-title">
<i class="fas fa-hospital me-2"></i>Department Occupancy
</h4>
</div>
<div class="panel-body">
{% for dept in department_occupancy %}
<div class="mb-3">
<div class="d-flex justify-content-between align-items-center mb-1">
<span class="fw-bold">{{ dept.name }}</span>
<span class="text-muted">{{ dept.occupied }}/{{ dept.capacity }}</span>
</div>
<div class="progress" style="height: 8px;">
<div class="progress-bar bg-{% if dept.occupancy_rate >= 90 %}danger{% elif dept.occupancy_rate >= 75 %}warning{% else %}success{% endif %}"
style="width: {{ dept.occupancy_rate }}%"></div>
</div>
<small class="text-muted">{{ dept.occupancy_rate }}% occupancy</small>
</div>
{% empty %}
<div class="text-center text-muted py-4">
<i class="fas fa-building fa-2x mb-2"></i>
<p class="mb-0">No department data available</p>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
<!-- END main content -->
{% endblock %}
{% block extra_js %}
<script src="{% static 'assets/plugins/chart.js/dist/chart.min.js' %}"></script>
<script src="{% static 'assets/plugins/datatables.net/js/dataTables.min.js' %}"></script>
<script src="{% static 'assets/plugins/datatables.net-bs5/js/dataTables.bootstrap5.min.js' %}"></script>
<script>
$(document).ready(function() {
// Initialize Patient Activity Chart
const ctx = document.getElementById('patientActivityChart').getContext('2d');
const patientActivityChart = new Chart(ctx, {
type: 'line',
data: {
labels: {{ chart_labels|safe }},
datasets: [{
label: 'New Registrations',
data: {{ new_registrations_data|safe }},
borderColor: 'rgb(75, 192, 192)',
backgroundColor: 'rgba(75, 192, 192, 0.1)',
tension: 0.1
}, {
label: 'Admissions',
data: {{ admissions_data|safe }},
borderColor: 'rgb(255, 99, 132)',
backgroundColor: 'rgba(255, 99, 132, 0.1)',
tension: 0.1
}, {
label: 'Discharges',
data: {{ discharges_data|safe }},
borderColor: 'rgb(54, 162, 235)',
backgroundColor: 'rgba(54, 162, 235, 0.1)',
tension: 0.1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'top',
},
title: {
display: true,
text: 'Patient Activity Over Time'
}
},
scales: {
y: {
beginAtZero: true
}
}
}
});
// Chart period change handler
$('#chart-period').change(function() {
const period = $(this).val();
// AJAX call to update chart data
$.get('{% url "patients:dashboard_chart_data" %}', {period: period}, function(data) {
patientActivityChart.data.labels = data.labels;
patientActivityChart.data.datasets[0].data = data.new_registrations;
patientActivityChart.data.datasets[1].data = data.admissions;
patientActivityChart.data.datasets[2].data = data.discharges;
patientActivityChart.update();
});
});
// Auto-refresh stats every 30 seconds
setInterval(function() {
refreshStats();
}, 30000);
// Auto-refresh alerts every 60 seconds
setInterval(function() {
refreshAlerts();
}, 60000);
});
function refreshStats() {
$.get('{% url "patients:dashboard_stats" %}', function(data) {
$('#total-patients').text(data.total_patients);
$('#active-inpatients').text(data.active_inpatients);
$('#todays-visits').text(data.todays_visits);
$('#critical-alerts').text(data.critical_alerts);
});
}
function refreshAlerts() {
// Refresh critical alerts section
$.get('{% url "patients:dashboard_alerts" %}', function(data) {
// Update alerts section with new data
// Implementation would depend on your specific alert system
});
}
</script>
{% endblock %}