358 Zeilen
11 KiB
HTML
358 Zeilen
11 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Analytics{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<style>
|
|
.analytics-card {
|
|
background: white;
|
|
border-radius: 10px;
|
|
padding: 20px;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
margin-bottom: 20px;
|
|
height: 100%;
|
|
}
|
|
|
|
.chart-container {
|
|
position: relative;
|
|
height: 300px;
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.stat-box {
|
|
text-align: center;
|
|
padding: 15px;
|
|
background: #f8f9fa;
|
|
border-radius: 8px;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.stat-value {
|
|
font-size: 2rem;
|
|
font-weight: bold;
|
|
color: #495057;
|
|
}
|
|
|
|
.stat-label {
|
|
font-size: 0.875rem;
|
|
color: #6c757d;
|
|
text-transform: uppercase;
|
|
margin-top: 5px;
|
|
}
|
|
|
|
.trend-up {
|
|
color: #28a745;
|
|
}
|
|
|
|
.trend-down {
|
|
color: #dc3545;
|
|
}
|
|
|
|
.date-range-selector {
|
|
background: white;
|
|
padding: 15px;
|
|
border-radius: 8px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.export-buttons {
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.grafana-info {
|
|
background: #e7f3ff;
|
|
border: 1px solid #b3d9ff;
|
|
padding: 15px;
|
|
border-radius: 8px;
|
|
margin-bottom: 20px;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="row mb-4">
|
|
<div class="col">
|
|
<h2><i class="bi bi-bar-chart-line"></i> Analytics</h2>
|
|
<p class="text-muted">Detaillierte Analyse und Berichte</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Grafana Integration Info -->
|
|
<div class="grafana-info">
|
|
<div class="row align-items-center">
|
|
<div class="col-md-8">
|
|
<h5><i class="bi bi-graph-up"></i> Erweiterte Analytics verfügbar</h5>
|
|
<p class="mb-0">Für detaillierte Dashboards und erweiterte Analysen nutzen Sie unser Grafana Dashboard.</p>
|
|
</div>
|
|
<div class="col-md-4 text-end">
|
|
<a href="http://localhost:3000/d/license-server-overview" target="_blank" class="btn btn-primary">
|
|
<i class="bi bi-box-arrow-up-right"></i> Grafana öffnen
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Date Range Selector -->
|
|
<div class="date-range-selector">
|
|
<div class="row align-items-center">
|
|
<div class="col-md-6">
|
|
<label>Zeitraum auswählen:</label>
|
|
<select class="form-select" id="date-range" onchange="updateAnalytics()">
|
|
<option value="today">Heute</option>
|
|
<option value="week" selected>Letzte 7 Tage</option>
|
|
<option value="month">Letzte 30 Tage</option>
|
|
<option value="quarter">Letztes Quartal</option>
|
|
<option value="year">Letztes Jahr</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-6 text-end">
|
|
<button class="btn btn-outline-primary" onclick="refreshAnalytics()">
|
|
<i class="bi bi-arrow-clockwise"></i> Aktualisieren
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Key Metrics Overview -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-3">
|
|
<div class="stat-box">
|
|
<div class="stat-value">1,234</div>
|
|
<div class="stat-label">Aktive Lizenzen</div>
|
|
<div class="trend-up">
|
|
<i class="bi bi-arrow-up"></i> +12% vs. Vormonat
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="stat-box">
|
|
<div class="stat-value">45.2K</div>
|
|
<div class="stat-label">Validierungen</div>
|
|
<div class="trend-up">
|
|
<i class="bi bi-arrow-up"></i> +8% vs. Vormonat
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="stat-box">
|
|
<div class="stat-value">€12.5K</div>
|
|
<div class="stat-label">MRR</div>
|
|
<div class="trend-up">
|
|
<i class="bi bi-arrow-up"></i> +15% vs. Vormonat
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="stat-box">
|
|
<div class="stat-value">2.3%</div>
|
|
<div class="stat-label">Churn Rate</div>
|
|
<div class="trend-down">
|
|
<i class="bi bi-arrow-down"></i> -0.5% vs. Vormonat
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Charts Row 1 -->
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="analytics-card">
|
|
<h5>Lizenz-Nutzung über Zeit</h5>
|
|
<div class="chart-container">
|
|
<canvas id="usageChart"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="analytics-card">
|
|
<h5>Validierungen nach Stunde</h5>
|
|
<div class="chart-container">
|
|
<canvas id="validationChart"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Charts Row 2 -->
|
|
<div class="row mt-4">
|
|
<div class="col-md-4">
|
|
<div class="analytics-card">
|
|
<h5>Lizenztyp-Verteilung</h5>
|
|
<div class="chart-container">
|
|
<canvas id="licenseTypeChart"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="analytics-card">
|
|
<h5>Geografische Verteilung</h5>
|
|
<div class="chart-container">
|
|
<canvas id="geoChart"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="analytics-card">
|
|
<h5>Top 10 Kunden</h5>
|
|
<div style="height: 300px; overflow-y: auto;">
|
|
<table class="table table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>Kunde</th>
|
|
<th>Lizenzen</th>
|
|
<th>Nutzung</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>ACME Corp</td>
|
|
<td>45</td>
|
|
<td><span class="badge bg-success">Hoch</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td>TechStart GmbH</td>
|
|
<td>32</td>
|
|
<td><span class="badge bg-success">Hoch</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td>Global Solutions</td>
|
|
<td>28</td>
|
|
<td><span class="badge bg-warning">Mittel</span></td>
|
|
</tr>
|
|
<!-- More rows... -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Export Options -->
|
|
<div class="analytics-card mt-4">
|
|
<h5>Berichte exportieren</h5>
|
|
<div class="export-buttons">
|
|
<button class="btn btn-outline-primary me-2" onclick="exportReport('pdf')">
|
|
<i class="bi bi-file-pdf"></i> PDF Export
|
|
</button>
|
|
<button class="btn btn-outline-success me-2" onclick="exportReport('excel')">
|
|
<i class="bi bi-file-excel"></i> Excel Export
|
|
</button>
|
|
<button class="btn btn-outline-info" onclick="exportReport('csv')">
|
|
<i class="bi bi-file-text"></i> CSV Export
|
|
</button>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.js"></script>
|
|
<script>
|
|
let usageChart, validationChart, licenseTypeChart, geoChart;
|
|
|
|
function initCharts() {
|
|
// Usage over time
|
|
const usageCtx = document.getElementById('usageChart').getContext('2d');
|
|
usageChart = new Chart(usageCtx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'],
|
|
datasets: [{
|
|
label: 'Aktive Lizenzen',
|
|
data: [1180, 1205, 1195, 1220, 1234, 1150, 1100],
|
|
borderColor: 'rgb(75, 192, 192)',
|
|
backgroundColor: 'rgba(75, 192, 192, 0.1)',
|
|
tension: 0.1
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false
|
|
}
|
|
});
|
|
|
|
// Validations by hour
|
|
const validationCtx = document.getElementById('validationChart').getContext('2d');
|
|
validationChart = new Chart(validationCtx, {
|
|
type: 'bar',
|
|
data: {
|
|
labels: ['00', '04', '08', '12', '16', '20'],
|
|
datasets: [{
|
|
label: 'Validierungen',
|
|
data: [120, 80, 450, 680, 520, 340],
|
|
backgroundColor: 'rgba(54, 162, 235, 0.5)',
|
|
borderColor: 'rgba(54, 162, 235, 1)',
|
|
borderWidth: 1
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false
|
|
}
|
|
});
|
|
|
|
// License type distribution
|
|
const typeCtx = document.getElementById('licenseTypeChart').getContext('2d');
|
|
licenseTypeChart = new Chart(typeCtx, {
|
|
type: 'doughnut',
|
|
data: {
|
|
labels: ['Professional', 'Enterprise', 'Starter', 'Trial'],
|
|
datasets: [{
|
|
data: [45, 30, 20, 5],
|
|
backgroundColor: [
|
|
'rgba(255, 99, 132, 0.5)',
|
|
'rgba(54, 162, 235, 0.5)',
|
|
'rgba(255, 205, 86, 0.5)',
|
|
'rgba(75, 192, 192, 0.5)'
|
|
]
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false
|
|
}
|
|
});
|
|
|
|
// Geographic distribution
|
|
const geoCtx = document.getElementById('geoChart').getContext('2d');
|
|
geoChart = new Chart(geoCtx, {
|
|
type: 'bar',
|
|
data: {
|
|
labels: ['DE', 'AT', 'CH', 'US', 'UK'],
|
|
datasets: [{
|
|
label: 'Aktive Nutzer',
|
|
data: [580, 230, 180, 120, 90],
|
|
backgroundColor: 'rgba(153, 102, 255, 0.5)',
|
|
borderColor: 'rgba(153, 102, 255, 1)',
|
|
borderWidth: 1
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
indexAxis: 'y'
|
|
}
|
|
});
|
|
}
|
|
|
|
function updateAnalytics() {
|
|
const range = document.getElementById('date-range').value;
|
|
// In production, this would fetch new data based on the selected range
|
|
console.log('Updating analytics for range:', range);
|
|
}
|
|
|
|
function refreshAnalytics() {
|
|
// Refresh all data
|
|
location.reload();
|
|
}
|
|
|
|
function exportReport(format) {
|
|
alert(`Exporting report as ${format.toUpperCase()}...`);
|
|
// In production, this would trigger actual export
|
|
}
|
|
|
|
// Initialize charts on page load
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
initCharts();
|
|
});
|
|
</script>
|
|
{% endblock %} |