HH/templates/dashboard/complaint_monthly_report.html
ismail c5f76b3855
Some checks are pending
Build and Push Docker Image / build (push) Waiting to run
updates
2026-05-11 14:45:30 +03:00

204 lines
10 KiB
HTML

{% extends "layouts/base.html" %}
{% load i18n %}
{% block title %}Complaint Monthly Calculations - PX360{% endblock %}
{% block content %}
<div class="max-w-[1400px] mx-auto">
<div class="flex justify-between items-center mb-6">
<div>
<h1 class="text-2xl font-bold text-gray-800">{% trans "Complaint Monthly Calculations" %}</h1>
<p class="text-sm text-gray-500 mt-1">{% trans "Step 1 — Complaint lifecycle tracking with stage timing" %}</p>
</div>
<a href="{% url 'dashboard:complaint_monthly_export' %}?hospital={{ selected_hospital }}&year={{ selected_year }}&month={{ selected_month }}"
class="inline-flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium transition"
style="background-color: #2563eb; color: white;">
<i data-lucide="download" class="w-4 h-4" style="color: white;"></i>
{% trans "Export Excel" %}
</a>
</div>
{% if no_data %}
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-12 text-center">
<div class="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-4">
<i data-lucide="file-text" class="w-8 h-8 text-gray-400"></i>
</div>
<h3 class="text-lg font-semibold text-gray-700 mb-2">{% trans "No Complaint Data" %}</h3>
<p class="text-gray-500">{% trans "There are no complaint records for the selected hospital and period." %}</p>
</div>
{% else %}
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-4 mb-6">
<form method="get" class="flex flex-wrap gap-4 items-end">
<div class="flex-1 min-w-[200px]">
<label class="block text-xs font-semibold text-gray-600 mb-1">{% trans "Hospital" %}</label>
<select name="hospital" class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500" data-tomselect>
{% for h in hospitals %}
<option value="{{ h.id }}" {% if selected_hospital == h.id|stringformat:'s' %}selected{% endif %}>{{ h.name }}</option>
{% endfor %}
</select>
</div>
<div class="w-28">
<label class="block text-xs font-semibold text-gray-600 mb-1">{% trans "Year" %}</label>
<select name="year" class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm">
{% for y in available_months %}
<option value="{{ y.year }}" {% if selected_year == y.year %}selected{% endif %}>{{ y.year }}</option>
{% endfor %}
{% if selected_year != available_months.0.year %}
<option value="{{ selected_year }}" selected>{{ selected_year }}</option>
{% endif %}
</select>
</div>
<div class="w-36">
<label class="block text-xs font-semibold text-gray-600 mb-1">{% trans "Month" %}</label>
<select name="month" class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm">
{% for m in available_months %}
{% if m.year == selected_year %}
<option value="{{ m.month }}" {% if selected_month == m.month %}selected{% endif %}>{{ m.label }}</option>
{% endif %}
{% endfor %}
</select>
</div>
<button type="submit" class="px-4 py-2 bg-navy text-white text-sm font-medium rounded-lg hover:bg-navy/90 transition">
{% trans "Apply" %}
</button>
</form>
</div>
<div class="grid grid-cols-1 md:grid-cols-5 gap-4 mb-6">
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-5">
<div class="flex items-center gap-3">
<div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center">
<i data-lucide="file-text" class="w-5 h-5 text-blue-600"></i>
</div>
<div>
<p class="text-xs text-gray-500 font-medium">{% trans "Total Complaints" %}</p>
<p class="text-2xl font-bold text-gray-800">{{ total_fmt }}</p>
</div>
</div>
</div>
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-5">
<div class="flex items-center gap-3">
<div class="w-10 h-10 bg-emerald-100 rounded-lg flex items-center justify-center">
<i data-lucide="check-circle" class="w-5 h-5 text-emerald-600"></i>
</div>
<div>
<p class="text-xs text-gray-500 font-medium">{% trans "Resolution Rate" %}</p>
<p class="text-2xl font-bold text-gray-800">{{ summary.resolution_rate }}%</p>
</div>
</div>
</div>
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-5">
<div class="flex items-center gap-3">
<div class="w-10 h-10 bg-orange-100 rounded-lg flex items-center justify-center">
<i data-lucide="zap" class="w-5 h-5 text-orange-600"></i>
</div>
<div>
<p class="text-xs text-gray-500 font-medium">{% trans "Activation Rate" %}</p>
<p class="text-2xl font-bold text-gray-800">{{ summary.activation_rate }}%</p>
</div>
</div>
</div>
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-5">
<div class="flex items-center gap-3">
<div class="w-10 h-10 bg-red-100 rounded-lg flex items-center justify-center">
<i data-lucide="alert-triangle" class="w-5 h-5 text-red-600"></i>
</div>
<div>
<p class="text-xs text-gray-500 font-medium">{% trans "Escalated" %}</p>
<p class="text-2xl font-bold text-gray-800">{{ summary.escalated }}</p>
</div>
</div>
</div>
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-5">
<div class="flex items-center gap-3">
<div class="w-10 h-10 bg-purple-100 rounded-lg flex items-center justify-center">
<i data-lucide="clock" class="w-5 h-5 text-purple-600"></i>
</div>
<div>
<p class="text-xs text-gray-500 font-medium">{% trans "Avg Close Time" %}</p>
<p class="text-2xl font-bold text-gray-800">{{ stage_times.total_close|default:"—" }}h</p>
</div>
</div>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-5">
<h3 class="text-sm font-semibold text-gray-700 mb-4">{% trans "Daily Trend" %}</h3>
<div id="daily-chart"></div>
</div>
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-5">
<h3 class="text-sm font-semibold text-gray-700 mb-4">{% trans "Stage Funnel" %}</h3>
<div id="funnel-chart"></div>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-6">
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-5">
<h3 class="text-sm font-semibold text-gray-700 mb-4">{% trans "By Status" %}</h3>
<div id="status-chart"></div>
</div>
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-5">
<h3 class="text-sm font-semibold text-gray-700 mb-4">{% trans "By Source Type" %}</h3>
<div id="source-chart"></div>
</div>
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-5">
<h3 class="text-sm font-semibold text-gray-700 mb-4">{% trans "By Satisfaction" %}</h3>
<div id="satisfaction-chart"></div>
</div>
</div>
{% endif %}
</div>
{% endblock %}
{% block extra_js %}
{% if not no_data and chart_data_json %}
<script>
(function() {
var cd = JSON.parse('{{ chart_data_json|escapejs }}');
new ApexCharts(document.getElementById('daily-chart'), {
chart: { type: 'bar', height: 280, toolbar: { show: true } },
plotOptions: { bar: { borderRadius: 3 } },
dataLabels: { enabled: false },
series: [{ name: 'Complaints', data: cd.daily, color: '#3B82F6' }],
xaxis: { type: 'category' },
tooltip: { y: { formatter: function(v) { return v + ' complaints'; } } },
}).render();
new ApexCharts(document.getElementById('funnel-chart'), {
chart: { type: 'bar', height: 280, toolbar: { show: false } },
plotOptions: { bar: { borderRadius: 3, horizontal: true } },
dataLabels: { enabled: true },
series: [{ name: 'Count', data: cd.funnel.counts.map(function(v, i) { return { x: cd.funnel.labels[i], y: v }; }), color: '#6366F1' }],
}).render();
new ApexCharts(document.getElementById('status-chart'), {
chart: { type: 'donut', height: 280 },
series: cd.by_status.map(function(d) { return d.y; }),
labels: cd.by_status.map(function(d) { return d.x; }),
legend: { position: 'bottom' },
}).render();
new ApexCharts(document.getElementById('source-chart'), {
chart: { type: 'pie', height: 280 },
series: cd.by_source.map(function(d) { return d.y; }),
labels: cd.by_source.map(function(d) { return d.x; }),
colors: ['#3B82F6', '#10B981'],
legend: { position: 'bottom' },
}).render();
new ApexCharts(document.getElementById('satisfaction-chart'), {
chart: { type: 'donut', height: 280 },
series: cd.by_satisfaction.map(function(d) { return d.y; }),
labels: cd.by_satisfaction.map(function(d) { return d.x; }),
colors: ['#10B981', '#F59E0B', '#EF4444', '#94A3B8', '#6366F1'],
legend: { position: 'bottom' },
}).render();
})();
</script>
{% endif %}
{% endblock %}