feat(dashboard): add country distribution bar chart using Chart.js

This commit is contained in:
2026-07-06 20:20:46 +08:00
parent 200602c1e6
commit 31eb6dcfc9
2 changed files with 40 additions and 0 deletions

View File

@@ -397,6 +397,13 @@ def dashboard(request: Request, user: User = Depends(get_current_user_web), db:
else: else:
sent_pct = delivered_pct = received_pct = 0 sent_pct = delivered_pct = received_pct = 0
# country stats
country_counts: dict[str, int] = {}
for c in all_cards:
if c.country:
country_counts[c.country] = country_counts.get(c.country, 0) + 1
country_stats = sorted(country_counts.items(), key=lambda x: -x[1])
from datetime import datetime, timezone as _tz from datetime import datetime, timezone as _tz
return templates.TemplateResponse("dashboard.html", { return templates.TemplateResponse("dashboard.html", {
@@ -404,6 +411,7 @@ def dashboard(request: Request, user: User = Depends(get_current_user_web), db:
"total": total, "sent": sent, "delivered": delivered, "received": received, "total": total, "sent": sent, "delivered": delivered, "received": received,
"countries": countries, "recent": recent, "countries": countries, "recent": recent,
"sent_pct": sent_pct, "delivered_pct": delivered_pct, "received_pct": received_pct, "sent_pct": sent_pct, "delivered_pct": delivered_pct, "received_pct": received_pct,
"country_stats": country_stats,
"now": datetime.now(_tz.utc), "now": datetime.now(_tz.utc),
}) })

View File

@@ -59,6 +59,13 @@
</div> </div>
{% endif %} {% endif %}
{% if country_stats %}
<div style="background:var(--card-bg);border:1px solid var(--border);border-radius:10px;padding:1.25rem;margin-bottom:1.5rem">
<h2 style="margin-bottom:.75rem">🌍 国家/地区分布</h2>
<canvas id="country-chart" height="100"></canvas>
</div>
{% endif %}
<div class="dash-sections"> <div class="dash-sections">
<div class="dash-section"> <div class="dash-section">
<h2>最近动态</h2> <h2>最近动态</h2>
@@ -129,4 +136,29 @@
<p class="empty-sub">创建一个 <a href="/profiles">Profile</a> 开始管理你的明信片</p> <p class="empty-sub">创建一个 <a href="/profiles">Profile</a> 开始管理你的明信片</p>
</div> </div>
{% endif %} {% endif %}
{% if country_stats %}
<script src="https://cdn.jsdelivr.net/npm/chart.js@4"></script>
<script>
new Chart(document.getElementById('country-chart'), {
type: 'bar',
data: {
labels: [{% for code, _ in country_stats %}'{{ code }}',{% endfor %}],
datasets: [{
data: [{% for _, count in country_stats %}{{ count }},{% endfor %}],
backgroundColor: '#3b82f6',
borderRadius: 4,
maxBarThickness: 40
}]
},
options: {
responsive: true,
plugins: { legend: { display: false } },
scales: {
y: { beginAtZero: true, ticks: { stepSize: 1 } },
x: { grid: { display: false } }
}
}
});
</script>
{% endif %}
{% endblock %} {% endblock %}