feat: Gestion complète des containers et refactorisation du matériel

Ajout de la gestion des containers (création, édition, suppression, affichage des détails).
Introduction d'un système de génération de QR codes unifié et d'un mode de sélection multiple.

**Features:**
- **Gestion des Containers :**
    - Nouvelle page de gestion des containers (`container_management_page.dart`) avec recherche et filtres.
    - Formulaire de création/édition de containers (`container_form_page.dart`) avec génération d'ID automatique.
    - Page de détails d'un container (`container_detail_page.dart`) affichant son contenu et ses caractéristiques.
    - Ajout des routes et du provider (`ContainerProvider`) nécessaires.
- **Modèle de Données :**
    - Ajout du `ContainerModel` pour représenter les boîtes, flight cases, etc.
    - Le modèle `EquipmentModel` a été enrichi avec des caractéristiques physiques (poids, dimensions).
- **QR Codes :**
    - Nouveau service unifié (`UnifiedPDFGeneratorService`) pour générer des PDFs de QR codes pour n'importe quelle entité.
    - Services `PDFGeneratorService` et `ContainerPDFGeneratorService` transformés en wrappers pour maintenir la compatibilité.
    - Amélioration de la performance de la génération de QR codes en masse.
- **Interface Utilisateur (UI/UX) :**
    - Nouvelle page de détails pour le matériel (`equipment_detail_page.dart`).
    - Ajout d'un `SelectionModeMixin` pour gérer la sélection multiple dans les pages de gestion.
    - Dialogues réutilisables pour l'affichage de QR codes (`QRCodeDialog`) et la sélection de format d'impression (`QRCodeFormatSelectorDialog`).
    - Ajout d'un bouton "Gérer les boîtes" sur la page de gestion du matériel.

**Refactorisation :**
- L' `IdGenerator` a été déplacé dans le répertoire `utils` et étendu pour gérer les containers.
- Mise à jour de nombreuses dépendances `pubspec.yaml` vers des versions plus récentes.
- Séparation de la logique d'affichage des containers et du matériel dans des widgets dédiés (`ContainerHeaderCard`, `EquipmentParentContainers`, etc.).
This commit is contained in:
ElPoyo
2025-10-29 10:57:42 +01:00
parent ae3a1b7227
commit 3fab69cb00
31 changed files with 6540 additions and 656 deletions

View File

@@ -0,0 +1,155 @@
import 'package:em2rp/models/container_model.dart';
import 'package:em2rp/services/equipment_service.dart';
/// Générateur d'identifiants unifié pour l'application
/// Gère les équipements, containers et autres entités
class IdGenerator {
// ============================================================================
// ÉQUIPEMENTS
// ============================================================================
/// Génère un ID pour un équipement
/// Format: {Marque4Chars}_{Modèle}_{#Numéro}
/// Exemple: BEAM_7R_#1
static String generateEquipmentId({
required String brand,
required String model,
int? number,
}) {
final brandTrim = brand.trim().replaceAll(' ', '_');
final modelTrim = model.trim().replaceAll(' ', '_');
if (brandTrim.isEmpty && modelTrim.isEmpty) {
return 'EQ-${DateTime.now().millisecondsSinceEpoch}${number != null ? '_$number' : ''}';
}
final brandPrefix = brandTrim.length >= 4
? brandTrim.substring(0, 4)
: brandTrim;
String baseId = modelTrim.isNotEmpty
? '${brandPrefix}_$modelTrim'
: (brandPrefix.isNotEmpty ? brandPrefix : 'EQ');
// Empêcher les ID commençant par BOX_ (réservé aux containers)
if (baseId.toUpperCase().startsWith('BOX_')) {
baseId = 'EQ_$baseId';
}
if (number != null) {
baseId += '_#$number';
}
return baseId.toUpperCase();
}
/// Garantit l'unicité d'un ID d'équipement
static Future<String> ensureUniqueEquipmentId(
String baseId,
EquipmentService service,
) async {
// Vérifier que l'ID ne commence pas par BOX_
if (baseId.toUpperCase().startsWith('BOX_')) {
baseId = 'EQ_$baseId';
}
if (await service.isIdUnique(baseId)) {
return baseId;
}
return '${baseId}_${DateTime.now().millisecondsSinceEpoch}';
}
// ============================================================================
// CONTAINERS
// ============================================================================
/// Génère un ID pour un container
/// Format: BOX_{Type}_{Nom}_{#Numéro}
/// Exemple: BOX_FLIGHT_CASE_BEAM_#1
static String generateContainerId({
required ContainerType type,
required String name,
int? number,
}) {
final typeStr = containerTypeToString(type);
final cleanName = _cleanId(name);
if (number != null) {
return 'BOX_${typeStr}_${cleanName}_#$number';
}
return 'BOX_${typeStr}_$cleanName';
}
/// Garantit l'unicité d'un ID de container
/// Note: La vérification d'unicité doit être faite par l'appelant
static String ensureUniqueContainerId(String baseId) {
// Retourne simplement l'ID de base
// L'unicité sera vérifiée au niveau du provider/form
return baseId;
}
/// Génère un ID unique avec un timestamp si nécessaire
static String generateUniqueContainerId(String baseId) {
return '${baseId}_${DateTime.now().millisecondsSinceEpoch}';
}
// ============================================================================
// UTILITAIRES
// ============================================================================
/// Nettoie une chaîne pour en faire un ID valide
/// - Supprime les espaces (remplacés par _)
/// - Supprime les caractères spéciaux
/// - Met en majuscules
static String _cleanId(String input) {
return input
.trim()
.toUpperCase()
.replaceAll(' ', '_')
.replaceAll(RegExp(r'[^A-Z0-9_-]'), '');
}
/// Valide qu'un ID d'équipement ne commence pas par un préfixe réservé
static String? validateEquipmentId(String id) {
if (id.isEmpty) {
return 'L\'identifiant ne peut pas être vide';
}
if (id.toUpperCase().startsWith('BOX_')) {
return 'Les ID commençant par BOX_ sont réservés aux containers';
}
return null;
}
/// Valide qu'un ID de container commence bien par BOX_
static String? validateContainerId(String id) {
if (id.isEmpty) {
return 'L\'identifiant ne peut pas être vide';
}
if (!id.toUpperCase().startsWith('BOX_')) {
return 'Les containers doivent avoir un ID commençant par BOX_';
}
return null;
}
/// Détermine le type d'entité à partir d'un ID
static EntityType getEntityType(String id) {
if (id.toUpperCase().startsWith('BOX_')) {
return EntityType.container;
}
return EntityType.equipment;
}
}
/// Type d'entité identifiable
enum EntityType {
equipment,
container,
}