bp/app/Views/superadmin/statistics.twig

180 lines
6.5 KiB
Twig
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends 'superadmin/layout.twig' %}
{% block content %}
<div class="sa-header">
<h1>Статистика</h1>
</div>
<div class="grid-2" style="margin-top: 20px;">
<div class="sa-card">
<div class="sa-card-header">
<h2>Распределение по тарифам</h2>
</div>
<div class="sa-card-body">
{% if planStats is empty %}
<p style="color: #7f8c8d; text-align: center; padding: 40px;">Нет данных о тарифах</p>
{% else %}
<table class="table">
<thead>
<tr>
<th>Тариф</th>
<th>Организаций</th>
<th>Доля</th>
</tr>
</thead>
<tbody>
{% set totalOrgs = 0 %}
{% for plan in planStats %}
{% set totalOrgs = totalOrgs + plan.orgs_count %}
{% endfor %}
{% for plan in planStats %}
{% set percent = totalOrgs > 0 ? (plan.orgs_count / totalOrgs * 100)|round(1) : 0 %}
<tr>
<td>{{ plan.name }}</td>
<td>{{ plan.orgs_count }}</td>
<td>
<div style="display: flex; align-items: center; gap: 10px;">
<div style="flex: 1; background: #eee; height: 20px; border-radius: 10px; overflow: hidden;">
<div style="width: {{ percent }}%; background: #3498db; height: 100%;"></div>
</div>
<span style="min-width: 40px;">{{ percent }}%</span>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>
</div>
<div class="sa-card">
<div class="sa-card-header">
<h2>Сводка</h2>
</div>
<div class="sa-card-body">
<div style="padding: 20px;">
<div style="display: flex; justify-content: space-between; padding: 15px 0; border-bottom: 1px solid #eee;">
<span>Всего пользователей (30 дней)</span>
<strong>
{% set totalUsers = 0 %}
{% for stat in dailyStats %}
{% set totalUsers = totalUsers + stat.users %}
{% endfor %}
{{ totalUsers|number_format(0, '', ' ') }}
</strong>
</div>
<div style="display: flex; justify-content: space-between; padding: 15px 0; border-bottom: 1px solid #eee;">
<span>Всего организаций (30 дней)</span>
<strong>
{% set totalOrgs = 0 %}
{% for stat in dailyStats %}
{% set totalOrgs = totalOrgs + stat.orgs %}
{% endfor %}
{{ totalOrgs|number_format(0, '', ' ') }}
</strong>
</div>
<div style="display: flex; justify-content: space-between; padding: 15px 0; border-bottom: 1px solid #eee;">
<span>Среднее организаций на пользователя</span>
<strong>
{{ totalUsers > 0 ? (totalOrgs / totalUsers)|round(2) : 0 }}
</strong>
</div>
</div>
</div>
</div>
</div>
<div class="sa-card">
<div class="sa-card-header">
<h2>Регистрации по дням (последние 30 дней)</h2>
</div>
<div style="margin-bottom: 30px;">
<canvas id="statsChart" width="800" height="300"></canvas>
</div>
<div class="sa-card-body">
<div style="overflow-x: auto;">
<table class="table">
<thead>
<tr>
<th>Дата</th>
<th>Новые пользователи</th>
<th>Новые организации</th>
</tr>
</thead>
<tbody>
{% for stat in dailyStats %}
<tr>
<td>{{ stat.date|date('d.m.Y') }}</td>
<td>{{ stat.users }}</td>
<td>{{ stat.orgs }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const ctx = document.getElementById('statsChart').getContext('2d');
const labels = [
{% for stat in dailyStats %}
'{{ stat.date|date('d.m') }}'{% if not loop.last %},{% endif %}
{% endfor %}
];
const usersData = [
{% for stat in dailyStats %}
{{ stat.users }}{% if not loop.last %},{% endif %}
{% endfor %}
];
const orgsData = [
{% for stat in dailyStats %}
{{ stat.orgs }}{% if not loop.last %},{% endif %}
{% endfor %}
];
new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [
{
label: 'Пользователи',
data: usersData,
borderColor: '#3498db',
backgroundColor: 'rgba(52, 152, 219, 0.1)',
tension: 0.4,
fill: true
},
{
label: 'Организации',
data: orgsData,
borderColor: '#27ae60',
backgroundColor: 'rgba(39, 174, 96, 0.1)',
tension: 0.4,
fill: true
}
]
},
options: {
responsive: true,
plugins: {
legend: {
position: 'top'
}
},
scales: {
y: {
beginAtZero: true
}
}
}
});
});
</script>
{% endblock %}