HH/templates/complaints/analytics.html
Marwan Alwali 2179fbf39a update
2025-12-31 13:16:30 +03:00

306 lines
12 KiB
HTML

{% extends 'layouts/base.html' %}
{% load i18n %}
{% block title %}{% trans "Complaints Analytics" %}{% endblock %}
{% block extra_css %}
{% 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-0">{% trans "Complaints Analytics" %}</h1>
<p class="text-muted">{% trans "Comprehensive complaints metrics and insights" %}</p>
</div>
<div>
<form method="get" class="d-inline">
<select name="date_range" class="form-select d-inline-block w-auto" onchange="this.form.submit()">
<option value="7" {% if date_range == 7 %}selected{% endif %}>{% trans "Last 7 Days" %}</option>
<option value="30" {% if date_range == 30 %}selected{% endif %}>{% trans "Last 30 Days" %}</option>
<option value="90" {% if date_range == 90 %}selected{% endif %}>{% trans "Last 90 Days" %}</option>
</select>
</form>
</div>
</div>
<!-- Summary Cards -->
<div class="row mb-4">
<div class="col-md-3">
<div class="card border-left-primary">
<div class="card-body">
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">{% trans "Total Complaints" %}</div>
<div class="h5 mb-0 font-weight-bold">{{ dashboard_summary.status_counts.total }}</div>
<small class="text-muted">
{% if dashboard_summary.trend.percentage_change > 0 %}
<i class="fas fa-arrow-up text-danger"></i> +{{ dashboard_summary.trend.percentage_change }}%
{% elif dashboard_summary.trend.percentage_change < 0 %}
<i class="fas fa-arrow-down text-success"></i> {{ dashboard_summary.trend.percentage_change }}%
{% else %}
<i class="fas fa-minus text-muted"></i> 0%
{% endif %}
{% trans "vs last period" %}
</small>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-left-warning">
<div class="card-body">
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">{% trans "Open" %}</div>
<div class="h5 mb-0 font-weight-bold">{{ dashboard_summary.status_counts.open }}</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-left-danger">
<div class="card-body">
<div class="text-xs font-weight-bold text-danger text-uppercase mb-1">{% trans "Overdue" %}</div>
<div class="h5 mb-0 font-weight-bold">{{ dashboard_summary.status_counts.overdue }}</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-left-success">
<div class="card-body">
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">{% trans "Resolved" %}</div>
<div class="h5 mb-0 font-weight-bold">{{ dashboard_summary.status_counts.resolved }}</div>
</div>
</div>
</div>
</div>
<div class="row mb-4">
<!-- Complaints Trend -->
<div class="col-lg-8">
<div class="card">
<div class="card-header">
<h6 class="m-0 font-weight-bold">{% trans "Complaints Trend" %}</h6>
</div>
<div class="card-body">
<div id="trendChart"></div>
</div>
</div>
</div>
<!-- Top Categories -->
<div class="col-lg-4">
<div class="card">
<div class="card-header">
<h6 class="m-0 font-weight-bold">{% trans "Top Categories" %}</h6>
</div>
<div class="card-body">
<div id="categoryChart"></div>
</div>
</div>
</div>
</div>
<div class="row mb-4">
<!-- SLA Compliance -->
<div class="col-lg-6">
<div class="card">
<div class="card-header">
<h6 class="m-0 font-weight-bold">{% trans "SLA Compliance" %}</h6>
</div>
<div class="card-body">
<div class="text-center mb-3">
<h2 class="{% if sla_compliance.overall_compliance_rate >= 80 %}text-success{% elif sla_compliance.overall_compliance_rate >= 60 %}text-warning{% else %}text-danger{% endif %}">
{{ sla_compliance.overall_compliance_rate }}%
</h2>
<p class="text-muted">{% trans "Overall Compliance Rate" %}</p>
</div>
<div class="row text-center">
<div class="col-6">
<h4 class="text-success">{{ sla_compliance.on_time }}</h4>
<small class="text-muted">{% trans "On Time" %}</small>
</div>
<div class="col-6">
<h4 class="text-danger">{{ sla_compliance.overdue }}</h4>
<small class="text-muted">{% trans "Overdue" %}</small>
</div>
</div>
</div>
</div>
</div>
<!-- Resolution Rate -->
<div class="col-lg-6">
<div class="card">
<div class="card-header">
<h6 class="m-0 font-weight-bold">{% trans "Resolution Metrics" %}</h6>
</div>
<div class="card-body">
<div class="mb-3">
<div class="d-flex justify-content-between mb-1">
<span>{% trans "Resolution Rate" %}</span>
<strong>{{ resolution_rate.resolution_rate }}%</strong>
</div>
<div class="progress">
<div class="progress-bar bg-success" style="width: {{ resolution_rate.resolution_rate }}%"></div>
</div>
</div>
<div class="row text-center">
<div class="col-6">
<h4>{{ resolution_rate.resolved }}</h4>
<small class="text-muted">{% trans "Resolved" %}</small>
</div>
<div class="col-6">
<h4>{{ resolution_rate.pending }}</h4>
<small class="text-muted">{% trans "Pending" %}</small>
</div>
</div>
{% if resolution_rate.avg_resolution_time_hours %}
<div class="mt-3 text-center">
<p class="mb-0"><strong>{% trans "Avg Resolution Time" %}:</strong></p>
<h5>{{ resolution_rate.avg_resolution_time_hours }} {% trans "hours" %}</h5>
</div>
{% endif %}
</div>
</div>
</div>
</div>
<!-- Overdue Complaints -->
{% if overdue_complaints %}
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h6 class="m-0 font-weight-bold text-danger">{% trans "Overdue Complaints" %}</h6>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>{% trans "ID" %}</th>
<th>{% trans "Title" %}</th>
<th>{% trans "Patient" %}</th>
<th>{% trans "Severity" %}</th>
<th>{% trans "Due Date" %}</th>
<th>{% trans "Assigned To" %}</th>
<th>{% trans "Actions" %}</th>
</tr>
</thead>
<tbody>
{% for complaint in overdue_complaints %}
<tr>
<td><small class="text-muted">{{ complaint.id|truncatechars:8 }}</small></td>
<td>{{ complaint.title|truncatechars:50 }}</td>
<td>{{ complaint.patient.get_full_name }}</td>
<td>
<span class="badge bg-{% if complaint.severity == 'critical' %}danger{% elif complaint.severity == 'high' %}warning{% else %}secondary{% endif %}">
{{ complaint.get_severity_display }}
</span>
</td>
<td class="text-danger">{{ complaint.due_at|date:"Y-m-d H:i" }}</td>
<td>{{ complaint.assigned_to.get_full_name|default:"Unassigned" }}</td>
<td>
<a href="{% url 'complaints:complaint_detail' complaint.id %}" class="btn btn-sm btn-primary">
<i class="fas fa-eye"></i>
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
{% endif %}
</div>
<script>
// Trend Chart - ApexCharts
var trendOptions = {
series: [{
name: '{% trans "Complaints" %}',
data: {{ trends.data|safe }}
}],
chart: {
type: 'line',
height: 320,
toolbar: {
show: false
}
},
stroke: {
curve: 'smooth',
width: 3
},
colors: ['#4bc0c0'],
{#fill: {#}
{# type: 'gradient',#}
{# gradient: {#}
{# shadeIntensity: 1,#}
{# opacityFrom: 0.4,#}
{# opacityTo: 0.1,#}
{# }#}
{# },#}
xaxis: {
categories: {{ trends.labels|safe }},
labels: {
style: {
fontSize: '12px'
}
}
},
yaxis: {
min: 0,
forceNiceScale: true,
labels: {
style: {
fontSize: '12px'
}
}
},
grid: {
borderColor: '#e7e7e7',
strokeDashArray: 5
},
tooltip: {
theme: 'light'
}
};
var trendChart = new ApexCharts(document.querySelector("#trendChart"), trendOptions);
trendChart.render();
// Category Chart - ApexCharts
var categoryOptions = {
series: [{% for cat in top_categories.categories %}{{ cat.count }}{% if not forloop.last %},{% endif %}{% endfor %}],
chart: {
type: 'donut',
height: 360
},
labels: [{% for cat in top_categories.categories %}'{{ cat.category }}'{% if not forloop.last %},{% endif %}{% endfor %}],
colors: ['#ff6384', '#36a2eb', '#ffce56', '#4bc0c0', '#9966ff', '#ff9f40'],
legend: {
position: 'bottom',
fontSize: '12px'
},
dataLabels: {
enabled: true,
formatter: function (val) {
return val.toFixed(1) + "%"
}
},
plotOptions: {
pie: {
donut: {
size: '65%'
}
}
},
tooltip: {
theme: 'light'
}
};
var categoryChart = new ApexCharts(document.querySelector("#categoryChart"), categoryOptions);
categoryChart.render();
</script>
{% endblock %}