288 lines
15 KiB
HTML
288 lines
15 KiB
HTML
{% extends "layouts/base.html" %}
|
|
{% load i18n %}
|
|
|
|
{% block title %}Inquiry Reports - 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 "Inquiry Reports" %}</h1>
|
|
<p class="text-sm text-gray-500 mt-1">{% trans "Incoming & Outgoing inquiry analysis from HIS data" %}</p>
|
|
</div>
|
|
<div class="flex gap-3">
|
|
<a href="{% url 'inquiries:inquiry_export_incoming' %}?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 Incoming" %}
|
|
</a>
|
|
<a href="{% url 'inquiries:inquiry_export_outgoing' %}?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: #059669; color: white;">
|
|
<i data-lucide="download" class="w-4 h-4" style="color: white;"></i>
|
|
{% trans "Export Outgoing" %}
|
|
</a>
|
|
</div>
|
|
</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="help-circle" class="w-8 h-8 text-gray-400"></i>
|
|
</div>
|
|
<h3 class="text-lg font-semibold text-gray-700 mb-2">{% trans "No Inquiry Data Available" %}</h3>
|
|
<p class="text-gray-500">{% trans "There are no inquiry records in the database for the selected hospital." %}</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 focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
|
{% 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 focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
|
{% 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 %}
|
|
{% if not available_months %}
|
|
<option value="{{ selected_month }}" selected>{{ selected_month }}</option>
|
|
{% endif %}
|
|
</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-4 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="log-in" class="w-5 h-5 text-blue-600"></i>
|
|
</div>
|
|
<div>
|
|
<p class="text-xs text-gray-500 font-medium">{% trans "Incoming Total" %}</p>
|
|
<p class="text-2xl font-bold text-gray-800">{{ incoming_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="log-out" class="w-5 h-5 text-emerald-600"></i>
|
|
</div>
|
|
<div>
|
|
<p class="text-xs text-gray-500 font-medium">{% trans "Outgoing Total" %}</p>
|
|
<p class="text-2xl font-bold text-gray-800">{{ outgoing_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-amber-100 rounded-lg flex items-center justify-center">
|
|
<i data-lucide="clock" class="w-5 h-5 text-amber-600"></i>
|
|
</div>
|
|
<div>
|
|
<p class="text-xs text-gray-500 font-medium">{% trans "1st / 2nd Half" %}</p>
|
|
<p class="text-lg font-bold text-gray-800">{{ incoming.first_half }} / {{ incoming.second_half }}</p>
|
|
<p class="text-[10px] text-gray-400">{% trans "Incoming split" %}</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="check-circle" class="w-5 h-5 text-purple-600"></i>
|
|
</div>
|
|
<div>
|
|
<p class="text-xs text-gray-500 font-medium">{% trans "SLA Compliance" %}</p>
|
|
<p class="text-2xl font-bold text-gray-800">{{ incoming.sla_compliance }}%</p>
|
|
<p class="text-[10px] text-gray-400">{% trans "Incoming contacted rate" %}</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 "Incoming - Daily Trend" %}</h3>
|
|
<div id="incoming-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 "Outgoing - Daily Trend" %}</h3>
|
|
<div id="outgoing-daily-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 "Incoming by Status" %}</h3>
|
|
<div id="incoming-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 "Outgoing by Status" %}</h3>
|
|
<div id="outgoing-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 "Timeline SLA Distribution" %}</h3>
|
|
<div id="sla-chart"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
|
|
{% if employee_breakdown %}
|
|
<div class="bg-white rounded-xl shadow-sm border border-gray-200">
|
|
<div class="p-5 border-b border-gray-200">
|
|
<h3 class="text-lg font-semibold text-gray-800">{% trans "Incoming - Per Employee" %}</h3>
|
|
</div>
|
|
<div class="overflow-x-auto">
|
|
<table class="w-full text-sm">
|
|
<thead>
|
|
<tr class="bg-[#2F75B5] text-white">
|
|
<th class="px-4 py-3 text-left font-semibold">{% trans "Employee" %}</th>
|
|
<th class="px-4 py-3 text-center font-semibold">{% trans "No Response" %}</th>
|
|
<th class="px-4 py-3 text-center font-semibold">{% trans "In Progress" %}</th>
|
|
<th class="px-4 py-3 text-center font-semibold">{% trans "Contacted" %}</th>
|
|
<th class="px-4 py-3 text-center font-semibold bg-emerald-600">{% trans "Total" %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for row in employee_breakdown %}
|
|
<tr class="border-b border-gray-100 {% cycle '' 'bg-gray-50' %}">
|
|
<td class="px-4 py-3 font-medium text-gray-700">{{ row.name }}</td>
|
|
<td class="px-4 py-3 text-center text-red-600">{{ row.contacted_no_response }}</td>
|
|
<td class="px-4 py-3 text-center text-amber-600">{{ row.in_progress }}</td>
|
|
<td class="px-4 py-3 text-center text-emerald-600">{{ row.contacted }}</td>
|
|
<td class="px-4 py-3 text-center font-semibold bg-emerald-50 text-emerald-700">{{ row.total_fmt }}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if department_breakdown %}
|
|
<div class="bg-white rounded-xl shadow-sm border border-gray-200">
|
|
<div class="p-5 border-b border-gray-200">
|
|
<h3 class="text-lg font-semibold text-gray-800">{% trans "Outgoing - Per Department" %}</h3>
|
|
</div>
|
|
<div class="overflow-x-auto">
|
|
<table class="w-full text-sm">
|
|
<thead>
|
|
<tr class="bg-[#2F75B5] text-white">
|
|
<th class="px-4 py-3 text-left font-semibold">{% trans "Department" %}</th>
|
|
<th class="px-4 py-3 text-center font-semibold">{% trans "No Response" %}</th>
|
|
<th class="px-4 py-3 text-center font-semibold">{% trans "In Progress" %}</th>
|
|
<th class="px-4 py-3 text-center font-semibold">{% trans "Contacted" %}</th>
|
|
<th class="px-4 py-3 text-center font-semibold bg-emerald-600">{% trans "Total" %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for row in department_breakdown %}
|
|
<tr class="border-b border-gray-100 {% cycle '' 'bg-gray-50' %}">
|
|
<td class="px-4 py-3 font-medium text-gray-700">{{ row.name }}</td>
|
|
<td class="px-4 py-3 text-center text-red-600">{{ row.contacted_no_response }}</td>
|
|
<td class="px-4 py-3 text-center text-amber-600">{{ row.in_progress }}</td>
|
|
<td class="px-4 py-3 text-center text-emerald-600">{{ row.contacted }}</td>
|
|
<td class="px-4 py-3 text-center font-semibold bg-emerald-50 text-emerald-700">{{ row.total_fmt }}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</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('incoming-daily-chart'), {
|
|
chart: { type: 'bar', height: 280, toolbar: { show: true } },
|
|
plotOptions: { bar: { borderRadius: 3 } },
|
|
dataLabels: { enabled: false },
|
|
series: [{ name: 'Incoming', data: cd.incoming_daily, color: '#3B82F6' }],
|
|
xaxis: { type: 'category' },
|
|
yaxis: { labels: { formatter: function(v) { return v.toLocaleString(); } } },
|
|
tooltip: { y: { formatter: function(v) { return v + ' inquiries'; } } },
|
|
}).render();
|
|
|
|
new ApexCharts(document.getElementById('outgoing-daily-chart'), {
|
|
chart: { type: 'bar', height: 280, toolbar: { show: true } },
|
|
plotOptions: { bar: { borderRadius: 3 } },
|
|
dataLabels: { enabled: false },
|
|
series: [{ name: 'Outgoing', data: cd.outgoing_daily, color: '#10B981' }],
|
|
xaxis: { type: 'category' },
|
|
yaxis: { labels: { formatter: function(v) { return v.toLocaleString(); } } },
|
|
tooltip: { y: { formatter: function(v) { return v + ' inquiries'; } } },
|
|
}).render();
|
|
|
|
new ApexCharts(document.getElementById('incoming-status-chart'), {
|
|
chart: { type: 'donut', height: 280 },
|
|
series: cd.incoming_by_status.map(function(d) { return d.y; }),
|
|
labels: cd.incoming_by_status.map(function(d) { return d.x; }),
|
|
colors: ['#94A3B8', '#F59E0B', '#10B981', '#3B82F6', '#EF4444', '#6366F1'],
|
|
legend: { position: 'bottom' },
|
|
}).render();
|
|
|
|
new ApexCharts(document.getElementById('outgoing-status-chart'), {
|
|
chart: { type: 'donut', height: 280 },
|
|
series: cd.outgoing_by_status.map(function(d) { return d.y; }),
|
|
labels: cd.outgoing_by_status.map(function(d) { return d.x; }),
|
|
colors: ['#94A3B8', '#F59E0B', '#10B981', '#3B82F6', '#EF4444', '#6366F1'],
|
|
legend: { position: 'bottom' },
|
|
}).render();
|
|
|
|
var incSla = cd.incoming_by_sla.map(function(d) { return d.y; });
|
|
var outSla = cd.outgoing_by_sla.map(function(d) { return d.y; });
|
|
var slaCats = cd.incoming_by_sla.length >= cd.outgoing_by_sla.length
|
|
? cd.incoming_by_sla.map(function(d) { return d.x; })
|
|
: cd.outgoing_by_sla.map(function(d) { return d.x; });
|
|
|
|
new ApexCharts(document.getElementById('sla-chart'), {
|
|
chart: { type: 'bar', height: 280, toolbar: { show: false } },
|
|
plotOptions: { bar: { borderRadius: 3 } },
|
|
dataLabels: { enabled: false },
|
|
series: [
|
|
{ name: 'Incoming', data: incSla, color: '#3B82F6' },
|
|
{ name: 'Outgoing', data: outSla, color: '#10B981' },
|
|
],
|
|
xaxis: { categories: slaCats },
|
|
yaxis: { labels: { formatter: function(v) { return v.toLocaleString(); } } },
|
|
legend: { position: 'bottom' },
|
|
}).render();
|
|
})();
|
|
</script>
|
|
{% endif %}
|
|
{% endblock %}
|