From 9eb08073d0b9f7a449cbb6250b2fb86b337be30a Mon Sep 17 00:00:00 2001 From: Tykayn Date: Sat, 12 Jul 2025 14:28:00 +0200 Subject: [PATCH] =?UTF-8?q?graph=20d=C3=A9taill=C3=A9,=20listing=20cl?= =?UTF-8?q?=C3=A9s=20courantes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- migrations/Version20250712121647.php | 35 +++++++++ src/Controller/FollowUpController.php | 73 ++++++++++++------ src/Entity/Place.php | 2 +- templates/admin/followup_graph.html.twig | 77 +++++++++++++++---- .../admin/followup_theme_graph.html.twig | 64 +++++++++++++++ templates/public/add_city.html.twig | 6 +- templates/public/stats_evolutions.html.twig | 4 +- 7 files changed, 213 insertions(+), 48 deletions(-) create mode 100644 migrations/Version20250712121647.php diff --git a/migrations/Version20250712121647.php b/migrations/Version20250712121647.php new file mode 100644 index 00000000..2d6808d5 --- /dev/null +++ b/migrations/Version20250712121647.php @@ -0,0 +1,35 @@ +addSql(<<<'SQL' + ALTER TABLE place CHANGE email email VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_0900_ai_ci`, CHANGE note note LONGTEXT CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_0900_ai_ci`, CHANGE name name VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_0900_ai_ci`, CHANGE note_content note_content VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_0900_ai_ci`, CHANGE street street VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_0900_ai_ci`, CHANGE housenumber housenumber VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_0900_ai_ci`, CHANGE siret siret VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_0900_ai_ci`, CHANGE osm_user osm_user VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_0900_ai_ci`, CHANGE email_content email_content LONGTEXT CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_0900_ai_ci` + SQL); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql(<<<'SQL' + ALTER TABLE place CHANGE email email VARCHAR(255) DEFAULT NULL, CHANGE note note VARCHAR(255) DEFAULT NULL, CHANGE name name VARCHAR(255) DEFAULT NULL, CHANGE note_content note_content VARCHAR(255) DEFAULT NULL, CHANGE street street VARCHAR(255) DEFAULT NULL, CHANGE housenumber housenumber VARCHAR(255) DEFAULT NULL, CHANGE siret siret VARCHAR(255) DEFAULT NULL, CHANGE osm_user osm_user VARCHAR(255) DEFAULT NULL, CHANGE email_content email_content LONGTEXT DEFAULT NULL + SQL); + } +} diff --git a/src/Controller/FollowUpController.php b/src/Controller/FollowUpController.php index 1e73ce03..2ed362ac 100644 --- a/src/Controller/FollowUpController.php +++ b/src/Controller/FollowUpController.php @@ -114,36 +114,61 @@ class FollowUpController extends AbstractController $themes = \App\Service\FollowUpService::getFollowUpThemes(); $all_completion_data = []; $latest_diffs = []; + // Définir les bornes de période + $now = new \DateTime(); + $periods = [ + '7j' => (clone $now)->modify('-7 days'), + '30j' => (clone $now)->modify('-30 days'), + '6mois' => (clone $now)->modify('-6 months'), + ]; foreach ($themes as $type => $label) { $all_completion_data[$type] = $series[$type . '_completion'] ?? []; - // Calcul du diff sur 7 jours pour le nombre et la complétion $count_series = $series[$type . '_count'] ?? []; $completion_series = $series[$type . '_completion'] ?? []; - $count_now = count($count_series) ? $count_series[count($count_series)-1]['value'] : null; - $count_7d = null; - foreach (array_reverse($count_series) as $point) { - $date = \DateTime::createFromFormat('Y-m-d', $point['date']); - if ($date && $date <= (new \DateTime('-7 days'))) { - $count_7d = $point['value']; - break; + // Fonction utilitaire pour trouver la valeur la plus proche avant ou égale à une date + $findValueAtOrBefore = function($series, \DateTime $date) { + $val = null; + foreach (array_reverse($series) as $point) { + $ptDate = \DateTime::createFromFormat('Y-m-d', $point['date']); + if ($ptDate && $ptDate <= $date) { + $val = $point['value']; + break; + } } - } - $completion_now = count($completion_series) ? $completion_series[count($completion_series)-1]['value'] : null; - $completion_7d = null; - foreach (array_reverse($completion_series) as $point) { - $date = \DateTime::createFromFormat('Y-m-d', $point['date']); - if ($date && $date <= (new \DateTime('-7 days'))) { - $completion_7d = $point['value']; - break; - } - } + return $val; + }; + // Valeurs aux bornes + $val_now = count($count_series) ? $count_series[count($count_series)-1]['value'] : null; + $val_7j = $findValueAtOrBefore($count_series, $periods['7j']); + $val_30j = $findValueAtOrBefore($count_series, $periods['30j']); + $val_6mois = $findValueAtOrBefore($count_series, $periods['6mois']); + // Différences exclusives + $diff_7j = ($val_now !== null && $val_7j !== null) ? $val_now - $val_7j : null; + $diff_30j = ($val_7j !== null && $val_30j !== null) ? $val_7j - $val_30j : null; + $diff_6mois = ($val_30j !== null && $val_6mois !== null) ? $val_30j - $val_6mois : null; + // Idem pour la complétion + $comp_now = count($completion_series) ? $completion_series[count($completion_series)-1]['value'] : null; + $comp_7j = $findValueAtOrBefore($completion_series, $periods['7j']); + $comp_30j = $findValueAtOrBefore($completion_series, $periods['30j']); + $comp_6mois = $findValueAtOrBefore($completion_series, $periods['6mois']); + $comp_diff_7j = ($comp_now !== null && $comp_7j !== null) ? $comp_now - $comp_7j : null; + $comp_diff_30j = ($comp_7j !== null && $comp_30j !== null) ? $comp_7j - $comp_30j : null; + $comp_diff_6mois = ($comp_30j !== null && $comp_6mois !== null) ? $comp_30j - $comp_6mois : null; $latest_diffs[$type] = [ - 'count_now' => $count_now, - 'count_7d' => $count_7d, - 'count_diff' => ($count_now !== null && $count_7d !== null) ? $count_now - $count_7d : null, - 'completion_now' => $completion_now, - 'completion_7d' => $completion_7d, - 'completion_diff' => ($completion_now !== null && $completion_7d !== null) ? $completion_now - $completion_7d : null, + 'count_now' => $val_now, + 'count_7j' => $val_7j, + 'count_30j' => $val_30j, + 'count_6mois' => $val_6mois, + 'count_diff_7j' => $diff_7j, + 'count_diff_30j' => $diff_30j, + 'count_diff_6mois' => $diff_6mois, + 'completion_now' => $comp_now, + 'completion_7j' => $comp_7j, + 'completion_30j' => $comp_30j, + 'completion_6mois' => $comp_6mois, + 'completion_diff_7j' => $comp_diff_7j, + 'completion_diff_30j' => $comp_diff_30j, + 'completion_diff_6mois' => $comp_diff_6mois, 'label' => $label, ]; } diff --git a/src/Entity/Place.php b/src/Entity/Place.php index 9c7af8cb..86557f0d 100644 --- a/src/Entity/Place.php +++ b/src/Entity/Place.php @@ -31,7 +31,7 @@ class Place #[ORM\Column] private ?bool $dead = null; - #[ORM\Column(length: 255, nullable: true, options: ['charset' => 'utf8mb4'])] + #[ORM\Column(type: Types::TEXT, nullable: true, options: ['charset' => 'utf8mb4'])] private ?string $note = null; #[ORM\Column(nullable: true)] diff --git a/templates/admin/followup_graph.html.twig b/templates/admin/followup_graph.html.twig index afebede1..a5c46d8f 100644 --- a/templates/admin/followup_graph.html.twig +++ b/templates/admin/followup_graph.html.twig @@ -26,13 +26,15 @@ Thème - Évolution du nombre - Évolution de la complétion + Évolution 7j + Évolution 30j + Évolution 6 mois {% for type, diff in latest_diffs %} - {% if diff.count_diff is not null and diff.count_diff != 0 %} + {% set has_period_change = (diff.count_diff_7j != 0 or diff.count_diff_30j != 0 or diff.count_diff_6mois != 0) %} + {% if has_period_change %} {% set has_change = true %} @@ -41,28 +43,73 @@ - {% if diff.count_diff > 0 %} + {% if diff.count_diff_7j > 0 %} - {% else %} - - {% endif %} - {{ diff.count_diff > 0 ? '+' ~ diff.count_diff : diff.count_diff }} objets - - - {% if diff.completion_diff > 0 %} - - {% elseif diff.completion_diff < 0 %} + {% elseif diff.count_diff_7j < 0 %} {% else %} {% endif %} - {{ diff.completion_diff > 0 ? '+' ~ diff.completion_diff : diff.completion_diff }}% + {{ diff.count_diff_7j > 0 ? '+' ~ diff.count_diff_7j : diff.count_diff_7j }} objets +
+ Complétion : + {% if diff.completion_diff_7j > 0 %} + + {% elseif diff.completion_diff_7j < 0 %} + + {% else %} + + {% endif %} + {{ diff.completion_diff_7j > 0 ? '+' ~ diff.completion_diff_7j : diff.completion_diff_7j }}% + + + + {% if diff.count_diff_30j > 0 %} + + {% elseif diff.count_diff_30j < 0 %} + + {% else %} + + {% endif %} + {{ diff.count_diff_30j > 0 ? '+' ~ diff.count_diff_30j : diff.count_diff_30j }} objets +
+ Complétion : + {% if diff.completion_diff_30j > 0 %} + + {% elseif diff.completion_diff_30j < 0 %} + + {% else %} + + {% endif %} + {{ diff.completion_diff_30j > 0 ? '+' ~ diff.completion_diff_30j : diff.completion_diff_30j }}% + + + + {% if diff.count_diff_6mois > 0 %} + + {% elseif diff.count_diff_6mois < 0 %} + + {% else %} + + {% endif %} + {{ diff.count_diff_6mois > 0 ? '+' ~ diff.count_diff_6mois : diff.count_diff_6mois }} objets +
+ Complétion : + {% if diff.completion_diff_6mois > 0 %} + + {% elseif diff.completion_diff_6mois < 0 %} + + {% else %} + + {% endif %} + {{ diff.completion_diff_6mois > 0 ? '+' ~ diff.completion_diff_6mois : diff.completion_diff_6mois }}% + {% endif %} {% endfor %} {% if not has_change %} - Aucun changement significatif cette semaine. + Aucun changement significatif cette semaine. {% endif %} diff --git a/templates/admin/followup_theme_graph.html.twig b/templates/admin/followup_theme_graph.html.twig index b2eb223f..dec5aebd 100644 --- a/templates/admin/followup_theme_graph.html.twig +++ b/templates/admin/followup_theme_graph.html.twig @@ -101,6 +101,23 @@ .btn-josm { margin-bottom: 1rem; } + /* Bouton flottant suggestion desktop */ + .suggestion-float-btn { + position: fixed; + bottom: 32px; + right: 32px; + z-index: 1000; + box-shadow: 0 2px 8px rgba(0,0,0,0.15); + display: none; + } + @media (min-width: 768px) { + .suggestion-float-btn { display: block; } + .suggestion-footer-btn { display: none !important; } + } + @media (max-width: 767.98px) { + .suggestion-float-btn { display: none !important; } + .suggestion-footer-btn { display: block; width: 100%; margin: 0; border-radius: 0; } + } {% endblock %} @@ -167,6 +184,9 @@ Complétion des rues + + Faire une suggestion + {% if josm_url %} @@ -254,6 +274,29 @@ {% endif %} +
+
+ Statistiques des tags utilisés dans les objets trouvés +
+
+
+ + + + + + + + + + +
TagNombre d'occurrences
Chargement...
+
+
+
+ {% endblock %} {% block javascripts %} @@ -329,6 +372,8 @@ .then(data => { if (!data.elements || data.elements.length === 0) { document.getElementById('themeMap').innerHTML = '
Aucun objet trouvé via Overpass pour ce thème.
'; + // Vider le tableau des tags + document.querySelector('#tags-stats-table tbody').innerHTML = 'Aucun objet trouvé'; return; } // Centrage carte @@ -401,6 +446,25 @@ .setPopup(new maplibregl.Popup({ offset: 18 }).setHTML(popupHtml)) .addTo(mapInstance); }); + // --- Statistiques des tags --- + const tagCounts = {}; + data.elements.forEach(e => { + if (e.tags) { + Object.entries(e.tags).forEach(([k, v]) => { + if (!tagCounts[k]) tagCounts[k] = 0; + tagCounts[k]++; + }); + } + }); + const tbody = document.querySelector('#tags-stats-table tbody'); + if (Object.keys(tagCounts).length === 0) { + tbody.innerHTML = 'Aucun tag trouvé'; + } else { + tbody.innerHTML = Object.entries(tagCounts) + .sort((a, b) => b[1] - a[1]) + .map(([k, v]) => `${k}${v}`) + .join(''); + } }) .catch(err => { document.getElementById('themeMap').innerHTML = '
Erreur lors de la requête Overpass : ' + err + '
'; diff --git a/templates/public/add_city.html.twig b/templates/public/add_city.html.twig index a8424b96..7962b97d 100644 --- a/templates/public/add_city.html.twig +++ b/templates/public/add_city.html.twig @@ -11,13 +11,9 @@ Retour à l'accueil - +
-
-

Labourage d'une nouvelle ville

-

Entrez le code INSEE de votre ville pour l'ajouter à notre base de données

-
{% include 'public/labourage-form.html.twig' %}
diff --git a/templates/public/stats_evolutions.html.twig b/templates/public/stats_evolutions.html.twig index 71cea2ec..59734325 100644 --- a/templates/public/stats_evolutions.html.twig +++ b/templates/public/stats_evolutions.html.twig @@ -151,8 +151,6 @@

Aucun lieu modifié dans les 6 derniers mois.

{% endif %}
- - - + {% endblock %} \ No newline at end of file