180 lines
6.5 KiB
Twig
180 lines
6.5 KiB
Twig
{% 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 %}
|