Dashboard improvements
This commit is contained in:
parent
d37d0f95f1
commit
3154cfac22
@ -65,9 +65,22 @@ a.danger {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.dashboard-context {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.dashboard-context h2 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: #6b7280;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.dashboard-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 500px));
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
gap: 20px
|
||||
}
|
||||
|
||||
@ -79,7 +92,7 @@ a.danger {
|
||||
}
|
||||
|
||||
.card-chart {
|
||||
max-width: 500px;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.card-chart canvas {
|
||||
@ -87,6 +100,11 @@ a.danger {
|
||||
height: 220px !important;
|
||||
}
|
||||
|
||||
.chart-box {
|
||||
height: 300px;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.tag{
|
||||
display: inline-block;
|
||||
padding: 2px 6px;
|
||||
@ -104,7 +122,7 @@ a.danger {
|
||||
|
||||
.kpi-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-file, minmax(180px, 1fr));
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
gap: 1rem;
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
@ -128,6 +146,18 @@ a.danger {
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
/* .comparison strong {
|
||||
color:#b91c1c;
|
||||
} */
|
||||
|
||||
.comparison strong.positive {
|
||||
color: #166534;
|
||||
}
|
||||
|
||||
.comparison strong.negative {
|
||||
color:#b91c1c;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
@ -205,4 +235,52 @@ tbody tr:hover {
|
||||
.message.warning {
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
}
|
||||
|
||||
.dashboard-filters {
|
||||
margin: 1rem 0 1.5rem;
|
||||
padding: 1rem;
|
||||
background: #f9fafb;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.dashboard-filters form {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.75rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dashboard-filters select,
|
||||
.dashboard-filters button {
|
||||
padding: 0.4rem 0.6rem;
|
||||
}
|
||||
|
||||
.dashboard-filters .checkbox {
|
||||
display: flex;
|
||||
gap: 0.3rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dashboard-presets {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.preset {
|
||||
padding: 0.35rem 0.6rem;
|
||||
border-radius: 6px;
|
||||
background: #e5e7eb;
|
||||
text-decoration: none;
|
||||
color: #111827;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.preset:hover {
|
||||
background: #d1d5db;
|
||||
}
|
||||
|
||||
.preset.active {
|
||||
background: #2563eb;
|
||||
color: white;
|
||||
}
|
||||
@ -3,45 +3,70 @@
|
||||
{% block title %}Dashboard{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
|
||||
<section class="dashboard-context">
|
||||
<h2>
|
||||
{% if selected_account_obj %}
|
||||
{{ selected_account_obj.name }}
|
||||
{% else %}
|
||||
Todas las cuentas
|
||||
{% endif %}
|
||||
</h2>
|
||||
|
||||
<h1>
|
||||
Dashboard
|
||||
{% if selected_account_obj %}
|
||||
— {{ selected_account_obj.name }}
|
||||
{% endif %}
|
||||
</h1>
|
||||
<p class="muted">
|
||||
{% if selected_month %}
|
||||
{{ selected_month }}/{{ selected_year}}
|
||||
{% else %}
|
||||
Año {{ selected_year }}
|
||||
{% endif %}
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<!-- ========================= -->
|
||||
<!-- Filters -->
|
||||
<!-- ========================= -->
|
||||
|
||||
<div>
|
||||
<a href="{% url 'dashboard' %}?period=this_month">Este mes</a> |
|
||||
<a href="{% url 'dashboard' %}?period=last_month">Mes anterior</a> |
|
||||
<a href="{% url 'dashboard' %}?period=this_year">Este año</a>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<section class="dashboard-filters">
|
||||
<div class="dashboard-presets">
|
||||
<a href="{% url 'dashboard' %}" data-period="this_month" class="preset {% if period == 'this_month' %}active{% endif %}">
|
||||
Este mes
|
||||
</a>
|
||||
|
||||
<a href="{% url 'dashboard' %}" data-period="last_month" class="preset {% if period == 'last_month' %}active{% endif %}">
|
||||
Mes anterior
|
||||
</a>
|
||||
|
||||
<a href="{% url 'dashboard' %}" data-period="this_year" class="preset {% if period == 'this_year' %}active{% endif %}">
|
||||
Este año
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<form method="get">
|
||||
<select name="account" id="account">
|
||||
<option value="">Todas las cuentas</option>
|
||||
{% for acc in accounts %}
|
||||
<option value="{{ acc.id }}"
|
||||
{% if selected_account == acc.id %}selected{% endif %}
|
||||
>
|
||||
{{ acc.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
<form method="get" class="filters">
|
||||
<label>
|
||||
Año:
|
||||
<select name="year">
|
||||
{% for y in year_list %}
|
||||
<option value="{{ y }}"
|
||||
{% if y == selected_year %}selected{% endif %}
|
||||
>
|
||||
{{y}}
|
||||
{{ y }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Mes:
|
||||
|
||||
<select name="month">
|
||||
<option value="">Todos</option>
|
||||
<option value="">Todo el año</option>
|
||||
{% for m in months %}
|
||||
<option value="{{ m }}"
|
||||
{% if m == selected_month %}selected{% endif %}
|
||||
@ -50,43 +75,39 @@
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<input type="checkbox" name="compare" value="1"
|
||||
{% if compare_enabled %}checked{% endif %}>
|
||||
Comparar con periodo anterior
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="compare" value="1"
|
||||
{% if compare_enabled %}checked{% endif %}>
|
||||
Comparar
|
||||
</label>
|
||||
|
||||
<label for="account">Cuenta:</label>
|
||||
<select name="account" id="account">
|
||||
<option value="">Todas</option>
|
||||
{% for acc in accounts %}
|
||||
<option value="{{ acc.id }}"
|
||||
{% if selected_account == acc.id %}selected{% endif %}
|
||||
>
|
||||
{{ acc.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<button type="submit">Aplicar</button>
|
||||
</form>
|
||||
|
||||
<button type="submit">Aplicar</button>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<p>
|
||||
Mostrando:
|
||||
<strong>{{ selected_year }}</strong>
|
||||
{% if selected_month %}/<strong>{{ selected_month }}</strong>{% endif %}
|
||||
</p>
|
||||
<p>Comparado con el periodo inmediatamente anterior</p>
|
||||
<script>
|
||||
document.querySelectorAll('.dashboard-presets a').forEach(link => {
|
||||
link.addEventListener('click', e => {
|
||||
e.preventDefault();
|
||||
|
||||
<hr>
|
||||
const period = link.dataset.period;
|
||||
const isActive = link.classList.contains('active');
|
||||
|
||||
if (isActive) {
|
||||
window.location.href = link.href;
|
||||
} else {
|
||||
window.location.href = `${link.href}?period=${period}`
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- ========================= -->
|
||||
<!-- KPIs -->
|
||||
<!-- ========================= -->
|
||||
|
||||
|
||||
<section class="kpi-grid">
|
||||
|
||||
<div class="kpi-card">
|
||||
@ -111,145 +132,15 @@
|
||||
|
||||
</section>
|
||||
|
||||
{% if compare_enabled %}
|
||||
<section class="kpi compare">
|
||||
<h3>Comparación con periodo anterior</h3>
|
||||
|
||||
{% if kpi_previous_total == 0 %}
|
||||
<p><em>No hay datos en el periodo anterior</em></p>
|
||||
{% else %}
|
||||
<p>
|
||||
Total anterior: <strong>{{ kpi_previous_total|floatformat:2 }}</strong>
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<div>
|
||||
Diferencia:
|
||||
{% if kpi_trend == "up" %}
|
||||
<span style="color:red;">▲ {{ kpi_difference|floatformat:2 }}€</span>
|
||||
{% elif kpi_trend == "down" %}
|
||||
<span style="color:green;">▼ {{ kpi_difference_abs|floatformat:2 }}€</span>
|
||||
{% else %}
|
||||
<span>0€</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<p>
|
||||
Variación:
|
||||
{% if kpi_percentage is not None %}
|
||||
{{ kpi_percentage|floatformat:2 }}%
|
||||
{% else %}
|
||||
Variación: N/D
|
||||
{% endif %}
|
||||
</p>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
<!-- ========================= -->
|
||||
<!-- Expenses by category -->
|
||||
<!-- Charts -->
|
||||
<!-- ========================= -->
|
||||
<h2>Gastos por categoría</h2>
|
||||
|
||||
{% if not by_category %}
|
||||
<p>No hay gastos para este periodo.</p>
|
||||
{% else %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Categoría</th>
|
||||
<th>Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for row in by_category %}
|
||||
<tr>
|
||||
<td>{{ row.category__name }}</td>
|
||||
<td>{{ row.total }}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="2">Sin datos</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
{% if compare_enabled %}
|
||||
<h3>Comparativa por categoría</h3>
|
||||
<section class="chart-box">
|
||||
<canvas id="mainChart"></canvas>
|
||||
</section>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Categoría</th>
|
||||
<th>Actual</th>
|
||||
<th>Anterior</th>
|
||||
<th>Diferencia</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for row in category_comparison %}
|
||||
<tr>
|
||||
<td>{{ row.category }}</td>
|
||||
<td>{{ row.current|floatformat:2 }}€</td>
|
||||
<td>{{ row.previous }}</td>
|
||||
<td>
|
||||
{% if row.difference > 0 %}
|
||||
<span style="color:red;">▲ {{ row.difference|floatformat:2 }}€</span>
|
||||
{% elif row.difference < 0 %}
|
||||
<span style="color:green;">▼ {{ row.difference_abs|floatformat:2 }}€</span>
|
||||
{% else %}
|
||||
=
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
<hr>
|
||||
|
||||
<!-- ========================= -->
|
||||
<!-- Expenses by month -->
|
||||
<!-- ========================= -->
|
||||
|
||||
<h2>Gastos por mes</h2>
|
||||
|
||||
<ul>
|
||||
{% for row in by_month %}
|
||||
<li>Mes {{ row.month }} → {{ row.total }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<!-- ========================= -->
|
||||
<!-- Chart -->
|
||||
<!-- ========================= -->
|
||||
|
||||
<h2>Distribución mensual (año completo)</h2>
|
||||
|
||||
<canvas id="expensesChart"></canvas>
|
||||
|
||||
<script>
|
||||
const labels = {{ chart_labels|safe }};
|
||||
const data = {{ chart_data|safe }};
|
||||
|
||||
const ctx = document.getElementById('expensesChart');
|
||||
|
||||
new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets:[{
|
||||
label: 'Gastos',
|
||||
data: data,
|
||||
}]
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>Evolución anual por cuenta ({{ selected_year }})</h2>
|
||||
<h3>Evolución anual por cuenta ({{ selected_year }})</h3>
|
||||
|
||||
<div class="dashboard-grid">
|
||||
{% for acc in accounts_charts %}
|
||||
@ -262,6 +153,23 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const labels = {{ chart_labels|safe }};
|
||||
const data = {{ chart_data|safe }};
|
||||
|
||||
const ctx = document.getElementById('mainChart');
|
||||
|
||||
new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets:[{
|
||||
label: 'Gastos',
|
||||
data: data,
|
||||
}]
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
const monthLabels = {{ chart_labels|safe }};
|
||||
|
||||
@ -289,4 +197,38 @@
|
||||
</script>
|
||||
|
||||
|
||||
{% if compare_enabled %}
|
||||
<section class="comparison">
|
||||
<h3>Comparativa</h3>
|
||||
|
||||
<p>
|
||||
Diferencia:
|
||||
<strong class="{% if kpi_trend == 'up' %}positive{% endif %}">
|
||||
{% if kpi_trend == "up" %}+{% endif %}
|
||||
{{ kpi_difference_abs|floatformat:2 }} €
|
||||
</strong>
|
||||
{% if kpi_percentage %}
|
||||
({{ kpi_percentage|floatformat:1 }}%)
|
||||
{% endif %}
|
||||
</p>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Categoría</th>
|
||||
<th>Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for row in by_category %}
|
||||
<tr>
|
||||
<td>{{ row.category__name }}</td>
|
||||
<td>{{ row.total|floatformat:2 }} €</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
||||
@ -530,6 +530,7 @@ def dashboard(request):
|
||||
'selected_account_obj': selected_account_obj,
|
||||
'kpi_balance': kpi_balance,
|
||||
'accounts_charts': accounts_charts,
|
||||
'period':period,
|
||||
})
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user