Files
autoban/templates/stats.html
2026-01-01 02:13:34 +01:00

97 lines
4.5 KiB
HTML

{% extends "base.html" %}
{% block title %}Statystyki{% endblock %}
{% block content %}
<div class="card bg-dark border-secondary mb-4">
<div class="card-header">Rozkład geograficzny</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-dark align-middle mb-0" id="geo-table">
<thead>
<tr>
<th style="width:48%">Kraj</th>
<th style="width:40%">Udział</th>
<th class="text-end" style="width:12%">Liczba</th>
</tr>
</thead>
<tbody>
{% set ns = namespace(total_geo=0) %}
{% for _, c in stats.geo_distribution.items() %}{% set ns.total_geo = ns.total_geo + (c|int) %}{%
endfor %}
{% for country, count in stats.geo_distribution.items() %}
{% set pct = ((count|int) / (ns.total_geo if ns.total_geo>0 else 1) * 100) | round(1) %}
{% set pct = 0 if pct < 0 else (100 if pct> 100 else pct) %}
<tr>
<td><span class="d-inline-block text-truncate" style="max-width:95%"
title="{{ country }}">{{ country }}</span></td>
<td>
<div class="progress bg-black border border-secondary" style="height:10px;">
<div class="progress-bar bg-primary" role="progressbar" style="width: {{ pct }}%;"
aria-valuenow="{{ pct }}" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<div class="text-secondary small mt-1">{{ pct }}%</div>
</td>
<td class="text-end"><span class="badge bg-secondary">{{ count|int }}</span></td>
</tr>
{% endfor %}
{% if stats.geo_distribution|length == 0 %}
<tr>
<td colspan="3" class="text-center text-secondary">Brak danych</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
</div>
</div>
<!-- Reasons -->
<div class="card bg-dark border-secondary mb-4">
<div class="card-header">Przyczyny banów</div>
<div class="card-body">
{% set nsr = namespace(total=0) %}
{% for _, v in stats.ban_reasons.items() %}{% set nsr.total = nsr.total + (v|int) %}{% endfor %}
{% if stats.ban_reasons|length == 0 %}
<div class="text-center text-secondary small">Brak danych</div>
{% else %}
<div class="list-group list-group-flush">
{% for reason, count in (stats.ban_reasons|dictsort(by='value', reverse=true)) %}
{% set label = reason if reason else 'Manual ban' %}
{% set pct = ((count|int) / (nsr.total if nsr.total>0 else 1) * 100) | round(1) %}
{% set pct = 0 if pct < 0 else (100 if pct> 100 else pct) %}
<div class="list-group-item bg-dark text-white border-secondary">
<div class="d-flex justify-content-between align-items-center mb-1">
<span class="text-truncate" title="{{ label }}">{{ label }}</span>
<span class="small text-secondary">{{ count|int }} ({{ pct }}%)</span>
</div>
<div class="progress bg-black border border-secondary" style="height:10px;">
<div class="progress-bar bg-primary" role="progressbar" style="width: {{ pct }}%;"
aria-valuenow="{{ pct }}" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
{% endfor %}
</div>
{% endif %}
</div>
</div>
{% endblock %}
{% block scripts %}
{{ super() }}
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.6"></script>
<script>
// dane dla wykresu z Jinja -> JS
const reasonsData = (() => {
const entries = Object.entries({{ stats.ban_reasons | tojson }});
// posortuj malejąco
entries.sort((a, b) => (b[1] || 0) - (a[1] || 0));
const labels = entries.map(([k]) => k && k.length ? k : "Manual ban");
const data = entries.map(([, v]) => v);
return { labels, data };
}) ();
</script>
<script src="{{ url_for('static', filename='js/stats.js') }}" defer></script>
{% endblock %}