This commit is contained in:
2026-08-31 15:11:52 +03:30
parent 236002a87c
commit 463b812e3e
63 changed files with 3254 additions and 1476 deletions
@@ -0,0 +1,143 @@
{% extends "admin/base_site.html" %}
{% load i18n %}
{% block content %}
<div dir="rtl" class="space-y-6">
<div class="flex items-center justify-between">
<p class="text-sm text-gray-500 dark:text-gray-400">
آمار {{ window_days }} روزِ اخیر — برای دیدنِ لیستِ خامِ جلسه‌ها
<a href="?raw=1" class="text-primary-600 dark:text-primary-400 underline">این‌جا</a> را بزن.
</p>
</div>
{# ---------------- خلاصه‌ی کلی ---------------- #}
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
{% for label, value in overview_cards %}
<div class="rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-base-800 p-4">
<p class="text-xs text-gray-500 dark:text-gray-400">{{ label }}</p>
<p class="text-2xl font-bold text-gray-900 dark:text-gray-50 mt-1">{{ value }}</p>
</div>
{% endfor %}
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
{# ---------------- صفحات پربازدید ---------------- #}
<div class="rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-base-800 p-4">
<h2 class="font-bold text-gray-900 dark:text-gray-50 mb-3">صفحاتِ پربازدید</h2>
{% if top_screens %}
<div class="space-y-2">
{% for s in top_screens %}
<div>
<div class="flex justify-between text-sm mb-1">
<span class="text-gray-700 dark:text-gray-200">{{ s.screen_name|default:"—" }}</span>
<span class="text-gray-500 dark:text-gray-400">
{{ s.count }} بازدید
{% if s.avg_duration %}· میانگین {{ s.avg_duration }} ثانیه{% endif %}
</span>
</div>
<div class="h-2 rounded-full bg-gray-100 dark:bg-base-700 overflow-hidden">
<div class="h-full bg-primary-500" style="width: {{ s.bar_percent }}%"></div>
</div>
</div>
{% endfor %}
</div>
{% else %}
<p class="text-sm text-gray-500 dark:text-gray-400">هنوز داده‌ای ثبت نشده.</p>
{% endif %}
</div>
{# ---------------- خطاهای اخیر ---------------- #}
<div class="rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-base-800 p-4">
<h2 class="font-bold text-gray-900 dark:text-gray-50 mb-3">خطاهای اخیرِ سمتِ کاربر</h2>
{% if recent_errors %}
<div class="space-y-2 max-h-80 overflow-y-auto">
{% for e in recent_errors %}
<div class="text-sm border-b border-gray-100 dark:border-gray-700 pb-2">
<div class="flex justify-between text-gray-500 dark:text-gray-400 text-xs">
<span>{{ e.screen_name|default:"—" }}</span>
<span>{{ e.created_at|date:"Y-m-d H:i" }}</span>
</div>
<p class="text-gray-800 dark:text-gray-200 truncate">{{ e.message }}</p>
</div>
{% endfor %}
</div>
{% else %}
<p class="text-sm text-gray-500 dark:text-gray-400">خطایی ثبت نشده — خوب است.</p>
{% endif %}
</div>
</div>
{# ---------------- عملکرد اندپوینت‌ها ---------------- #}
<div class="rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-base-800 p-4 overflow-x-auto">
<h2 class="font-bold text-gray-900 dark:text-gray-50 mb-3">عملکردِ اندپوینت‌ها</h2>
<table class="w-full text-sm">
<thead>
<tr class="text-gray-500 dark:text-gray-400 text-xs border-b border-gray-200 dark:border-gray-700">
<th class="text-right py-2">مسیر</th>
<th class="text-right py-2">متد</th>
<th class="text-right py-2">تعداد فراخوانی</th>
<th class="text-right py-2">میانگین زمان (ms)</th>
<th class="text-right py-2">بیشترین زمان (ms)</th>
<th class="text-right py-2">تعداد خطا</th>
</tr>
</thead>
<tbody>
{% for e in endpoints %}
<tr class="border-b border-gray-100 dark:border-gray-800">
<td class="py-2 text-gray-800 dark:text-gray-200" dir="ltr">{{ e.path }}</td>
<td class="py-2">{{ e.method }}</td>
<td class="py-2">{{ e.count }}</td>
<td class="py-2">{{ e.avg_ms }}</td>
<td class="py-2">{{ e.max_ms|floatformat:1 }}</td>
<td class="py-2 {% if e.error_count %}text-red-600 dark:text-red-400{% endif %}">{{ e.error_count }}</td>
</tr>
{% empty %}
<tr><td colspan="6" class="py-4 text-center text-gray-500 dark:text-gray-400">هنوز داده‌ای ثبت نشده.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
{# ---------------- به‌ازای هر کاربر ---------------- #}
<div class="rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-base-800 p-4 overflow-x-auto">
<h2 class="font-bold text-gray-900 dark:text-gray-50 mb-3">وضعیتِ هر کاربر</h2>
<table class="w-full text-sm">
<thead>
<tr class="text-gray-500 dark:text-gray-400 text-xs border-b border-gray-200 dark:border-gray-700">
<th class="text-right py-2">کاربر</th>
<th class="text-right py-2">زمان در اپ (دقیقه)</th>
<th class="text-right py-2">تعداد جلسه</th>
<th class="text-right py-2">صفحه‌بازدید</th>
<th class="text-right py-2">فراخوانی API</th>
<th class="text-right py-2">خطا</th>
<th class="text-right py-2">صفحه‌ی محبوب</th>
<th class="text-right py-2">تعداد دعوت</th>
<th class="text-right py-2">آی‌پی‌ها</th>
<th class="text-right py-2">آخرین حضور</th>
</tr>
</thead>
<tbody>
{% for row in user_rows %}
<tr class="border-b border-gray-100 dark:border-gray-800">
<td class="py-2 text-gray-800 dark:text-gray-200" dir="ltr">{{ row.user.phone }}</td>
<td class="py-2">{{ row.total_minutes }}</td>
<td class="py-2">{{ row.session_count }}</td>
<td class="py-2">{{ row.page_view_count }}</td>
<td class="py-2">{{ row.api_call_count }}</td>
<td class="py-2 {% if row.error_count %}text-red-600 dark:text-red-400{% endif %}">{{ row.error_count }}</td>
<td class="py-2">{{ row.top_screen }}</td>
<td class="py-2">{{ row.referral_count }}</td>
<td class="py-2" dir="ltr">{{ row.ips|join:", "|default:"—" }}</td>
<td class="py-2">{{ row.last_seen|date:"Y-m-d H:i"|default:"—" }}</td>
</tr>
{% empty %}
<tr><td colspan="10" class="py-4 text-center text-gray-500 dark:text-gray-400">هنوز کاربری در این بازه فعال نبوده.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}