feat: suivre la température pendant les tournées

This commit is contained in:
Alexandre NOEL 2026-09-15 15:43:00 +02:00
commit d35434c522
15 changed files with 129 additions and 23 deletions

View file

@ -235,14 +235,14 @@
<div class="card mt-3">
<div class="card-header">
<h3 class="card-title m-0"><?= h(t('animal.weight_evolution')) ?></h3>
<h3 class="card-title m-0"><?= h(t('animal.measurements_evolution')) ?></h3>
</div>
<?php if (!$weights): ?>
<div class="card-body text-muted"><?= h(t('animal.no_weight')) ?></div>
<?php if (!$weights && !$temperatures): ?>
<div class="card-body text-muted"><?= h(t('animal.no_measurement')) ?></div>
<?php else: ?>
<div style="height:260px">
<canvas id="weightChart"></canvas>
<canvas id="healthMeasurementsChart"></canvas>
</div>
<?php endif; ?>

View file

@ -944,25 +944,47 @@ $currentTime = date('H:i');
</script>
<script>
(function() {
const el = document.getElementById('weightChart');
const el = document.getElementById('healthMeasurementsChart');
if (!el) return;
const rows = <?= json_encode($weights ?? [], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?> ;
const weights = <?= json_encode($weights ?? [], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?>;
const temperatures = <?= json_encode($temperatures ?? [], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?>;
const normalizeDate = value => String(value || '').replace(' ', 'T');
const labels = [...new Set([
...weights.map(row => normalizeDate(row.measured_at)),
...temperatures.map(row => normalizeDate(row.measured_at))
])].filter(Boolean).sort();
const valuesByDate = rows => new Map(rows.map(row => [normalizeDate(row.measured_at), Number(row.value)]));
const weightValues = valuesByDate(weights);
const temperatureValues = valuesByDate(temperatures);
// labels = dates, data = poids
const labels = rows.map(r => (r.measured_at || '').slice(0, 10)); // YYYY-MM-DD
const data = rows.map(r => Number(r.value));
// Chart.js default color (on ne fixe rien volontairement)
new Chart(el, {
type: 'line',
data: {
labels,
datasets: [{
labels: labels.map(value => new Date(value).toLocaleString(undefined, {
dateStyle: 'short',
timeStyle: 'short'
})),
datasets: [
{
label: <?= json_encode(t('chart.weight'), JSON_UNESCAPED_UNICODE) ?> ,
data,
data: labels.map(label => weightValues.get(label) ?? null),
borderColor: '#206bc4',
backgroundColor: '#206bc4',
tension: 0.25,
pointRadius: 2
pointRadius: 3,
spanGaps: true,
yAxisID: 'weight'
},
{
label: <?= json_encode(t('chart.temperature'), JSON_UNESCAPED_UNICODE) ?>,
data: labels.map(label => temperatureValues.get(label) ?? null),
borderColor: '#d63939',
backgroundColor: '#d63939',
tension: 0.25,
pointRadius: 3,
spanGaps: true,
yAxisID: 'temperature'
}]
},
options: {
@ -974,12 +996,25 @@ $currentTime = date('H:i');
}
},
scales: {
y: {
weight: {
type: 'linear',
position: 'left',
title: {
display: true,
text: 'kg'
}
},
temperature: {
type: 'linear',
position: 'right',
grid: {
drawOnChartArea: false
},
title: {
display: true,
text: '°C'
}
},
x: {
title: {
display: true,

View file

@ -4,6 +4,7 @@
/** @var array $treatments */
/** @var array $vaccinations */
/** @var array $weights */
/** @var array $temperatures */
/** @var array adoption */
require_once __DIR__ . '/../Services/IcadService.php';

View file

@ -347,6 +347,16 @@ $fieldOptions = [
type="radio" name="<?= h($field) ?>" value="<?= h($value) ?>"
<?= (($obs[$field] ?? array_key_first($options)) === $value) ? 'checked' : '' ?>><span><?= h($label) ?></span></label><?php endforeach; ?>
</div><?php endforeach; ?>
<div class="mb-2">
<label class="form-label fw-bold" for="temperature-<?= (int)$a['id'] ?>">🌡️ <?= h(t('care.temperature')) ?></label>
<div class="input-group">
<input class="form-control" id="temperature-<?= (int)$a['id'] ?>"
name="temperature_c" type="number" min="30" max="45" step="0.1"
inputmode="decimal" required
value="<?= h(number_format((float)($obs['temperature_c'] ?? 38.5), 1, '.', '')) ?>">
<span class="input-group-text">°C</span>
</div>
</div>
<?php foreach ($treatmentsByAnimal[(int)$a['id']] ?? [] as $t): ?><div
class="card card-sm bg-purple-lt mb-2">
<div class="card-body py-2"><strong>💊 <?= h($t['medication_name']) ?></strong>

View file

@ -31,10 +31,10 @@
<div class="col-lg-6">
<section class="card h-100">
<div class="card-body">
<span class="badge bg-blue-lt mb-2">1.0.0-rc.20</span>
<h3>Localisations cohérentes</h3>
<p class="text-muted">Lieu de récupération et lieu actuel clairement distingués, avec réparation
des coordonnées manquantes après un import ou un placement.</p>
<span class="badge bg-blue-lt mb-2">1.0.0-rc.21</span>
<h3>Température pendant les tournées</h3>
<p class="text-muted">Température proposée à 38,5 °C pendant chaque contrôle et graphique médical
commun pour suivre son évolution avec celle du poids.</p>
</div>
</section>
</div>