214 lines
9.3 KiB
HTML
214 lines
9.3 KiB
HTML
{% extends 'layouts/base.html' %}
|
|
{% load i18n %}
|
|
|
|
{% block title %}PX Command Center - PX360{% endblock %}
|
|
|
|
{% block page_title %}PX Command Center{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid">
|
|
<!-- Top KPI Cards -->
|
|
{% include 'layouts/partials/stat_cards.html' with stats=stats %}
|
|
|
|
<!-- Charts Row -->
|
|
<div class="row g-3 mb-4">
|
|
<!-- Complaints Trend -->
|
|
<div class="col-lg-8">
|
|
<div class="card table-card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0"><i class="bi bi-graph-up me-2"></i>{% trans "Complaints Trend (Last 30 Days)" %}</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<canvas id="complaintsTrendChart" height="80"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Survey Satisfaction -->
|
|
<div class="col-lg-4">
|
|
<div class="card table-card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0"><i class="bi bi-star me-2"></i>{% trans "Survey Satisfaction" %}</h5>
|
|
</div>
|
|
<div class="card-body text-center">
|
|
<div class="display-3 text-primary mb-2">{{ chart_data.survey_satisfaction|floatformat:1 }}</div>
|
|
<p class="text-muted">Average Score (Last 30 Days)</p>
|
|
<div class="progress" style="height: 10px;">
|
|
<div class="progress-bar bg-success" role="progressbar"
|
|
style="width: {{ chart_data.survey_satisfaction|floatformat:0 }}%"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Live Feed Row -->
|
|
<div class="row g-3">
|
|
<!-- Latest High Severity Complaints -->
|
|
<div class="col-lg-6">
|
|
<div class="card table-card">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<h5 class="mb-0"><i class="bi bi-exclamation-triangle me-2"></i>{% trans "Latest High Severity Complaints" %}</h5>
|
|
<a href="#" class="btn btn-sm btn-primary">{% trans "View All" %}</a>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
{% if latest_complaints %}
|
|
<div class="list-group list-group-flush">
|
|
{% for complaint in latest_complaints %}
|
|
<div class="list-group-item">
|
|
<div class="d-flex justify-content-between align-items-start">
|
|
<div class="flex-grow-1">
|
|
<h6 class="mb-1">{{ complaint.title }}</h6>
|
|
<p class="mb-1 text-muted small">
|
|
<i class="bi bi-person me-1"></i>{{ complaint.patient.get_full_name }}
|
|
<i class="bi bi-building ms-2 me-1"></i>{{ complaint.hospital.name }}
|
|
</p>
|
|
<small class="text-muted">{{ complaint.created_at|timesince }} ago</small>
|
|
</div>
|
|
<div>
|
|
<span class="badge bg-{{ complaint.severity }}">{{ complaint.get_severity_display }}</span>
|
|
{% if complaint.is_overdue %}
|
|
<span class="badge bg-danger ms-1">OVERDUE</span>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<div class="p-4 text-center text-muted">
|
|
<i class="bi bi-check-circle fs-1"></i>
|
|
<p class="mt-2">No high severity complaints</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Latest Escalated Actions -->
|
|
<div class="col-lg-6">
|
|
<div class="card table-card">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<h5 class="mb-0"><i class="bi bi-arrow-up-circle me-2"></i>{% trans "Latest Escalated Actions" %}</h5>
|
|
<a href="#" class="btn btn-sm btn-primary">{% trans "View All" %}</a>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
{% if latest_actions %}
|
|
<div class="list-group list-group-flush">
|
|
{% for action in latest_actions %}
|
|
<div class="list-group-item">
|
|
<div class="d-flex justify-content-between align-items-start">
|
|
<div class="flex-grow-1">
|
|
<h6 class="mb-1">{{ action.title }}</h6>
|
|
<p class="mb-1 text-muted small">
|
|
<i class="bi bi-building me-1"></i>{{ action.hospital.name }}
|
|
{% if action.assigned_to %}
|
|
<i class="bi bi-person ms-2 me-1"></i>{{ action.assigned_to.get_full_name }}
|
|
{% endif %}
|
|
</p>
|
|
<small class="text-muted">Escalated {{ action.escalated_at|timesince }} ago</small>
|
|
</div>
|
|
<div>
|
|
<span class="badge bg-danger">Level {{ action.escalation_level }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<div class="p-4 text-center text-muted">
|
|
<i class="bi bi-check-circle fs-1"></i>
|
|
<p class="mt-2">No escalated actions</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Latest Integration Events -->
|
|
<div class="row g-3 mt-3">
|
|
<div class="col-12">
|
|
<div class="card table-card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0"><i class="bi bi-activity me-2"></i>{% trans "Latest Integration Events" %}</h5>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
{% if latest_events %}
|
|
<div class="table-responsive">
|
|
<table class="table table-hover mb-0">
|
|
<thead>
|
|
<tr>
|
|
<th>{% trans "Source" %}</th>
|
|
<th>{% trans "Event Code" %}</th>
|
|
<th>{% trans "Encounter ID" %}</th>
|
|
<th>{% trans "Status" %}</th>
|
|
<th>{% trans "Processed At" %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for event in latest_events %}
|
|
<tr>
|
|
<td><span class="badge bg-info">{{ event.get_source_system_display }}</span></td>
|
|
<td><code>{{ event.event_code }}</code></td>
|
|
<td>{{ event.encounter_id }}</td>
|
|
<td><span class="badge bg-success">{{ event.get_status_display }}</span></td>
|
|
<td>{{ event.processed_at|timesince }} ago</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% else %}
|
|
<div class="p-4 text-center text-muted">
|
|
<i class="bi bi-inbox fs-1"></i>
|
|
<p class="mt-2">No recent events</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
<script>
|
|
// Complaints Trend Chart
|
|
const ctx = document.getElementById('complaintsTrendChart');
|
|
if (ctx) {
|
|
const trendData = {{ chart_data.complaints_trend|safe }};
|
|
new Chart(ctx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: trendData.map(d => d.date),
|
|
datasets: [{
|
|
label: 'Complaints',
|
|
data: trendData.map(d => d.count),
|
|
borderColor: 'rgb(239, 68, 68)',
|
|
backgroundColor: 'rgba(239, 68, 68, 0.1)',
|
|
tension: 0.4
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
plugins: {
|
|
legend: {
|
|
display: false
|
|
}
|
|
},
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true,
|
|
ticks: {
|
|
stepSize: 1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
</script>
|
|
{% endblock %}
|