Files
EM2_ERP/em2rp/temp.txt
T

301 lines
27 KiB
Plaintext

 color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
),
],
),
);
}
Widget _buildEquipmentCard(EquipmentModel equipment, {Key? key}) {
final isSelected = _selectedItems.containsKey(equipment.id);
final isConsumable = equipment.category == EquipmentCategory.consumable ||
equipment.category == EquipmentCategory.cable;
final availableQty = _availableQuantities[equipment.id];
final selectedItem = _selectedItems[equipment.id];
final hasConflict = _conflictingEquipmentIds.contains(equipment.id); // CORRECTION ICI !
final conflictDetails = _getConflictDetailsFor(equipment.id);
// Bloquer la sélection si en conflit et non forcé
final canSelect = !hasConflict || isSelected;
return RepaintBoundary(
key: key,
child: Card(
margin: const EdgeInsets.only(bottom: 12),
elevation: isSelected ? 4 : 1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side: isSelected
? const BorderSide(color: AppColors.rouge, width: 2)
: hasConflict
? BorderSide(color: Colors.orange.shade300, width: 1)
: BorderSide.none,
),
child: InkWell(
onTap: canSelect
? () => _toggleSelection(
equipment.id,
equipment.id,
SelectionType.equipment,
maxQuantity: availableQty,
)
: null,
borderRadius: BorderRadius.circular(8),
child: Container(
decoration: hasConflict && !isSelected
? BoxDecoration(
color: Colors.orange.shade50,
borderRadius: BorderRadius.circular(8),
)
: null,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Row(
children: [
// Checkbox
Checkbox(
value: isSelected,
onChanged: canSelect
? (value) => _toggleSelection(
equipment.id,
equipment.id,
SelectionType.equipment,
maxQuantity: availableQty,
)
: null,
activeColor: AppColors.rouge,
),
const SizedBox(width: 12),
// Icône
equipment.category.getIcon(size: 32, color: equipment.category.color),
const SizedBox(width: 16),
// Infos
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
equipment.id,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
if (hasConflict)
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Colors.orange.shade700,
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.warning, size: 14, color: Colors.white),
const SizedBox(width: 4),
Text(
'Déjà utilisé',
style: const TextStyle(
color: Colors.white,
fontSize: 11,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
),
if (equipment.brand != null || equipment.model != null)
Text(
'${equipment.brand ?? ''} ${equipment.model ?? ''}'.trim(),
style: TextStyle(
color: Colors.grey.shade700,
fontSize: 14,
),
),
// Affichage des boîtes parentes
if (_getParentContainers(equipment.id).isNotEmpty)
Padding(
padding: const EdgeInsets.only(top: 4),
child: Wrap(
spacing: 4,
runSpacing: 4,
children: _getParentContainers(equipment.id).map((container) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: Colors.blue.shade50,
border: Border.all(color: Colors.blue.shade300),
borderRadius: BorderRadius.circular(10),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.inventory, size: 12, color: Colors.blue.shade700),
const SizedBox(width: 4),
Text(
container.name,
style: TextStyle(
fontSize: 10,
color: Colors.blue.shade700,
fontWeight: FontWeight.w500,
),
),
],
),
);
}).toList(),
),
),
if (isConsumable)
Padding(
padding: const EdgeInsets.only(top: 4),
child: _buildQuantityInfo(equipment),
),
],
),
),
// Sélecteur de quantité pour consommables (toujours affiché)
if (isConsumable && availableQty != null)
_buildQuantitySelector(
equipment.id,
selectedItem ?? SelectedItem(
id: equipment.id,
name: equipment.id,
type: SelectionType.equipment,
quantity: 0, // Quantité 0 si non sélectionné
),
availableQty,
isSelected: isSelected, // Passer l'état de sélection
),
],
),
// Affichage des conflits
if (hasConflict)
Container(
margin: const EdgeInsets.only(top: 12),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.orange.shade100,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.orange.shade300),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(Icons.info_outline, size: 16, color: Colors.orange.shade900),
const SizedBox(width: 6),
Text(
'Utilisé sur ${conflictDetails.length} événement(s) :',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.orange.shade900,
),
),
],
),
const SizedBox(height: 6),
...conflictDetails.take(2).map((detail) {
final eventName = detail['eventName'] as String? ?? 'Événement inconnu';
final viaContainer = detail['viaContainer'] as String?;
final viaContainerName = detail['viaContainerName'] as String?;
return Padding(
padding: const EdgeInsets.only(left: 22, top: 4),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'• $eventName',
style: TextStyle(
fontSize: 11,
color: Colors.orange.shade800,
),
),
if (viaContainer != null)
Padding(
padding: const EdgeInsets.only(left: 8),
child: Text(
'via ${viaContainerName ?? viaContainer}',
style: TextStyle(
fontSize: 10,
color: Colors.grey.shade600,
fontStyle: FontStyle.italic,
),
),
),
],
),
);
}),
if (conflictDetails.length > 2)
Padding(
padding: const EdgeInsets.only(left: 22, top: 4),
child: Text(
'... et ${conflictDetails.length - 2} autre(s)',
style: TextStyle(
fontSize: 11,
color: Colors.orange.shade800,
fontStyle: FontStyle.italic,
),
),
),
if (!isSelected)
Padding(
padding: const EdgeInsets.only(top: 8),
child: TextButton.icon(
onPressed: () => _toggleSelection(
equipment.id,
equipment.id,
SelectionType.equipment,
maxQuantity: availableQty,
force: true,
),
icon: const Icon(Icons.warning, size: 16),
label: const Text('Forcer quand même', style: TextStyle(fontSize: 12)),
style: TextButton.styleFrom(
foregroundColor: Colors.orange.shade900,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
),
),
),
],
),
),
],
),
),
),
),
);
}
/// Widget pour le sélecteur de quantité
/// Si isSelected = false, le premier clic sur + sélectionne l'item avec quantité 1
Widget _buildQuantitySelector(
String equipmentId,
SelectedItem selectedItem,
int maxQuantity, {
required bool isSelected,
}) {
final displayQuantity = isSelected ? selectedItem.quantity : 0;