mirror of
https://github.com/agessaman/meshcore-bot.git
synced 2026-03-30 20:15:40 +00:00
- Added a new 'daily_stats' table for tracking daily advertisement statistics. - Implemented methods to track daily advertisement counts and retrieve statistics over specified date ranges. - Updated existing advertisement tracking logic to utilize the new daily statistics. - Modified web viewer to display advertisement metrics using the new daily tracking data. - Improved path command logic to prioritize database queries over API cache for path decoding.
333 lines
11 KiB
HTML
333 lines
11 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Statistics - MeshCore Bot Data Viewer{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<h1 class="mb-4">
|
|
<i class="fas fa-chart-bar"></i> Statistics
|
|
</h1>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Key Metrics -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-3">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<i class="fas fa-users"></i> Total Contacts
|
|
</div>
|
|
<div class="card-body">
|
|
<h3 id="total-contacts">0</h3>
|
|
<small class="text-muted">All time</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-3">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<i class="fas fa-comments"></i> Total Adverts
|
|
</div>
|
|
<div class="card-body">
|
|
<h3 id="total-adverts">0</h3>
|
|
<small class="text-muted">All time</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-3">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<i class="fas fa-clock"></i> Recent Activity
|
|
</div>
|
|
<div class="card-body">
|
|
<h3 id="recent-activity">0</h3>
|
|
<small class="text-muted">Last 24 hours</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-3">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<i class="fas fa-chart-line"></i> Growth Rate
|
|
</div>
|
|
<div class="card-body">
|
|
<h3 id="growth-rate">0%</h3>
|
|
<small class="text-muted">Daily growth</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Activity Charts -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<i class="fas fa-chart-pie"></i> Activity Distribution
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="activity-chart">
|
|
<div class="loading">Loading activity chart...</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<i class="fas fa-chart-line"></i> Usage Trends
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="trends-chart">
|
|
<div class="loading">Loading trends chart...</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Detailed Statistics -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<i class="fas fa-table"></i> Detailed Statistics
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<h6>Contact Statistics</h6>
|
|
<ul class="list-unstyled" id="contact-stats">
|
|
<li class="loading">Loading contact statistics...</li>
|
|
</ul>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<h6>Advert Statistics</h6>
|
|
<ul class="list-unstyled" id="advert-stats">
|
|
<li class="loading">Loading advert statistics...</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- System Performance -->
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<i class="fas fa-server"></i> System Performance
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="system-performance">
|
|
<div class="loading">Loading system performance...</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<i class="fas fa-cog"></i> Configuration
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="system-config">
|
|
<div class="loading">Loading system configuration...</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
<script>
|
|
class ModernStatsManager {
|
|
constructor() {
|
|
this.statsData = {};
|
|
this.initializeStats();
|
|
}
|
|
|
|
async initializeStats() {
|
|
await this.loadStatsData();
|
|
this.setupEventHandlers();
|
|
this.updateStatistics();
|
|
this.renderCharts();
|
|
this.renderDetailedStats();
|
|
this.renderSystemInfo();
|
|
}
|
|
|
|
async loadStatsData() {
|
|
try {
|
|
const response = await fetch('/api/stats');
|
|
const data = await response.json();
|
|
|
|
if (data.error) {
|
|
this.showError('Failed to load statistics: ' + data.error);
|
|
return;
|
|
}
|
|
|
|
this.statsData = data;
|
|
|
|
} catch (error) {
|
|
console.error('Error loading statistics:', error);
|
|
this.showError('Failed to load statistics: ' + error.message);
|
|
}
|
|
}
|
|
|
|
setupEventHandlers() {
|
|
// Auto-refresh every 30 seconds
|
|
setInterval(() => {
|
|
this.loadStatsData().then(() => {
|
|
this.updateStatistics();
|
|
this.renderCharts();
|
|
this.renderDetailedStats();
|
|
this.renderSystemInfo();
|
|
});
|
|
}, 30000);
|
|
}
|
|
|
|
updateStatistics() {
|
|
document.getElementById('total-contacts').textContent = this.statsData.contact_count || 0;
|
|
document.getElementById('total-adverts').textContent = this.statsData.total_advertisements || 0;
|
|
document.getElementById('recent-activity').textContent = this.statsData.recent_contacts_24h || 0;
|
|
|
|
// Calculate growth rate
|
|
const recentContacts = this.statsData.recent_contacts_24h || 0;
|
|
const totalContacts = this.statsData.contact_count || 0;
|
|
const growthRate = totalContacts > 0 ? Math.round((recentContacts / totalContacts) * 100) : 0;
|
|
document.getElementById('growth-rate').textContent = growthRate + '%';
|
|
}
|
|
|
|
renderCharts() {
|
|
// Activity distribution chart
|
|
const activityChart = document.getElementById('activity-chart');
|
|
const recentContacts = this.statsData.recent_contacts_24h || 0;
|
|
const recentAdverts = this.statsData.advertisements_24h || 0;
|
|
const total = recentContacts + recentAdverts;
|
|
|
|
if (total > 0) {
|
|
const contactsPercent = Math.round((recentContacts / total) * 100);
|
|
const advertsPercent = Math.round((recentAdverts / total) * 100);
|
|
|
|
activityChart.innerHTML = `
|
|
<div class="row">
|
|
<div class="col-6">
|
|
<div class="text-center">
|
|
<h4 class="text-primary">${contactsPercent}%</h4>
|
|
<small class="text-muted">Contacts</small>
|
|
</div>
|
|
</div>
|
|
<div class="col-6">
|
|
<div class="text-center">
|
|
<h4 class="text-warning">${advertsPercent}%</h4>
|
|
<small class="text-muted">Adverts</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
} else {
|
|
activityChart.innerHTML = '<div class="text-muted text-center">No recent activity</div>';
|
|
}
|
|
|
|
// Trends chart
|
|
const trendsChart = document.getElementById('trends-chart');
|
|
const growthRate = this.statsData.contact_count > 0 ?
|
|
Math.round(((this.statsData.recent_contacts_24h || 0) / this.statsData.contact_count) * 100) : 0;
|
|
|
|
trendsChart.innerHTML = `
|
|
<div class="text-center">
|
|
<h4 class="text-${growthRate > 0 ? 'success' : 'secondary'}">${growthRate}%</h4>
|
|
<small class="text-muted">Daily growth rate</small>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
renderDetailedStats() {
|
|
// Contact statistics
|
|
const contactStats = document.getElementById('contact-stats');
|
|
contactStats.innerHTML = `
|
|
<li><strong>Total Contacts:</strong> ${this.statsData.contact_count || 0}</li>
|
|
<li><strong>Recent (24h):</strong> ${this.statsData.recent_contacts_24h || 0}</li>
|
|
<li><strong>Growth Rate:</strong> ${this.calculateGrowthRate()}%</li>
|
|
<li><strong>Last Updated:</strong> ${new Date().toLocaleString()}</li>
|
|
`;
|
|
|
|
// Advert statistics
|
|
const advertStats = document.getElementById('advert-stats');
|
|
advertStats.innerHTML = `
|
|
<li><strong>Total Adverts:</strong> ${this.statsData.total_advertisements || 0}</li>
|
|
<li><strong>Recent (24h):</strong> ${this.statsData.advertisements_24h || 0}</li>
|
|
<li><strong>Active Users:</strong> ${this.statsData.active_users_24h || 0}</li>
|
|
<li><strong>Last Updated:</strong> ${new Date().toLocaleString()}</li>
|
|
`;
|
|
}
|
|
|
|
renderSystemInfo() {
|
|
// System performance
|
|
const systemPerformance = document.getElementById('system-performance');
|
|
systemPerformance.innerHTML = `
|
|
<ul class="list-unstyled">
|
|
<li><strong>Connected Clients:</strong> ${this.statsData.connected_clients || 0}</li>
|
|
<li><strong>Database Status:</strong> <span class="badge bg-success">Healthy</span></li>
|
|
<li><strong>Last Activity:</strong> ${new Date().toLocaleString()}</li>
|
|
<li><strong>Uptime:</strong> ${this.calculateUptime()}</li>
|
|
</ul>
|
|
`;
|
|
|
|
// System configuration
|
|
const systemConfig = document.getElementById('system-config');
|
|
systemConfig.innerHTML = `
|
|
<ul class="list-unstyled">
|
|
<li><strong>Version:</strong> Modern v2.0</li>
|
|
<li><strong>Flask-SocketIO:</strong> 5.x</li>
|
|
<li><strong>Database:</strong> SQLite</li>
|
|
<li><strong>Real-time:</strong> <span class="badge bg-success">Enabled</span></li>
|
|
</ul>
|
|
`;
|
|
}
|
|
|
|
calculateGrowthRate() {
|
|
const recentContacts = this.statsData.recent_contacts_24h || 0;
|
|
const totalContacts = this.statsData.contact_count || 0;
|
|
return totalContacts > 0 ? Math.round((recentContacts / totalContacts) * 100) : 0;
|
|
}
|
|
|
|
calculateUptime() {
|
|
// This would be calculated based on actual system uptime
|
|
return 'Unknown';
|
|
}
|
|
|
|
showError(message) {
|
|
const errorDiv = document.createElement('div');
|
|
errorDiv.className = 'error';
|
|
errorDiv.textContent = message;
|
|
|
|
const content = document.querySelector('.container-fluid');
|
|
if (content) {
|
|
content.insertBefore(errorDiv, content.firstChild);
|
|
|
|
setTimeout(() => {
|
|
if (errorDiv.parentNode) {
|
|
errorDiv.parentNode.removeChild(errorDiv);
|
|
}
|
|
}, 5000);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Initialize stats manager when page loads
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
window.statsManager = new ModernStatsManager();
|
|
});
|
|
</script>
|
|
{% endblock %}
|