liens de thème dans la page de graphe, thèmes bouche d'égout, micro bibliothèque, parc à jeux
This commit is contained in:
parent
0a5814011f
commit
979be016f2
6 changed files with 117 additions and 86 deletions
|
@ -218,7 +218,7 @@ La commande traite la ville la plus ancienne en attente de labourage, si les res
|
|||
Pour labourer environ 300 villes par jour, il faut lancer la commande toutes les 5 minutes (24h * 60min / 5 = 288 passages par jour) :
|
||||
|
||||
```
|
||||
*/5 * * * * cd /chemin/vers/le/projet && php bin/console app:process-labourage-queue >> var/log/labourage_cron.log 2>&1
|
||||
*/5 * * * * cd /poule/encrypted/www/osm-commerces && php bin/console app:process-labourage-queue >> var/log/labourage_cron.log 2>&1
|
||||
```
|
||||
|
||||
Chaque exécution traite une ville si les ressources le permettent. En adaptant la fréquence, vous pouvez ajuster le débit de traitement.
|
||||
|
|
35
migrations/Version20250714165523.php
Normal file
35
migrations/Version20250714165523.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20250714165523 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->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 LONGTEXT 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);
|
||||
}
|
||||
}
|
|
@ -243,13 +243,12 @@ final class AdminController extends AbstractController
|
|||
$this->entityManager->flush();
|
||||
|
||||
// Générer les suivis (followups) après la mise à jour des Places
|
||||
$this->followUpService->generateCityFollowUps($stats, $this->motocultrice, $this->entityManager);
|
||||
|
||||
$message = 'Labourage terminé avec succès. ' . $processedCount . ' nouveaux lieux traités.';
|
||||
if ($updateExisting) {
|
||||
$message .= ' ' . $updatedCount . ' lieux existants mis à jour pour la zone ' . $stats->getName() . ' (' . $stats->getZone() . ').';
|
||||
$themes = \App\Service\FollowUpService::getFollowUpThemes();
|
||||
foreach (array_keys($themes) as $theme) {
|
||||
$this->followUpService->generateCityFollowUps($stats, $this->motocultrice, $this->entityManager, true, $theme);
|
||||
}
|
||||
$this->addFlash('success', $message);
|
||||
$this->entityManager->flush();
|
||||
return $this->redirectToRoute('app_admin_stats', ['insee_code' => $insee_code]);
|
||||
}
|
||||
|
||||
$this->entityManager->flush();
|
||||
|
@ -649,8 +648,9 @@ final class AdminController extends AbstractController
|
|||
'count_data' => json_encode($countData),
|
||||
'completion_data' => json_encode($completionData),
|
||||
'icons' => \App\Service\FollowUpService::getFollowUpIcons(),
|
||||
'followup_labels' => $themes,
|
||||
'geojson' => json_encode($geojson),
|
||||
'overpass_query' => $overpass_query | "",
|
||||
'overpass_query' => $overpass_query,
|
||||
'josm_url' => $josm_url,
|
||||
'center' => $center,
|
||||
'maptiler_token' => $_ENV['MAPTILER_TOKEN'] ?? null,
|
||||
|
@ -765,7 +765,10 @@ final class AdminController extends AbstractController
|
|||
$this->addFlash('warning', "Le serveur est trop sollicité actuellement (RAM insuffisante). La mise à jour des lieux sera effectuée plus tard automatiquement.");
|
||||
}
|
||||
// Toujours générer les CityFollowUp (mais ne jamais les supprimer)
|
||||
$this->followUpService->generateCityFollowUps($stats, $this->motocultrice, $this->entityManager, true /* disable cleanup: ne supprime rien */);
|
||||
$themes = \App\Service\FollowUpService::getFollowUpThemes();
|
||||
foreach (array_keys($themes) as $theme) {
|
||||
$this->followUpService->generateCityFollowUps($stats, $this->motocultrice, $this->entityManager, true, $theme);
|
||||
}
|
||||
$this->entityManager->flush();
|
||||
return $this->redirectToRoute('app_admin_stats', ['insee_code' => $insee_code]);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ class CityFollowUp
|
|||
#[ORM\Column]
|
||||
private ?\DateTime $date = null;
|
||||
|
||||
#[ORM\ManyToOne(targetEntity: Stats::class, inversedBy: 'cityFollowUps')]
|
||||
#[ORM\ManyToOne(targetEntity: Stats::class, inversedBy: 'cityFollowUps', cascade: ['persist'])]
|
||||
private ?Stats $stats = null;
|
||||
|
||||
public function getId(): ?int
|
||||
|
|
|
@ -68,6 +68,12 @@ class FollowUpService
|
|||
$objects = [];
|
||||
} elseif ($type === 'power_pole') {
|
||||
$objects = array_filter($elements, fn($el) => ($el['tags']['power'] ?? null) === 'pole') ?? [];
|
||||
} elseif ($type === 'manhole') {
|
||||
$objects = array_filter($elements, fn($el) => ($el['tags']['manhole'] ?? null) === 'manhole') ?? [];
|
||||
} elseif ($type === 'little_free_library') {
|
||||
$objects = array_filter($elements, fn($el) => ($el['tags']['amenity'] ?? null) === 'little_free_library') ?? [];
|
||||
} elseif ($type === 'playground') {
|
||||
$objects = array_filter($elements, fn($el) => ($el['tags']['leisure'] ?? null) === 'playground') ?? [];
|
||||
} else {
|
||||
$objects = [];
|
||||
}
|
||||
|
@ -148,40 +154,8 @@ class FollowUpService
|
|||
$em->flush();
|
||||
$em->clear();
|
||||
|
||||
// Suppression des mesures redondantes (même valeur consécutive, sauf la dernière) - désactivée si $disableCleanup est true
|
||||
if (!$disableCleanup) {
|
||||
$repo = $em->getRepository(CityFollowUp::class);
|
||||
foreach (array_keys(self::getFollowUpThemes()) as $type) {
|
||||
foreach (['_count', '_completion'] as $suffix) {
|
||||
$name = $type . $suffix;
|
||||
$followups = $repo->createQueryBuilder('f')
|
||||
->where('f.stats = :stats')
|
||||
->andWhere('f.name = :name')
|
||||
->setParameter('stats', $stats)
|
||||
->setParameter('name', $name)
|
||||
->orderBy('f.date', 'ASC')
|
||||
->getQuery()->getResult();
|
||||
$toDelete = [];
|
||||
$prev = null;
|
||||
$n = count($followups);
|
||||
foreach ($followups as $i => $fu) {
|
||||
// Si seulement 2 mesures, ne rien supprimer
|
||||
if ($n == 2) {
|
||||
break;
|
||||
}
|
||||
if ($prev && $fu->getMeasure() === $prev->getMeasure() && $i < $n - 1) {
|
||||
$toDelete[] = $prev;
|
||||
}
|
||||
$prev = $fu;
|
||||
}
|
||||
foreach ($toDelete as $del) {
|
||||
$em->remove($del);
|
||||
}
|
||||
}
|
||||
}
|
||||
$em->flush();
|
||||
$em->clear();
|
||||
}
|
||||
// Suppression des mesures redondantes (même valeur consécutive, sauf la dernière) - désactivée définitivement
|
||||
// (aucune suppression de CityFollowUp)
|
||||
}
|
||||
|
||||
public function generateGlobalFollowUps(EntityManagerInterface $em): void
|
||||
|
@ -296,6 +270,9 @@ class FollowUpService
|
|||
'tree' => 'Arbres',
|
||||
'places' => 'Lieux',
|
||||
'power_pole' => 'Poteaux électriques',
|
||||
'manhole' => "Bouche d'égout",
|
||||
'little_free_library' => "Micro bibliothèque",
|
||||
'playground' => "Parc à jeux pour enfants",
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -325,6 +302,9 @@ class FollowUpService
|
|||
'tree' => 'bi-tree',
|
||||
'places' => 'bi-geo-alt',
|
||||
'power_pole' => 'bi-signpost',
|
||||
'manhole' => 'bi-droplet-half',
|
||||
'little_free_library' => 'bi-book',
|
||||
'playground' => 'bi-emoji-smile',
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -359,6 +339,9 @@ class FollowUpService
|
|||
'drinking_water' => 'nwr["amenity"="drinking_water"](area.searchArea);',
|
||||
'tree' => 'nwr["natural"="tree"](area.searchArea);',
|
||||
'power_pole' => 'nwr["power"="pole"](area.searchArea);',
|
||||
'manhole' => 'nwr["manhole"](area.searchArea);',
|
||||
'little_free_library' => 'nwr["amenity"="little_free_library"](area.searchArea);',
|
||||
'playground' => 'nwr["leisure"="playground"](area.searchArea);',
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -505,6 +488,9 @@ class FollowUpService
|
|||
'tree' => ['species', 'leaf_type', 'leaf_cycle'],
|
||||
'power_pole' => ['ref', 'material'],
|
||||
'places' => ['name', 'address', 'opening_hours', 'website', 'phone', 'wheelchair', 'siret'],
|
||||
'manhole' => ['manhole', 'location'],
|
||||
'little_free_library' => ['amenity', 'operator'],
|
||||
'playground' => ['playground', 'operator'],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -187,6 +187,12 @@
|
|||
|
||||
</div>
|
||||
|
||||
|
||||
{% if overpass_query is defined %}
|
||||
<a href="https://overpass-turbo.eu/?Q={{ overpass_query|url_encode }}" target="_blank" class="btn btn-outline-primary">
|
||||
<i class="bi bi-geo"></i> Vérifier sur Overpass Turbo
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if josm_url %}
|
||||
<a href="{{ josm_url }}" class="btn btn-outline-dark btn-josm" target="_blank">
|
||||
<i class="bi bi-box-arrow-up-right"></i> Ouvrir tous les objets dans JOSM
|
||||
|
@ -194,17 +200,13 @@
|
|||
{% else %}
|
||||
<div class="alert alert-info mb-3">Aucun objet sélectionné pour ce thème, rien à charger dans JOSM.</div>
|
||||
{% endif %}
|
||||
{# <label for="basemapSelect" class="form-label mb-1">Fond de carte :</label>
|
||||
<select id="basemapSelect" class="form-select">
|
||||
<option value="streets">MapTiler Streets</option>
|
||||
<option value="satellite">BD Ortho IGN</option>
|
||||
</select> #}
|
||||
|
||||
<div id="themeMap"></div>
|
||||
{% if geojson is defined %}
|
||||
{# On n'utilise plus geojson côté PHP, la carte sera alimentée dynamiquement via Overpass en JS #}
|
||||
{% endif %}
|
||||
{% if overpass_query is defined %}
|
||||
<div class="mb-3">
|
||||
<a href="https://overpass-turbo.eu/?Q={{ overpass_query|url_encode }}" target="_blank" class="btn btn-outline-primary mt-2">
|
||||
<i class="bi bi-geo"></i> Vérifier sur Overpass Turbo
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
|
@ -225,31 +227,6 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
{# <div class="card p-3">
|
||||
<h5>Progression</h5>
|
||||
<table class="table table-sm mb-0">
|
||||
<thead><tr><th>Période</th><th>Nombre</th><th>Complétion (%)</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>7 jours</td><td>{{ progressions.count['7j'] is not null ? '%+d'|format(progressions.count['7j']) : '–' }}</td><td>{{ progressions.completion['7j'] is not null ? '%+.1f'|format(progressions.completion['7j']) : '–' }}</td></tr>
|
||||
<tr><td>30 jours</td><td>{{ progressions.count['30j'] is not null ? '%+d'|format(progressions.count['30j']) : '–' }}</td><td>{{ progressions.completion['30j'] is not null ? '%+.1f'|format(progressions.completion['30j']) : '–' }}</td></tr>
|
||||
<tr><td>6 mois</td><td>{{ progressions.count['6m'] is not null ? '%+d'|format(progressions.count['6m']) : '–' }}</td><td>{{ progressions.completion['6m'] is not null ? '%+.1f'|format(progressions.completion['6m']) : '–' }}</td></tr>
|
||||
<tr><td>1 an</td><td>{{ progressions.count['1a'] is not null ? '%+d'|format(progressions.count['1a']) : '–' }}</td><td>{{ progressions.completion['1a'] is not null ? '%+.1f'|format(progressions.completion['1a']) : '–' }}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div> #}
|
||||
</div>
|
||||
<div class="col-md-6 d-flex align-items-end">
|
||||
<div class="ms-auto">
|
||||
<label for="basemapSelect" class="form-label mb-1">Fond de carte :</label>
|
||||
<select id="basemapSelect" class="form-select">
|
||||
<option value="streets">MapTiler Streets</option>
|
||||
<option value="satellite">BD Ortho IGN</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chart-container">
|
||||
<canvas id="themeChart"></canvas>
|
||||
|
@ -291,6 +268,24 @@
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{# Bloc navigation autres thématiques #}
|
||||
{% if followup_labels is defined and icons is defined %}
|
||||
<hr>
|
||||
<div class="mt-4">
|
||||
<h4>Autres thématiques de suivi :</h4>
|
||||
<ul class="list-inline">
|
||||
{% for t, label in followup_labels %}
|
||||
{% if t != theme %}
|
||||
<li class="list-inline-item mb-2">
|
||||
<a href="{{ path('admin_followup_theme_graph', {'insee_code': stats.zone, 'theme': t}) }}" class="btn btn-outline-secondary">
|
||||
<i class="bi {{ icons[t]|default('bi-question-circle') }}"></i> {{ label }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<a href="https://forum.openstreetmap.fr/t/osm-mon-commerce/34403/11" class="btn btn-info suggestion-footer-btn mt-4 mb-2" target="_blank" rel="noopener">
|
||||
<i class="bi bi-chat-dots"></i> Faire une suggestion
|
||||
|
@ -429,15 +424,27 @@
|
|||
// Affichage des tags manquants
|
||||
let missingHtml = '';
|
||||
if (missingTags.length > 0) {
|
||||
missingHtml = `<div style='color:#b30000;font-size:0.95em;margin-top:4px;'><b>Manque :</b> ${missingTags.map(t => `<code>${t}</code>`).join(', ')}</div>`;
|
||||
missingHtml = `<div style='color:#b30000;font-size:0.95em;margin-top:4px;'><b>Manque :</b> ` + missingTags.map(t => `<a href='https://wiki.openstreetmap.org/wiki/Key:${encodeURIComponent(t)}' target='_blank' rel='noopener'><code>${t}</code></a>`).join(', ') + `</div>`;
|
||||
}
|
||||
// Liens édition JOSM et iD
|
||||
const josmUrl = `http://127.0.0.1:8111/load_object?objects=${e.type[0].toUpperCase()}${e.id}`;
|
||||
const idUrl = `https://www.openstreetmap.org/edit?editor=id&${e.type}=${e.id}`;
|
||||
const popupHtml = `<div style='min-width:180px'>
|
||||
<strong>${e.tags && e.tags.name ? e.tags.name : '(sans nom)'}</strong><br>
|
||||
<span class='text-muted'>${e.type} ${e.id}</span><br>
|
||||
<span style='font-size:0.95em;'>${e.tags ? Object.entries(e.tags).map(([k,v]) => `<span><b>${k}</b>: ${v}</span>`).join('<br>') : ''}</span><br>
|
||||
<h2 class="title is-2">${e.tags && e.tags.name ? e.tags.name : '(sans nom)'}</h2><br>
|
||||
<b>Complétion :</b> ${completion !== null ? completion + '%' : '–'}
|
||||
${missingHtml}
|
||||
<br><a href='https://www.openstreetmap.org/${e.type}/${e.id}' target='_blank'>Voir sur OSM</a>
|
||||
<br>
|
||||
|
||||
<a class="btn btn-info" href='https://www.openstreetmap.org/${e.type}/${e.id}' target='_blank'>
|
||||
<i class="bi bi-planet" ></i>
|
||||
Voir sur OSM</a>
|
||||
<br>
|
||||
<a class="btn btn-info" href='${josmUrl}' target='_blank'> <i class="bi bi-map" ></i> JOSM</a>
|
||||
<a class="btn btn-info" href='${idUrl}' target='_blank'><i class="bi bi-pencil" ></i>iD</a>
|
||||
|
||||
|
||||
<span style='font-size:0.95em;'>${e.tags ? Object.entries(e.tags).map(([k,v]) => `<span><b>${k}</b>: ${v}</span>`).join('<br>') : ''}</span><br>
|
||||
|
||||
</div>`;
|
||||
new maplibregl.Marker({ color: color })
|
||||
.setLngLat([lon, lat])
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue