first commit. application working
This commit is contained in:
198
backend/target/classes/templates/dashboard.html
Normal file
198
backend/target/classes/templates/dashboard.html
Normal file
@ -0,0 +1,198 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Dashboard | Weight Tracker</title>
|
||||
<link th:href="@{/vendor/fontawesome-free/css/all.min.css}" rel="stylesheet">
|
||||
<link th:href="@{/css/sb-admin-2.min.css}" rel="stylesheet">
|
||||
<link rel="icon" href="data:,">
|
||||
|
||||
<!-- Chart.js -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<!-- Daterangepicker -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css" />
|
||||
</head>
|
||||
|
||||
<body id="page-top">
|
||||
<div id="wrapper">
|
||||
<div th:replace="~{fragments/fragment-menu :: menu}"></div>
|
||||
<div id="content-wrapper" class="d-flex flex-column">
|
||||
<div id="content" class="p-4">
|
||||
<nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow">
|
||||
<button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3">
|
||||
<i class="fa fa-bars"></i>
|
||||
</button>
|
||||
<h1 class="h4 mb-0 text-gray-800">Dashboard</h1>
|
||||
</nav>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row gx-3 gy-4">
|
||||
<!-- Últimos registros -->
|
||||
<div class="col-12 col-lg-6">
|
||||
<div class="card shadow mb-4 h-100">
|
||||
<div class="card-header">Últimos 10 registros</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Fecha</th>
|
||||
<th>Peso (kg)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr th:each="r : ${ultimos}">
|
||||
<td th:text="${#temporals.format(r.date, 'yyyy-MM-dd HH:mm')}">2025-07-10</td>
|
||||
<td th:text="${r.weight}">70.5</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Gráfica -->
|
||||
<div class="col-12 col-lg-6 mt-3 mt-lg-0">
|
||||
<div class="card shadow mb-4 h-100">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span id="chart-title">Evolución del peso</span>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-sm btn-secondary dropdown-toggle" type="button" id="metricDropdown"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
Métricas
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end p-2" aria-labelledby="metricDropdown"
|
||||
style="min-width: 200px;">
|
||||
<li><div class="form-check"><input class="form-check-input metric-check" type="checkbox" value="weight" id="metricWeight" checked><label class="form-check-label" for="metricWeight">Peso (kg)</label></div></li>
|
||||
<li><div class="form-check"><input class="form-check-input metric-check" type="checkbox" value="bodyFat" id="metricBodyFat"><label class="form-check-label" for="metricBodyFat">% Grasa</label></div></li>
|
||||
<li><div class="form-check"><input class="form-check-input metric-check" type="checkbox" value="muscleMass" id="metricMuscleMass"><label class="form-check-label" for="metricMuscleMass">Masa muscular</label></div></li>
|
||||
<li><div class="form-check"><input class="form-check-input metric-check" type="checkbox" value="waterPercent" id="metricWater"><label class="form-check-label" for="metricWater">% Agua</label></div></li>
|
||||
<li><div class="form-check"><input class="form-check-input metric-check" type="checkbox" value="bmi" id="metricBMI"><label class="form-check-label" for="metricBMI">IMC</label></div></li>
|
||||
<li><div class="form-check"><input class="form-check-input metric-check" type="checkbox" value="metabolicAge" id="metricMetAge"><label class="form-check-label" for="metricMetAge">Edad metabólica</label></div></li>
|
||||
<li><div class="form-check"><input class="form-check-input metric-check" type="checkbox" value="visceralFat" id="metricVisceral"><label class="form-check-label" for="metricVisceral">Grasa visceral</label></div></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-2">
|
||||
<label for="chartDateRange">Filtrar por fecha:</label>
|
||||
<input type="text" id="chartDateRange" class="form-control form-control-sm w-auto d-inline-block">
|
||||
</div>
|
||||
<canvas id="chart" class="w-100" style="max-height: 300px;"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- jQuery, Bootstrap y plugins -->
|
||||
<script th:src="@{/vendor/jquery/jquery.min.js}"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/moment@2.29.4/moment.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js"></script>
|
||||
<script th:src="@{/js/sb-admin-2.min.js}"></script>
|
||||
|
||||
<!-- Script Chart -->
|
||||
<script th:inline="javascript">
|
||||
$(document).ready(function () {
|
||||
// Datos desde el controlador
|
||||
const labels = /*[[${labels}]]*/[];
|
||||
const dataMap = {
|
||||
weight: /*[[${pesos}]]*/[],
|
||||
bodyFat: /*[[${grasa}]]*/[],
|
||||
muscleMass: /*[[${musculo}]]*/[],
|
||||
waterPercent: /*[[${agua}]]*/[],
|
||||
bmi: /*[[${bmi}]]*/[],
|
||||
metabolicAge: /*[[${edadMetabolica}]]*/[],
|
||||
visceralFat: /*[[${grasaVisceral}]]*/[]
|
||||
};
|
||||
|
||||
const metricColors = {
|
||||
weight: 'rgba(78, 115, 223, 1)',
|
||||
bodyFat: 'rgba(231, 74, 59, 1)',
|
||||
muscleMass: 'rgba(28, 200, 138, 1)',
|
||||
waterPercent: 'rgba(54, 185, 204, 1)',
|
||||
bmi: 'rgba(246, 194, 62, 1)',
|
||||
metabolicAge: 'rgba(133, 135, 150, 1)',
|
||||
visceralFat: 'rgba(106, 90, 205, 1)'
|
||||
};
|
||||
|
||||
const ctx = document.getElementById('chart').getContext('2d');
|
||||
const chart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: 'Peso (kg)',
|
||||
data: dataMap.weight,
|
||||
borderColor: metricColors.weight,
|
||||
borderWidth: 2,
|
||||
fill: false,
|
||||
tension: 0.3,
|
||||
pointRadius: 3
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
x: {
|
||||
ticks: {
|
||||
maxRotation: 45,
|
||||
minRotation: 45
|
||||
}
|
||||
},
|
||||
y: {
|
||||
beginAtZero: false
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Filtro por métricas
|
||||
$('.metric-check').on('change', function () {
|
||||
const selected = $('.metric-check:checked').map(function () {
|
||||
return this.value;
|
||||
}).get();
|
||||
|
||||
chart.data.datasets = selected.map(metric => ({
|
||||
label: $(`label[for="metric${metric.charAt(0).toUpperCase() + metric.slice(1)}"]`).text(),
|
||||
data: dataMap[metric],
|
||||
borderColor: metricColors[metric],
|
||||
borderWidth: 2,
|
||||
fill: false,
|
||||
tension: 0.3,
|
||||
pointRadius: 3
|
||||
}));
|
||||
|
||||
chart.update();
|
||||
});
|
||||
|
||||
// Rango de fechas
|
||||
$('#chartDateRange').daterangepicker({
|
||||
autoUpdateInput: false,
|
||||
locale: {
|
||||
cancelLabel: 'Limpiar',
|
||||
applyLabel: 'Aplicar',
|
||||
format: 'YYYY-MM-DD'
|
||||
}
|
||||
});
|
||||
|
||||
$('#chartDateRange').on('apply.daterangepicker', function (ev, picker) {
|
||||
const start = picker.startDate.format('YYYY-MM-DD');
|
||||
const end = picker.endDate.format('YYYY-MM-DD');
|
||||
window.location.href = `/?start=${start}&end=${end}`;
|
||||
});
|
||||
|
||||
$('#chartDateRange').on('cancel.daterangepicker', function () {
|
||||
window.location.href = `/`;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user