ajout de suivi des parkings vélo

This commit is contained in:
Tykayn 2025-06-29 19:38:54 +02:00 committed by tykayn
parent 0611b28172
commit 4fbdcfc704
5 changed files with 37 additions and 5 deletions

View file

@ -1,5 +1,10 @@
#!/bin/bash #!/bin/bash
curl -X GET "https://osm-commerces.cipherbliss.com/admin/followup/global"
# Les 10 codes postaux des villes les plus peuplées de France # Les 10 codes postaux des villes les plus peuplées de France
codes_insee=( codes_insee=(
"06088" # Nice "06088" # Nice
@ -240,5 +245,5 @@ done
echo "Traitement terminé pour les codes insee" echo "Traitement terminé pour les codes insee"
curl -X GET "https://osm-commerces.cipherbliss.com/https://127.0.0.1:8000/admin/followup/global" curl -X GET "https://osm-commerces.cipherbliss.com/admin/followup/global"

View file

@ -79,6 +79,13 @@ class FollowUpController extends AbstractController
'name' => $fu->getName(), 'name' => $fu->getName(),
]; ];
} }
// Tri par date dans chaque série
foreach ($series as &$points) {
usort($points, function($a, $b) {
return strtotime($a['date']) <=> strtotime($b['date']);
});
}
unset($points);
return $this->render('admin/followup_graph.html.twig', [ return $this->render('admin/followup_graph.html.twig', [
'stats' => $stats, 'stats' => $stats,
'series' => $series, 'series' => $series,
@ -126,6 +133,13 @@ class FollowUpController extends AbstractController
'name' => $fu->getName(), 'name' => $fu->getName(),
]; ];
} }
// Tri par date dans chaque série
foreach ($series as &$points) {
usort($points, function($a, $b) {
return strtotime($a['date']) <=> strtotime($b['date']);
});
}
unset($points);
return $this->render('admin/followup_global_graph.html.twig', [ return $this->render('admin/followup_global_graph.html.twig', [
'stats' => $stats, 'stats' => $stats,
'series' => $series, 'series' => $series,

View file

@ -46,6 +46,8 @@ class FollowUpService
|| ($el['tags']['amenity'] ?? null) === 'clinic' || ($el['tags']['amenity'] ?? null) === 'clinic'
|| ($el['tags']['amenity'] ?? null) === 'social_facility'; || ($el['tags']['amenity'] ?? null) === 'social_facility';
}) ?? []; }) ?? [];
} elseif ($type === 'bicycle_parking') {
$objects = array_filter($elements, fn($el) => ($el['tags']['amenity'] ?? null) === 'bicycle_parking') ?? [];
} else { } else {
$objects = []; $objects = [];
} }
@ -118,6 +120,10 @@ class FollowUpService
|| !empty($tags['email'] ?? null) || !empty($tags['email'] ?? null)
|| !empty($tags['contact:email'] ?? null); || !empty($tags['contact:email'] ?? null);
}); });
} elseif ($type === 'bicycle_parking') {
$completed = array_filter($data['objects'], function($el) {
return !empty($el['tags']['capacity'] ?? null) || !empty($el['tags']['covered'] ?? null);
});
} }
$completion = count($data['objects']) > 0 ? round(count($completed) / count($data['objects']) * 100) : 0; $completion = count($data['objects']) > 0 ? round(count($completed) / count($data['objects']) * 100) : 0;
$followupCompletion = new CityFollowUp(); $followupCompletion = new CityFollowUp();
@ -231,6 +237,7 @@ class FollowUpService
'school' => 'Écoles', 'school' => 'Écoles',
'police' => 'Commissariats', 'police' => 'Commissariats',
'healthcare' => 'Lieux de santé', 'healthcare' => 'Lieux de santé',
'bicycle_parking' => 'Parkings vélos',
'places' => 'Lieux' 'places' => 'Lieux'
]; ];
} }
@ -250,6 +257,7 @@ class FollowUpService
'school' => 'bi-mortarboard', 'school' => 'bi-mortarboard',
'police' => 'bi-shield-lock', 'police' => 'bi-shield-lock',
'healthcare' => 'bi-hospital', 'healthcare' => 'bi-hospital',
'bicycle_parking' => 'bi-bicycle',
'places' => 'bi-geo-alt' 'places' => 'bi-geo-alt'
]; ];
} }
@ -269,6 +277,7 @@ class FollowUpService
'school' => 'nwr["amenity"="school"](area.searchArea);', 'school' => 'nwr["amenity"="school"](area.searchArea);',
'police' => 'nwr["amenity"="police"](area.searchArea);', 'police' => 'nwr["amenity"="police"](area.searchArea);',
'healthcare' => 'nwr["healthcare"](area.searchArea);nwr["amenity"="doctors"](area.searchArea);nwr["amenity"="pharmacy"](area.searchArea);nwr["amenity"="hospital"](area.searchArea);nwr["amenity"="clinic"](area.searchArea);nwr["amenity"="social_facility"](area.searchArea);', 'healthcare' => 'nwr["healthcare"](area.searchArea);nwr["amenity"="doctors"](area.searchArea);nwr["amenity"="pharmacy"](area.searchArea);nwr["amenity"="hospital"](area.searchArea);nwr["amenity"="clinic"](area.searchArea);nwr["amenity"="social_facility"](area.searchArea);',
'bicycle_parking' => 'nwr["amenity"="bicycle_parking"](area.searchArea);',
'places' => '' 'places' => ''
]; ];
} }

