feat: Gestion des secteurs et migration v3.0.4+304
- Ajout système complet de gestion des secteurs avec contours géographiques - Import des contours départementaux depuis GeoJSON - API REST pour la gestion des secteurs (/api/sectors) - Service de géolocalisation pour déterminer les secteurs - Migration base de données avec tables x_departements_contours et sectors_adresses - Interface Flutter pour visualisation et gestion des secteurs - Ajout thème sombre dans l'application - Corrections diverses et optimisations 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
453
app/docs/GESTION-SECTEURS.md
Normal file
453
app/docs/GESTION-SECTEURS.md
Normal file
@@ -0,0 +1,453 @@
|
||||
# Gestion des Secteurs et de la Carte
|
||||
|
||||
Ce document centralise toutes les règles de gestion des secteurs et de la carte dans l'application Geosector.
|
||||
|
||||
**Dernière mise à jour** : Décembre 2024 - Améliorations de la détection d'adjacence et de l'ergonomie du drag
|
||||
|
||||
## Table des matières
|
||||
|
||||
1. [Vue d'ensemble](#vue-densemble)
|
||||
2. [Structure des données](#structure-des-données)
|
||||
3. [Modes de la carte](#modes-de-la-carte)
|
||||
4. [Création d'un secteur](#création-dun-secteur)
|
||||
5. [Gestion des secteurs adjacents](#gestion-des-secteurs-adjacents)
|
||||
6. [Modification d'un secteur](#modification-dun-secteur)
|
||||
7. [Suppression d'un secteur](#suppression-dun-secteur)
|
||||
8. [Affichage des secteurs](#affichage-des-secteurs)
|
||||
9. [Affichage des passages](#affichage-des-passages)
|
||||
10. [Permissions et rôles](#permissions-et-rôles)
|
||||
11. [Synchronisation API/Hive](#synchronisation-apihive)
|
||||
12. [Interactions utilisateur](#interactions-utilisateur)
|
||||
13. [Bonnes pratiques](#bonnes-pratiques)
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
La carte administrative (`AdminMapPage`) permet aux administrateurs de gérer les secteurs géographiques d'une opération. Chaque secteur est un polygone défini par des coordonnées GPS et peut contenir des passages (adresses à visiter).
|
||||
|
||||
### Technologies utilisées
|
||||
- **flutter_map** avec **MapBox** pour l'affichage de la carte
|
||||
- **Hive** pour le stockage local des données
|
||||
- **ValueListenableBuilder** pour la mise à jour réactive de l'interface
|
||||
|
||||
## Structure des données
|
||||
|
||||
### SectorModel
|
||||
```dart
|
||||
{
|
||||
id: int, // Identifiant unique
|
||||
libelle: String, // Nom du secteur
|
||||
color: String, // Couleur hexadécimale (#RRGGBB)
|
||||
sector: String // Coordonnées "lat/lng#lat/lng#..."
|
||||
}
|
||||
```
|
||||
|
||||
### PassageModel
|
||||
```dart
|
||||
{
|
||||
id: int,
|
||||
fk_sector: int, // ID du secteur
|
||||
fk_user: int, // ID de l'utilisateur assigné
|
||||
fk_type: int, // Type de passage (1-6)
|
||||
gps_lat: String, // Latitude
|
||||
gps_lng: String, // Longitude
|
||||
numero: String, // Numéro de rue
|
||||
rue: String, // Nom de la rue
|
||||
ville: String, // Ville
|
||||
// ... autres champs
|
||||
}
|
||||
```
|
||||
|
||||
### Types de passages
|
||||
- **1** : Effectué (vert)
|
||||
- **2** : À finaliser (orange)
|
||||
- **3** : Refusé (rouge)
|
||||
- **4** : Don (bleu)
|
||||
- **5** : Lot (violet)
|
||||
- **6** : Maison vide (gris)
|
||||
|
||||
## Modes de la carte
|
||||
|
||||
La carte peut être dans l'un des modes suivants :
|
||||
|
||||
### MapMode.view (Mode visualisation)
|
||||
- Mode par défaut
|
||||
- Permet de naviguer sur la carte
|
||||
- Affiche les secteurs et passages
|
||||
- Permet la sélection d'un secteur via la combobox
|
||||
|
||||
### MapMode.drawing (Mode création)
|
||||
- Activé par le bouton "Créer un secteur"
|
||||
- Affiche une carte d'aide explicative
|
||||
- Permet de dessiner un nouveau secteur en cliquant sur la carte
|
||||
- Points verts pour le premier point, bleus pour les suivants
|
||||
- Fermeture du polygone en cliquant sur le premier point
|
||||
|
||||
### MapMode.editing (Mode édition)
|
||||
- Activé par le bouton "Modifier un secteur"
|
||||
- Permet de modifier les contours d'un secteur existant
|
||||
- Sélectionner un secteur par clic ou via la combobox puis cliquer "Modifier"
|
||||
- Points orange draggables avec magnétisme automatique
|
||||
- Ajout de points via les points intermédiaires gris
|
||||
- Suppression de points avec clic droit ou Ctrl+clic
|
||||
|
||||
### MapMode.deleting (Mode suppression)
|
||||
- Activé par le bouton "Supprimer un secteur"
|
||||
- Affiche une carte d'aide avec avertissements
|
||||
- Permet de sélectionner un secteur à supprimer en cliquant dessus
|
||||
- Le secteur sélectionné apparaît en rouge
|
||||
|
||||
## Création d'un secteur
|
||||
|
||||
### Processus de création
|
||||
|
||||
1. **Dessin du secteur**
|
||||
- L'administrateur clique sur le bouton "Créer un secteur"
|
||||
- Il dessine le contour en cliquant sur la carte (minimum 3 points)
|
||||
- Il ferme le polygone en cliquant sur le premier point
|
||||
|
||||
2. **Dialog de création**
|
||||
- Nom du secteur (obligatoire)
|
||||
- Couleur du secteur (sélection dans une palette)
|
||||
- Sélection des membres assignés (au moins un obligatoire)
|
||||
|
||||
3. **Envoi à l'API**
|
||||
```json
|
||||
{
|
||||
"id": 0,
|
||||
"libelle": "Nom du secteur",
|
||||
"color": "#2196F3",
|
||||
"sector": "lat/lng#lat/lng#...",
|
||||
"operation_id": 3124,
|
||||
"fk_entite": 5,
|
||||
"users": [9999980, 9999985]
|
||||
}
|
||||
```
|
||||
|
||||
4. **Réponse de l'API**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"sector": { /* ou sector_id */ },
|
||||
"passages_sector": [...],
|
||||
"passages_created": 86,
|
||||
"passages_integrated": 0,
|
||||
"users_sectors": [...],
|
||||
"warning": "Avertissement si débordement départemental",
|
||||
"intersecting_departments": [
|
||||
{
|
||||
"code_dept": "35",
|
||||
"nom_dept": "Ille-et-Vilaine",
|
||||
"percentage_overlap": 85.2
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
5. **Traitement de la réponse**
|
||||
- Le secteur est sauvegardé dans Hive
|
||||
- Les passages sont créés avec les coordonnées GPS
|
||||
- Les associations utilisateur-secteur sont traitées
|
||||
- La carte se centre sur le nouveau secteur
|
||||
|
||||
### Règles de création
|
||||
- Un secteur doit avoir au moins 3 points
|
||||
- Le nom est obligatoire
|
||||
- Au moins un membre doit être assigné
|
||||
- Les coordonnées sont au format "latitude/longitude"
|
||||
- Le dernier point doit fermer le polygone
|
||||
- Les secteurs adjacents sont automatiquement corrigés (voir section dédiée)
|
||||
|
||||
## Gestion des secteurs adjacents
|
||||
|
||||
### Vue d'ensemble
|
||||
|
||||
L'application gère automatiquement la création de secteurs adjacents (partageant une bordure commune) sans générer d'erreur de chevauchement. Cette fonctionnalité est cruciale pour permettre un découpage précis du territoire.
|
||||
|
||||
### Correction automatique des points
|
||||
|
||||
#### Méthode `_correctPointsForAdjacency`
|
||||
|
||||
Cette méthode est appelée automatiquement lors de :
|
||||
- La validation d'un nouveau secteur (création)
|
||||
- La validation d'un secteur modifié (modification)
|
||||
|
||||
**Paramètres de correction :**
|
||||
- **Distance de détection** : 10 mètres
|
||||
- **Décalage de correction** : 2 mètres vers l'intérieur
|
||||
- **Décalage fort** : 5 mètres (si chevauchement persistant)
|
||||
|
||||
**Processus en deux passes :**
|
||||
|
||||
1. **Première passe - Détection et correction des segments adjacents**
|
||||
```dart
|
||||
// Pour chaque segment du nouveau secteur
|
||||
// Vérifier s'il est proche d'un segment existant
|
||||
// Si oui, corriger les deux points du segment
|
||||
```
|
||||
|
||||
2. **Deuxième passe - Vérification et correction forte**
|
||||
```dart
|
||||
// Appel à _ensureNoIntersection
|
||||
// Si chevauchement détecté → _applyStrongerCorrection
|
||||
```
|
||||
|
||||
### Calcul du décalage vers l'intérieur
|
||||
|
||||
#### Méthode `_offsetPointInward`
|
||||
|
||||
**Principe :**
|
||||
- Calcule la bissectrice des segments adjacents
|
||||
- Utilise le produit vectoriel pour déterminer la direction intérieure
|
||||
- Applique un décalage en tenant compte de la latitude
|
||||
|
||||
**Formule de conversion :**
|
||||
```dart
|
||||
offsetDegreesLat = offsetMeters / 111320.0
|
||||
offsetDegreesLng = offsetMeters / (111320.0 * cos(latitude))
|
||||
```
|
||||
|
||||
### Détection intelligente des chevauchements
|
||||
|
||||
#### Méthode `_doPolygonsOverlap`
|
||||
|
||||
**Tolérance d'adjacence** : 2 mètres
|
||||
|
||||
**Règles de détection améliorées :**
|
||||
1. **Points intérieurs** : Un point est considéré à l'intérieur seulement s'il est à plus de 2m du bord
|
||||
2. **Vertices partagés** : Les vertices à moins de 5m de distance sont considérés comme partagés et ignorés
|
||||
3. **Segments adjacents** : Deux segments alignés et proches ne sont pas considérés comme un chevauchement
|
||||
4. **Seuil de détection** : Il faut au moins 3 points intérieurs ou 3 intersections pour détecter un chevauchement réel
|
||||
5. **Exclusion du secteur en cours** : Lors de la modification, le secteur lui-même est exclu de la détection
|
||||
|
||||
#### Méthode `_areSegmentsAdjacent`
|
||||
|
||||
Détermine si deux segments sont adjacents (partagent une partie commune) :
|
||||
- Vérifie l'alignement des segments
|
||||
- Vérifie la proximité des points aux lignes opposées
|
||||
- Retourne `true` si les segments sont sur la même ligne
|
||||
|
||||
### Magnétisme automatique
|
||||
|
||||
Lors de la sélection d'un secteur pour modification :
|
||||
- Application automatique du magnétisme aux points proches
|
||||
- Visualisation immédiate des ajustements
|
||||
- Message d'information si des points ont été magnétisés
|
||||
|
||||
### Exemple de création de secteurs adjacents
|
||||
|
||||
```
|
||||
Secteur A (existant) : Nouveau secteur B :
|
||||
+--------+ +--------+
|
||||
| | | |
|
||||
| A | <-- bordure --> | B |
|
||||
| | commune | |
|
||||
+--------+ +--------+
|
||||
```
|
||||
|
||||
**Résultat après correction automatique :**
|
||||
- Les points de B sur la bordure commune sont décalés de 2m vers l'intérieur
|
||||
- Aucune erreur de chevauchement
|
||||
- Les secteurs restent visuellement adjacents
|
||||
|
||||
### Messages utilisateur
|
||||
|
||||
- **Correction appliquée** : "Les points ont été ajustés automatiquement pour éviter les chevauchements" (bleu)
|
||||
- **Chevauchement détecté** : "Le nouveau secteur chevauche avec le secteur [nom]" (rouge)
|
||||
- **Logging détaillé** : En cas de chevauchement détecté, les coordonnées des zones problématiques sont loggées
|
||||
|
||||
## Modification d'un secteur
|
||||
|
||||
### Processus de modification
|
||||
|
||||
1. **Sélection du secteur**
|
||||
- Via la combobox ou clic sur la carte
|
||||
- Bouton "Modifier" dans la barre d'outils
|
||||
|
||||
2. **Mode édition**
|
||||
- Application automatique du magnétisme dès la sélection
|
||||
- Points draggables instantanément (clic et drag immédiat)
|
||||
- Points orange avec zone de détection élargie (50x50px)
|
||||
- Ajout de points via les points intermédiaires gris
|
||||
- Suppression avec clic droit ou Ctrl+clic
|
||||
- Désactivation du drag de la carte pendant le déplacement d'un point
|
||||
|
||||
3. **Validation**
|
||||
- Mêmes vérifications que pour la création
|
||||
- Application de `_correctPointsForAdjacency` avec exclusion du secteur en cours
|
||||
- Dialog pour modifier nom, couleur et membres
|
||||
- Les membres déjà affectés sont automatiquement présélectionnés
|
||||
- Affichage d'un dialog récapitulatif avec statistiques
|
||||
|
||||
### Règles de modification
|
||||
- Minimum 3 points maintenu
|
||||
- Correction automatique des adjacences
|
||||
- Même processus de validation que la création
|
||||
- Les passages sont automatiquement réaffectés selon le nouveau contour
|
||||
|
||||
## Suppression d'un secteur
|
||||
|
||||
### Processus de suppression
|
||||
|
||||
1. **Sélection du secteur**
|
||||
- L'administrateur clique sur "Supprimer un secteur"
|
||||
- Il clique sur le secteur à supprimer (surbrillance rouge)
|
||||
|
||||
2. **Dialog de confirmation**
|
||||
- Affichage du nom du secteur
|
||||
- Avertissements sur les conséquences
|
||||
|
||||
3. **Règles de suppression des passages**
|
||||
- Passages "à finaliser" (type 2) sans nom d'habitant → **supprimés**
|
||||
- Autres passages → **conservés mais réassignés au secteur 0**
|
||||
|
||||
4. **Réponse de l'API**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"passages_deleted": 45,
|
||||
"passages_reassigned": 125
|
||||
}
|
||||
```
|
||||
|
||||
5. **Mise à jour locale**
|
||||
- Suppression du secteur de Hive
|
||||
- Mise à jour des passages selon les règles
|
||||
- Actualisation automatique de la carte
|
||||
|
||||
## Affichage des secteurs
|
||||
|
||||
### Représentation visuelle
|
||||
- **Polygones colorés** avec transparence (30% en normal, 50% si sélectionné)
|
||||
- **Bordure** de la couleur du secteur (épaisseur 2px, 3px si sélectionné)
|
||||
- **Mode suppression** : secteur en rouge avec bordure épaisse (4px)
|
||||
|
||||
### Filtrage par secteur
|
||||
- Combobox en haut à gauche
|
||||
- "Tous les secteurs" par défaut
|
||||
- Sélection d'un secteur → zoom et centrage automatique
|
||||
- Filtrage des passages affichés
|
||||
|
||||
## Affichage des passages
|
||||
|
||||
### Représentation visuelle
|
||||
- **Marqueurs circulaires** de 14x14 pixels
|
||||
- **Couleur principale** selon le type de passage
|
||||
- **Bordure blanche** de 1px
|
||||
- **Cliquables** pour afficher les détails
|
||||
|
||||
### Conditions d'affichage
|
||||
- Coordonnées GPS valides (gps_lat et gps_lng)
|
||||
- Type de passage reconnu (1-6)
|
||||
- Appartenance au secteur sélectionné (si filtre actif)
|
||||
|
||||
### Informations au clic
|
||||
- Adresse complète
|
||||
- Nom de l'habitant (si disponible)
|
||||
- Type de passage
|
||||
- Informations de règlement (si applicable)
|
||||
- Boutons d'édition/suppression
|
||||
|
||||
## Permissions et rôles
|
||||
|
||||
### Accès à la carte administrative
|
||||
- **Rôle minimum requis** : Admin Amicale (rôle > 1)
|
||||
- **Rôle 1 (Membre)** : Pas d'accès à la carte admin
|
||||
- **Rôle 2+ (Admin)** : Accès complet aux fonctionnalités
|
||||
|
||||
### Actions autorisées
|
||||
- **Création de secteur** : Admin+
|
||||
- **Modification de secteur** : Admin+
|
||||
- **Suppression de secteur** : Admin+
|
||||
- **Visualisation** : Admin+
|
||||
|
||||
## Synchronisation API/Hive
|
||||
|
||||
### Principe "API First"
|
||||
1. Toute modification passe d'abord par l'API
|
||||
2. En cas de succès, mise à jour de Hive
|
||||
3. En cas d'échec, aucune modification locale
|
||||
|
||||
### Flux de données
|
||||
|
||||
#### Chargement initial
|
||||
```
|
||||
API (login) → Secteurs/Passages → Hive → ValueListenableBuilder → UI
|
||||
```
|
||||
|
||||
#### Création de secteur
|
||||
```
|
||||
UI → API → Réponse (secteur + passages) → Hive → Auto-refresh UI
|
||||
```
|
||||
|
||||
#### Suppression de secteur
|
||||
```
|
||||
UI → API → Réponse (stats) → Mise à jour Hive → Auto-refresh UI
|
||||
```
|
||||
|
||||
### Gestion des erreurs
|
||||
- Affichage de SnackBar avec message d'erreur
|
||||
- Pas de modification locale en cas d'échec API
|
||||
- Log des erreurs pour debug
|
||||
|
||||
### Performance
|
||||
- Utilisation de box caching dans les repositories
|
||||
- ValueListenableBuilder pour éviter les rebuilds inutiles
|
||||
- Chargement asynchrone des données
|
||||
|
||||
## Interactions utilisateur
|
||||
|
||||
### Gestion du drag des points
|
||||
|
||||
**Technologie utilisée** : `Listener` avec `onPointerDown`/`onPointerMove`/`onPointerUp`
|
||||
|
||||
**Avantages :**
|
||||
- Démarrage instantané du drag au clic (onPointerDown)
|
||||
- Pas de conflit avec les gestes de la carte
|
||||
- Conversion directe des coordonnées écran en coordonnées géographiques
|
||||
|
||||
**Interactions supportées :**
|
||||
- **Clic gauche** : Démarre le drag immédiatement
|
||||
- **Clic droit / Ctrl+clic** : Supprime le point
|
||||
- **Clic sur premier point (mode dessin)** : Ferme le polygone si 3+ points
|
||||
- **Drag** : Déplace le point avec magnétisme en temps réel
|
||||
|
||||
### Dialog récapitulatif
|
||||
|
||||
Après chaque opération (création/modification/suppression), un dialog affiche :
|
||||
- **Statistiques des passages** : créés, mis à jour, orphelins, total
|
||||
- **Avertissements départementaux** : si le secteur est à cheval sur plusieurs départements
|
||||
- **Icônes et couleurs** adaptées selon le type d'opération
|
||||
|
||||
## Bonnes pratiques
|
||||
|
||||
### Pour les développeurs
|
||||
|
||||
1. **Toujours passer par l'API** pour les modifications
|
||||
2. **Utiliser les repositories** pour l'accès aux données
|
||||
3. **Ne pas faire de setState** dans les ValueListenableBuilder
|
||||
4. **Gérer les erreurs** avec ApiException
|
||||
5. **Valider les données** avant envoi à l'API
|
||||
6. **Logger les actions importantes** pour le debug
|
||||
7. **Utiliser les mêmes méthodes de validation** pour création et modification :
|
||||
- `_correctPointsForAdjacency` pour la correction automatique
|
||||
- `_doPolygonsOverlap` pour la détection de chevauchement
|
||||
- `_isValidPolygon` pour la validation de base
|
||||
8. **Sauvegarder le contexte parent** avant d'ouvrir des dialogs pour éviter les erreurs de contexte
|
||||
9. **Implémenter le chargement des associations** (ex: UserSectorModel) pour présélectionner les données
|
||||
|
||||
### Pour les utilisateurs
|
||||
|
||||
1. **Dessiner des secteurs cohérents** (pas de croisements)
|
||||
2. **Nommer clairement** les secteurs
|
||||
3. **Assigner les bons membres** dès la création
|
||||
4. **Vérifier avant suppression** (action irréversible)
|
||||
5. **Utiliser des couleurs distinctes** pour différencier les secteurs
|
||||
6. **Pour les secteurs adjacents** :
|
||||
- Dessiner normalement sans se soucier de la précision
|
||||
- Le système ajuste automatiquement les bordures
|
||||
- Vérifier le résultat après la correction automatique
|
||||
7. **Pour la modification des secteurs** :
|
||||
- Cliquer directement sur un point pour le déplacer (pas besoin de maintenir)
|
||||
- Utiliser les points gris intermédiaires pour ajouter des sommets
|
||||
- Clic droit ou Ctrl+clic pour supprimer un point
|
||||
- Le magnétisme s'applique automatiquement aux bordures adjacentes
|
||||
Reference in New Issue
Block a user