Updated home with a mini dashboard and created the base.css
This commit is contained in:
parent
cf3869c370
commit
b75efb1553
21
expenses_manager/expenses/static/expenses/css/base.css
Normal file
21
expenses_manager/expenses/static/expenses/css/base.css
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
.dashboard-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(300px, 500px));
|
||||||
|
gap: 20px
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 16px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-chart {
|
||||||
|
max-width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-chart canvas {
|
||||||
|
width: 100% !important;
|
||||||
|
height: 220px !important;
|
||||||
|
}
|
||||||
@ -1,53 +1,68 @@
|
|||||||
|
{% load static %}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Home</title>
|
<title>Home</title>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
<link rel="stylesheet" href="{% static 'expenses/css/base.css' %}">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<h1>Resumen del mes</h1>
|
<h1>Home</h1>
|
||||||
|
|
||||||
<!-- KPIs -->
|
|
||||||
<section>
|
<section>
|
||||||
<h2>Indicadores</h2>
|
<h2>Resumen del mes</h2>
|
||||||
|
<p>Total: {{ kpi_total }}</p>
|
||||||
|
<p>Gastos: {{ kpi_count }}</p>
|
||||||
|
<p>Categorías: {{ kpi_categories }}</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Últimos gastos</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
{% for expense in last_expenses %}
|
||||||
<strong>Total gastado:</strong>
|
<li>
|
||||||
{{ kpi_total }}
|
{{ expense.date }} -
|
||||||
</li>
|
{{ expense.category.name }} -
|
||||||
|
{{ expense.amount }}
|
||||||
<li>
|
</li>
|
||||||
<strong>Nº de gastos:</strong>
|
{% empty %}
|
||||||
{{ kpi_difference }}
|
<li>No hay gastos</li>
|
||||||
</li>
|
{% endfor %}
|
||||||
|
|
||||||
<li>
|
|
||||||
<strong>Variación (%):</strong>
|
|
||||||
{% if kpi_percentage is not None %}
|
|
||||||
{{ kpi_percentage|floatformat:2 }} %
|
|
||||||
{% else %}
|
|
||||||
N/A
|
|
||||||
{% endif %}
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<!-- Actions -->
|
|
||||||
<section>
|
<section>
|
||||||
<h2>Acciones</h2>
|
<div class="dashboard-grid">
|
||||||
|
<div class="card card-chart">
|
||||||
|
<h2>Últimos meses</h2>
|
||||||
|
<canvas id="miniChart"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const labels = {{ mini_chart_labels|safe }};
|
||||||
|
const data = {{ mini_chart_data|safe }};
|
||||||
|
|
||||||
|
const ctx = document.getElementById('miniChart');
|
||||||
|
|
||||||
|
new Chart(ctx, {
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
labels: labels,
|
||||||
|
datasets:[{
|
||||||
|
label: 'Gastos',
|
||||||
|
data: data,
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a href="{% url 'dashboard' %}">Ir al dashboard</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="{% url 'expense_create' %}">Añadir gasto</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@ -32,66 +32,68 @@ def _get_int(value):
|
|||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def sub_months(year, month, n):
|
||||||
|
month -= n
|
||||||
|
while month <= 0:
|
||||||
|
month += 12
|
||||||
|
year -= 1
|
||||||
|
return year, month
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def home(request):
|
def home(request):
|
||||||
today = date.today()
|
expenses = Expense.objects.filter(owner=request.user)
|
||||||
year = today.year
|
|
||||||
month = today.month
|
|
||||||
|
|
||||||
expenses = Expense.objects.filter(
|
# Last expenses
|
||||||
owner=request.user,
|
last_expenses = (
|
||||||
date__year=year,
|
expenses
|
||||||
date__month=month,
|
.select_related('category')
|
||||||
|
.order_by('-date')[:5]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Current KPIs
|
# Simple KPIs (current month)
|
||||||
total_amount = expenses.aggregate(
|
today = date.today()
|
||||||
|
month_expenses = expenses.filter(
|
||||||
|
date__year=today.year,
|
||||||
|
date__month=today.month
|
||||||
|
)
|
||||||
|
|
||||||
|
kpi_total = month_expenses.aggregate(
|
||||||
total=Sum('amount')
|
total=Sum('amount')
|
||||||
)['total'] or 0
|
)['total'] or 0
|
||||||
|
|
||||||
expense_count = expenses.count()
|
kpi_count = month_expenses.count()
|
||||||
|
|
||||||
# ------------------
|
kpi_categories = (
|
||||||
# Previous period
|
month_expenses
|
||||||
# ------------------
|
.values('category')
|
||||||
if month == 1:
|
.distinct()
|
||||||
prev_year = year - 1
|
.count()
|
||||||
prev_month = 12
|
|
||||||
else:
|
|
||||||
prev_year = year
|
|
||||||
prev_month = month - 1
|
|
||||||
|
|
||||||
previous_expenses = Expense.objects.filter(
|
|
||||||
owner=request.user,
|
|
||||||
date__year=prev_year,
|
|
||||||
date__month=prev_month,
|
|
||||||
)
|
|
||||||
|
|
||||||
previous_total = (
|
|
||||||
previous_expenses.aggregate(total=Sum('amount'))['total'] or 0
|
|
||||||
)
|
|
||||||
|
|
||||||
difference = total_amount - previous_total
|
|
||||||
|
|
||||||
percentage = (difference / previous_total) * 100 if previous_total else None
|
|
||||||
|
|
||||||
# ------------------
|
|
||||||
# Top categories
|
|
||||||
# ------------------
|
|
||||||
top_categories = (
|
|
||||||
expenses
|
|
||||||
.values('category__name')
|
|
||||||
.annotate(total=Sum('amount'))
|
|
||||||
.order_by('-total')[:3]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
six_months = []
|
||||||
|
for i in range(5, -1, -1):
|
||||||
|
y, m = sub_months(today.year, today.month, i)
|
||||||
|
six_months.append((y, m))
|
||||||
|
|
||||||
|
mini_data = []
|
||||||
|
for y, m in six_months:
|
||||||
|
total = expenses.filter(
|
||||||
|
date__year=y,
|
||||||
|
date__month=m
|
||||||
|
).aggregate(total=Sum('amount'))['total'] or 0
|
||||||
|
|
||||||
|
mini_data.append({
|
||||||
|
'label': f'{m}/{y}',
|
||||||
|
'total': float(total),
|
||||||
|
})
|
||||||
|
|
||||||
return render(request, 'expenses/home.html', {
|
return render(request, 'expenses/home.html', {
|
||||||
'kpi_total': total_amount,
|
'last_expenses': last_expenses,
|
||||||
'kpi_amount': expense_count,
|
'kpi_total': kpi_total,
|
||||||
'kpi_difference': difference,
|
'kpi_count': kpi_count,
|
||||||
'kpi_percentage': percentage,
|
'kpi_categories': kpi_categories,
|
||||||
'kpi_previous_total': previous_total,
|
'mini_chart_labels': [x['label'] for x in mini_data],
|
||||||
'top_categories': top_categories,
|
'mini_chart_data': [x['total'] for x in mini_data],
|
||||||
})
|
})
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user