View file

@ -582,6 +582,7 @@ area["ref:INSEE"="$zone"]->.searchArea;
nwr["healthcare"="laboratory"](area.searchArea); nwr["healthcare"="laboratory"](area.searchArea);
nwr["amenity"="school"](area.searchArea); nwr["amenity"="school"](area.searchArea);
nwr["amenity"="police"](area.searchArea); nwr["amenity"="police"](area.searchArea);
nwr["amenity"="bicycle_parking"](area.searchArea);
); );
(._;>;); (._;>;);
out meta; out meta;

View file

@ -18,7 +18,7 @@
</div> </div>
<p>Historique des objets suivis (nombre et complétion).</p> <p>Historique des objets suivis (nombre et complétion).</p>
{% for type, label in followup_labels %} {% for type, label in followup_labels %}
<h2 id="title-{{ type }}"><i class="bi {{ followup_icons[type]|default('bi-question-circle') }}"></i> {{ label }}</h2> <h2 id="title-{{ type }}"><i class="bi {{ followup_icons[type]|default('bi-question-circle') }} fs-2"></i> {{ label }}</h2>
<canvas id="{{ type }}Chart" width="600" height="300"></canvas> <canvas id="{{ type }}Chart" width="600" height="300"></canvas>
<div class="mb-3"> <div class="mb-3">
{% set overpass_query = '[out:json][timeout:60];\narea["ref:INSEE"="' ~ stats.zone ~ '"]->.searchArea;\n(' ~ followup_overpass[type]|default('') ~ ');\n\n(._;>;);\n\nout meta;\n>;' %} {% set overpass_query = '[out:json][timeout:60];\narea["ref:INSEE"="' ~ stats.zone ~ '"]->.searchArea;\n(' ~ followup_overpass[type]|default('') ~ ');\n\n(._;>;);\n\nout meta;\n>;' %}
@ -63,6 +63,8 @@
<script src="/js/chartjs/chartjs-adapter-date-fns.js"></script> <script src="/js/chartjs/chartjs-adapter-date-fns.js"></script>
<script> <script>
const series = {{ series|json_encode|raw }}; const series = {{ series|json_encode|raw }};
console.log('series',series)
const typeLabels = { const typeLabels = {
fire_hydrant: 'Bornes incendie', fire_hydrant: 'Bornes incendie',
charging_station: 'Bornes de recharge', charging_station: 'Bornes de recharge',
@ -75,7 +77,8 @@
laboratory: "Laboratoires d'analyse", laboratory: "Laboratoires d'analyse",
school: 'Écoles', school: 'Écoles',
police: 'Commissariats', police: 'Commissariats',
healthcare: 'Lieux de santé' healthcare: 'Lieux de santé',
bicycle_parking: 'Parkings vélos'
}; };
function formatDelta(val) { function formatDelta(val) {
if (val === null) return '-'; if (val === null) return '-';
@ -117,7 +120,7 @@
// Mettre à jour le titre // Mettre à jour le titre
const titleElem = document.getElementById('title-' + baseType); const titleElem = document.getElementById('title-' + baseType);
if (titleElem) { if (titleElem) {
titleElem.innerHTML = `${typeLabels[baseType]} (N = ${lastCount}, complétion = ${lastCompletion}%)`; titleElem.innerHTML = `${typeLabels[baseType]} ( ${lastCount}, ${lastCompletion}%)`;
} }
// Créer le graphique // Créer le graphique
new Chart(canvas, { new Chart(canvas, {
@ -148,7 +151,7 @@
plugins: { plugins: {
title: { title: {
display: true, display: true,
text: `${typeLabels[baseType]} (N = ${lastCount}, complétion = ${lastCompletion}%)` text: `${typeLabels[baseType]} ( ${lastCount}, ${lastCompletion}%)`
} }
}, },
scales: { scales: {