317 lines
15 KiB
HTML
317 lines
15 KiB
HTML
{% extends "layouts/base.html" %}
|
|
{% load i18n %}
|
|
|
|
{% block title %}{{ staff.name }} - {% trans "Performance Detail" %} - PX360{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid">
|
|
<!-- Header -->
|
|
<div class="row mb-4">
|
|
<div class="col">
|
|
<nav aria-label="breadcrumb">
|
|
<ol class="breadcrumb">
|
|
<li class="breadcrumb-item"><a href="{% url 'dashboard:admin_evaluation' %}">{% trans "Admin Evaluation" %}</a></li>
|
|
<li class="breadcrumb-item active">{{ staff.name }}</li>
|
|
</ol>
|
|
</nav>
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<h2 class="h3 mb-1">{{ staff.name }}</h2>
|
|
<p class="text-muted mb-0">
|
|
{{ staff.role }} |
|
|
{{ staff.department|default:_("No Department") }} |
|
|
{{ staff.hospital|default:_("No Hospital") }}
|
|
</p>
|
|
</div>
|
|
<div>
|
|
<select class="form-select" id="dateRange" onchange="changeDateRange(this.value)">
|
|
<option value="7d" {% if date_range == '7d' %}selected{% endif %}>{% trans "Last 7 Days" %}</option>
|
|
<option value="30d" {% if date_range == '30d' %}selected{% endif %}>{% trans "Last 30 Days" %}</option>
|
|
<option value="90d" {% if date_range == '90d' %}selected{% endif %}>{% trans "Last 90 Days" %}</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Performance Score Card -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-4">
|
|
<div class="card h-100">
|
|
<div class="card-body text-center">
|
|
<h5 class="card-title">{% trans "Performance Score" %}</h5>
|
|
<div class="display-1 fw-bold text-{{ performance.performance_score.rating_color }}">
|
|
{{ performance.performance_score.overall }}
|
|
</div>
|
|
<span class="badge bg-{{ performance.performance_score.rating_color }} fs-6">
|
|
{{ performance.performance_score.rating }}
|
|
</span>
|
|
<p class="text-muted mt-2 mb-0">
|
|
{% trans "Based on" %} {{ performance.performance_score.total_items_handled }} {% trans "items handled" %}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-8">
|
|
<div class="card h-100">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">{% trans "Score Breakdown" %}</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row g-3">
|
|
<div class="col-md-4">
|
|
<div class="d-flex justify-content-between">
|
|
<span>{% trans "Complaint Resolution" %}</span>
|
|
<span class="fw-bold">{{ performance.performance_score.breakdown.complaint_resolution|floatformat:0 }}%</span>
|
|
</div>
|
|
<div class="progress" style="height: 8px;">
|
|
<div class="progress-bar" style="width: {{ performance.performance_score.breakdown.complaint_resolution }}%"></div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="d-flex justify-content-between">
|
|
<span>{% trans "Complaint Response" %}</span>
|
|
<span class="fw-bold">{{ performance.performance_score.breakdown.complaint_response_time|floatformat:0 }}%</span>
|
|
</div>
|
|
<div class="progress" style="height: 8px;">
|
|
<div class="progress-bar bg-info" style="width: {{ performance.performance_score.breakdown.complaint_response_time }}%"></div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="d-flex justify-content-between">
|
|
<span>{% trans "Inquiry Resolution" %}</span>
|
|
<span class="fw-bold">{{ performance.performance_score.breakdown.inquiry_resolution|floatformat:0 }}%</span>
|
|
</div>
|
|
<div class="progress" style="height: 8px;">
|
|
<div class="progress-bar bg-success" style="width: {{ performance.performance_score.breakdown.inquiry_resolution }}%"></div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="d-flex justify-content-between">
|
|
<span>{% trans "Inquiry Response" %}</span>
|
|
<span class="fw-bold">{{ performance.performance_score.breakdown.inquiry_response_time|floatformat:0 }}%</span>
|
|
</div>
|
|
<div class="progress" style="height: 8px;">
|
|
<div class="progress-bar bg-warning" style="width: {{ performance.performance_score.breakdown.inquiry_response_time }}%"></div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="d-flex justify-content-between">
|
|
<span>{% trans "Activation Time" %}</span>
|
|
<span class="fw-bold">{{ performance.performance_score.breakdown.complaint_activation_time|floatformat:0 }}%</span>
|
|
</div>
|
|
<div class="progress" style="height: 8px;">
|
|
<div class="progress-bar bg-secondary" style="width: {{ performance.performance_score.breakdown.complaint_activation_time }}%"></div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="d-flex justify-content-between">
|
|
<span>{% trans "Workload" %}</span>
|
|
<span class="fw-bold">{{ performance.performance_score.breakdown.workload|floatformat:0 }}%</span>
|
|
</div>
|
|
<div class="progress" style="height: 8px;">
|
|
<div class="progress-bar bg-dark" style="width: {{ performance.performance_score.breakdown.workload }}%"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Summary Stats -->
|
|
<div class="row g-3 mb-4">
|
|
<div class="col-md-3">
|
|
<div class="card bg-primary text-white">
|
|
<div class="card-body">
|
|
<h6 class="card-title">{% trans "Total Complaints" %}</h6>
|
|
<h3 class="mb-0">{{ performance.summary.total_complaints }}</h3>
|
|
<small>{{ performance.summary.complaint_resolution_rate }}% {% trans "resolution rate" %}</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card bg-info text-white">
|
|
<div class="card-body">
|
|
<h6 class="card-title">{% trans "Total Inquiries" %}</h6>
|
|
<h3 class="mb-0">{{ performance.summary.total_inquiries }}</h3>
|
|
<small>{{ performance.summary.inquiry_resolution_rate }}% {% trans "resolution rate" %}</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card bg-warning text-dark">
|
|
<div class="card-body">
|
|
<h6 class="card-title">{% trans "Period" %}</h6>
|
|
<h3 class="mb-0">{{ performance.period.days }}</h3>
|
|
<small>{% trans "days" %}</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card bg-success text-white">
|
|
<div class="card-body">
|
|
<h6 class="card-title">{% trans "Items/Day" %}</h6>
|
|
<h3 class="mb-0">
|
|
{% with total=performance.summary.total_complaints|add:performance.summary.total_inquiries %}
|
|
{% if performance.period.days > 0 %}
|
|
{{ total|div:performance.period.days|floatformat:1 }}
|
|
{% else %}
|
|
0
|
|
{% endif %}
|
|
{% endwith %}
|
|
</h3>
|
|
<small>{% trans "average workload" %}</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Trends Chart -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">{% trans "6-Month Performance Trend" %}</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<canvas id="trendsChart" height="100"></canvas>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Items -->
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">{% trans "Recent Complaints" %}</h5>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<div class="list-group list-group-flush">
|
|
{% for complaint in performance.recent_complaints %}
|
|
<a href="{% url 'complaints:detail' complaint.id %}" class="list-group-item list-group-item-action">
|
|
<div class="d-flex w-100 justify-content-between">
|
|
<h6 class="mb-1">{{ complaint.title|truncatechars:50 }}</h6>
|
|
<small class="text-muted">{{ complaint.created_at|slice:":10" }}</small>
|
|
</div>
|
|
<span class="badge bg-{% if complaint.status == 'open' %}warning{% elif complaint.status == 'resolved' %}success{% else %}secondary{% endif %}">
|
|
{{ complaint.status }}
|
|
</span>
|
|
{% if complaint.severity == 'critical' %}
|
|
<span class="badge bg-danger">{% trans "Critical" %}</span>
|
|
{% endif %}
|
|
</a>
|
|
{% empty %}
|
|
<div class="list-group-item text-muted">
|
|
{% trans "No complaints in selected period" %}
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">{% trans "Recent Inquiries" %}</h5>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<div class="list-group list-group-flush">
|
|
{% for inquiry in performance.recent_inquiries %}
|
|
<a href="{% url 'complaints:inquiry_detail' inquiry.id %}" class="list-group-item list-group-item-action">
|
|
<div class="d-flex w-100 justify-content-between">
|
|
<h6 class="mb-1">{{ inquiry.subject|truncatechars:50 }}</h6>
|
|
<small class="text-muted">{{ inquiry.created_at|slice:":10" }}</small>
|
|
</div>
|
|
<span class="badge bg-{% if inquiry.status == 'open' %}warning{% elif inquiry.status == 'resolved' %}success{% else %}secondary{% endif %}">
|
|
{{ inquiry.status }}
|
|
</span>
|
|
</a>
|
|
{% empty %}
|
|
<div class="list-group-item text-muted">
|
|
{% trans "No inquiries in selected period" %}
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
<script>
|
|
const trendsData = {{ trends|safe }};
|
|
|
|
function changeDateRange(range) {
|
|
window.location.href = '?date_range=' + range;
|
|
}
|
|
|
|
// Initialize trends chart
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const ctx = document.getElementById('trendsChart').getContext('2d');
|
|
|
|
new Chart(ctx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: trendsData.map(t => t.month_name),
|
|
datasets: [
|
|
{
|
|
label: '{% trans "Performance Score" %}',
|
|
data: trendsData.map(t => t.performance_score),
|
|
borderColor: '#2563eb',
|
|
backgroundColor: 'rgba(37, 99, 235, 0.1)',
|
|
fill: true,
|
|
tension: 0.4
|
|
},
|
|
{
|
|
label: '{% trans "Complaints" %}',
|
|
data: trendsData.map(t => t.complaints_total),
|
|
borderColor: '#dc2626',
|
|
backgroundColor: 'transparent',
|
|
borderDash: [5, 5],
|
|
yAxisID: 'y1'
|
|
},
|
|
{
|
|
label: '{% trans "Inquiries" %}',
|
|
data: trendsData.map(t => t.inquiries_total),
|
|
borderColor: '#16a34a',
|
|
backgroundColor: 'transparent',
|
|
borderDash: [2, 2],
|
|
yAxisID: 'y1'
|
|
}
|
|
]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
interaction: {
|
|
mode: 'index',
|
|
intersect: false
|
|
},
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true,
|
|
max: 100,
|
|
title: {
|
|
display: true,
|
|
text: '{% trans "Score" %}'
|
|
}
|
|
},
|
|
y1: {
|
|
beginAtZero: true,
|
|
position: 'right',
|
|
title: {
|
|
display: true,
|
|
text: '{% trans "Count" %}'
|
|
},
|
|
grid: {
|
|
drawOnChartArea: false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %}
|