499 lines
22 KiB
HTML
499 lines
22 KiB
HTML
{% extends 'base.html' %}
|
|
{% load static %}
|
|
|
|
{% block title %}Message Analytics{% endblock %}
|
|
|
|
{% block css %}
|
|
<link href="{% static 'assets/plugins/datatables.net-bs5/css/dataTables.bootstrap5.min.css' %}" rel="stylesheet" />
|
|
<link href="{% static 'assets/plugins/datatables.net-responsive-bs5/css/responsive.bootstrap5.min.css' %}" rel="stylesheet" />
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div id="content" class="app-content">
|
|
<div class="container">
|
|
<ul class="breadcrumb">
|
|
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'communications:message_list' %}">Messages</a></li>
|
|
<li class="breadcrumb-item active">Analytics</li>
|
|
</ul>
|
|
|
|
<div class="row align-items-center mb-3">
|
|
<div class="col">
|
|
<h1 class="page-header">Message Analytics</h1>
|
|
<p class="text-muted">Track message delivery, engagement, and communication effectiveness</p>
|
|
</div>
|
|
<div class="col-auto">
|
|
<div class="btn-group">
|
|
<button type="button" class="btn btn-outline-primary" onclick="exportReport('pdf')">
|
|
<i class="fa fa-file-pdf me-2"></i>Export PDF
|
|
</button>
|
|
<button type="button" class="btn btn-outline-success" onclick="exportReport('excel')">
|
|
<i class="fa fa-file-excel me-2"></i>Export Excel
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Date Range Filter -->
|
|
<div class="card mb-4">
|
|
<div class="card-body">
|
|
<form method="get" class="row g-3 align-items-end">
|
|
<div class="col-md-3">
|
|
<label class="form-label">From Date</label>
|
|
<input type="date" name="start_date" class="form-control" value="{{ start_date }}">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label class="form-label">To Date</label>
|
|
<input type="date" name="end_date" class="form-control" value="{{ end_date }}">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label class="form-label">Message Type</label>
|
|
<select name="message_type" class="form-select">
|
|
<option value="">All Types</option>
|
|
<option value="announcement" {% if message_type == 'announcement' %}selected{% endif %}>Announcement</option>
|
|
<option value="alert" {% if message_type == 'alert' %}selected{% endif %}>Alert</option>
|
|
<option value="notification" {% if message_type == 'notification' %}selected{% endif %}>Notification</option>
|
|
<option value="reminder" {% if message_type == 'reminder' %}selected{% endif %}>Reminder</option>
|
|
<option value="emergency" {% if message_type == 'emergency' %}selected{% endif %}>Emergency</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fa fa-filter me-2"></i>Apply Filter
|
|
</button>
|
|
<a href="{% url 'communications:message_analytics' %}" class="btn btn-outline-secondary ms-2">
|
|
<i class="fa fa-times me-2"></i>Clear
|
|
</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Key Metrics -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-3">
|
|
<div class="card text-center">
|
|
<div class="card-body">
|
|
<div class="fs-28px fw-600 text-primary">{{ total_messages }}</div>
|
|
<div class="text-muted">Total Messages</div>
|
|
<div class="progress mt-2" style="height: 4px;">
|
|
<div class="progress-bar bg-primary" style="width: 100%"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card text-center">
|
|
<div class="card-body">
|
|
<div class="fs-28px fw-600 text-success">{{ delivered_messages }}</div>
|
|
<div class="text-muted">Delivered</div>
|
|
<div class="progress mt-2" style="height: 4px;">
|
|
<div class="progress-bar bg-success" style="width: {{ delivery_rate }}%"></div>
|
|
</div>
|
|
<small class="text-muted">{{ delivery_rate }}% delivery rate</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card text-center">
|
|
<div class="card-body">
|
|
<div class="fs-28px fw-600 text-info">{{ read_messages }}</div>
|
|
<div class="text-muted">Read</div>
|
|
<div class="progress mt-2" style="height: 4px;">
|
|
<div class="progress-bar bg-info" style="width: {{ read_rate }}%"></div>
|
|
</div>
|
|
<small class="text-muted">{{ read_rate }}% read rate</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card text-center">
|
|
<div class="card-body">
|
|
<div class="fs-28px fw-600 text-warning">{{ acknowledged_messages }}</div>
|
|
<div class="text-muted">Acknowledged</div>
|
|
<div class="progress mt-2" style="height: 4px;">
|
|
<div class="progress-bar bg-warning" style="width: {{ acknowledgment_rate }}%"></div>
|
|
</div>
|
|
<small class="text-muted">{{ acknowledgment_rate }}% ack rate</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Charts Row -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Message Volume Trend</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<canvas id="messageVolumeChart" height="300"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Message Types Distribution</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<canvas id="messageTypesChart" height="300"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mb-4">
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Delivery Performance</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<canvas id="deliveryPerformanceChart" height="300"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Response Time Analysis</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<canvas id="responseTimeChart" height="300"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Department Performance -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Department Performance</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-striped" id="departmentTable">
|
|
<thead>
|
|
<tr>
|
|
<th>Department</th>
|
|
<th>Messages Sent</th>
|
|
<th>Delivery Rate</th>
|
|
<th>Read Rate</th>
|
|
<th>Avg Response Time</th>
|
|
<th>Engagement Score</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for dept in department_stats %}
|
|
<tr>
|
|
<td>
|
|
<div class="d-flex align-items-center">
|
|
<div class="w-40px h-40px bg-{{ dept.color|default:'primary' }} bg-opacity-20 d-flex align-items-center justify-content-center rounded me-3">
|
|
<i class="fa fa-building text-{{ dept.color|default:'primary' }}"></i>
|
|
</div>
|
|
<div>
|
|
<div class="fw-bold">{{ dept.name }}</div>
|
|
<div class="text-muted small">{{ dept.user_count }} users</div>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td>{{ dept.messages_sent }}</td>
|
|
<td>
|
|
<div class="d-flex align-items-center">
|
|
<div class="flex-fill me-2">
|
|
<div class="progress" style="height: 6px;">
|
|
<div class="progress-bar bg-success" style="width: {{ dept.delivery_rate }}%"></div>
|
|
</div>
|
|
</div>
|
|
<div class="text-muted small">{{ dept.delivery_rate }}%</div>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div class="d-flex align-items-center">
|
|
<div class="flex-fill me-2">
|
|
<div class="progress" style="height: 6px;">
|
|
<div class="progress-bar bg-info" style="width: {{ dept.read_rate }}%"></div>
|
|
</div>
|
|
</div>
|
|
<div class="text-muted small">{{ dept.read_rate }}%</div>
|
|
</div>
|
|
</td>
|
|
<td>{{ dept.avg_response_time }}</td>
|
|
<td>
|
|
<span class="badge bg-{{ dept.engagement_color }}">{{ dept.engagement_score }}</span>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Messages Performance -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Recent Messages Performance</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-striped" id="messagesTable">
|
|
<thead>
|
|
<tr>
|
|
<th>Message</th>
|
|
<th>Type</th>
|
|
<th>Sent Date</th>
|
|
<th>Recipients</th>
|
|
<th>Delivered</th>
|
|
<th>Read</th>
|
|
<th>Acknowledged</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for message in recent_messages %}
|
|
<tr>
|
|
<td>
|
|
<div class="fw-bold">{{ message.subject|truncatechars:50 }}</div>
|
|
<div class="text-muted small">{{ message.sender.get_full_name }}</div>
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-{{ message.type_color }}">{{ message.get_message_type_display }}</span>
|
|
</td>
|
|
<td>{{ message.created_at|date:"M d, Y g:i A" }}</td>
|
|
<td>{{ message.recipient_count }}</td>
|
|
<td>
|
|
<div class="text-center">
|
|
<div class="fs-14px fw-600 text-success">{{ message.delivered_count }}</div>
|
|
<div class="text-muted small">{{ message.delivery_percentage }}%</div>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div class="text-center">
|
|
<div class="fs-14px fw-600 text-info">{{ message.read_count }}</div>
|
|
<div class="text-muted small">{{ message.read_percentage }}%</div>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div class="text-center">
|
|
<div class="fs-14px fw-600 text-warning">{{ message.acknowledged_count }}</div>
|
|
<div class="text-muted small">{{ message.acknowledgment_percentage }}%</div>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div class="btn-group">
|
|
<button type="button" class="btn btn-outline-primary btn-sm" onclick="viewMessageDetails('{{ message.id }}')">
|
|
<i class="fa fa-eye"></i>
|
|
</button>
|
|
<button type="button" class="btn btn-outline-info btn-sm" onclick="viewRecipients('{{ message.id }}')">
|
|
<i class="fa fa-users"></i>
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Communication Channels Performance -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Communication Channels Performance</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<div class="w-80px h-80px bg-primary bg-opacity-20 d-flex align-items-center justify-content-center rounded-circle mx-auto mb-3">
|
|
<i class="fa fa-bell fa-2x text-primary"></i>
|
|
</div>
|
|
<h5>In-App</h5>
|
|
<div class="fs-20px fw-600 text-primary">{{ in_app_stats.delivery_rate }}%</div>
|
|
<div class="text-muted small">{{ in_app_stats.total_sent }} sent</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<div class="w-80px h-80px bg-info bg-opacity-20 d-flex align-items-center justify-content-center rounded-circle mx-auto mb-3">
|
|
<i class="fa fa-envelope fa-2x text-info"></i>
|
|
</div>
|
|
<h5>Email</h5>
|
|
<div class="fs-20px fw-600 text-info">{{ email_stats.delivery_rate }}%</div>
|
|
<div class="text-muted small">{{ email_stats.total_sent }} sent</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<div class="w-80px h-80px bg-success bg-opacity-20 d-flex align-items-center justify-content-center rounded-circle mx-auto mb-3">
|
|
<i class="fa fa-mobile fa-2x text-success"></i>
|
|
</div>
|
|
<h5>SMS</h5>
|
|
<div class="fs-20px fw-600 text-success">{{ sms_stats.delivery_rate }}%</div>
|
|
<div class="text-muted small">{{ sms_stats.total_sent }} sent</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<div class="w-80px h-80px bg-warning bg-opacity-20 d-flex align-items-center justify-content-center rounded-circle mx-auto mb-3">
|
|
<i class="fa fa-mobile-alt fa-2x text-warning"></i>
|
|
</div>
|
|
<h5>Push</h5>
|
|
<div class="fs-20px fw-600 text-warning">{{ push_stats.delivery_rate }}%</div>
|
|
<div class="text-muted small">{{ push_stats.total_sent }} sent</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block js %}
|
|
<script src="{% static 'assets/plugins/datatables.net/js/jquery.dataTables.min.js' %}"></script>
|
|
<script src="{% static 'assets/plugins/datatables.net-bs5/js/dataTables.bootstrap5.min.js' %}"></script>
|
|
<script src="{% static 'assets/plugins/chart.js/dist/chart.min.js' %}"></script>
|
|
|
|
<script>
|
|
$(document).ready(function() {
|
|
// Initialize DataTables
|
|
$('#departmentTable, #messagesTable').DataTable({
|
|
responsive: true,
|
|
pageLength: 10,
|
|
order: [[0, 'asc']]
|
|
});
|
|
|
|
// Initialize Charts
|
|
initializeCharts();
|
|
});
|
|
|
|
function initializeCharts() {
|
|
// Message Volume Trend Chart
|
|
const volumeCtx = document.getElementById('messageVolumeChart').getContext('2d');
|
|
new Chart(volumeCtx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: {{ volume_chart_labels|safe }},
|
|
datasets: [{
|
|
label: 'Messages Sent',
|
|
data: {{ volume_chart_data|safe }},
|
|
borderColor: '#348fe2',
|
|
backgroundColor: 'rgba(52, 143, 226, 0.1)',
|
|
tension: 0.4
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Message Types Chart
|
|
const typesCtx = document.getElementById('messageTypesChart').getContext('2d');
|
|
new Chart(typesCtx, {
|
|
type: 'doughnut',
|
|
data: {
|
|
labels: {{ types_chart_labels|safe }},
|
|
datasets: [{
|
|
data: {{ types_chart_data|safe }},
|
|
backgroundColor: [
|
|
'#348fe2',
|
|
'#00acac',
|
|
'#f59c1a',
|
|
'#ff5b57',
|
|
'#727cb6'
|
|
]
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
plugins: {
|
|
legend: {
|
|
position: 'bottom'
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Delivery Performance Chart
|
|
const deliveryCtx = document.getElementById('deliveryPerformanceChart').getContext('2d');
|
|
new Chart(deliveryCtx, {
|
|
type: 'bar',
|
|
data: {
|
|
labels: ['Sent', 'Delivered', 'Read', 'Acknowledged'],
|
|
datasets: [{
|
|
label: 'Count',
|
|
data: [{{ total_messages }}, {{ delivered_messages }}, {{ read_messages }}, {{ acknowledged_messages }}],
|
|
backgroundColor: [
|
|
'#727cb6',
|
|
'#00acac',
|
|
'#348fe2',
|
|
'#f59c1a'
|
|
]
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Response Time Chart
|
|
const responseCtx = document.getElementById('responseTimeChart').getContext('2d');
|
|
new Chart(responseCtx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: {{ response_time_labels|safe }},
|
|
datasets: [{
|
|
label: 'Avg Response Time (hours)',
|
|
data: {{ response_time_data|safe }},
|
|
borderColor: '#f59c1a',
|
|
backgroundColor: 'rgba(245, 156, 26, 0.1)',
|
|
tension: 0.4
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function viewMessageDetails(messageId) {
|
|
window.open('{% url "communications:message_detail" 0 %}'.replace('0', messageId), '_blank');
|
|
}
|
|
|
|
function viewRecipients(messageId) {
|
|
window.open('{% url "communications:message_recipients" 0 %}'.replace('0', messageId), '_blank');
|
|
}
|
|
|
|
function exportReport(format) {
|
|
var params = new URLSearchParams(window.location.search);
|
|
params.set('export', format);
|
|
window.location.href = '{% url "communications:message_analytics" %}?' + params.toString();
|
|
}
|
|
</script>
|
|
{% endblock %}
|
|
|