diff --git a/frontend/src/views/PlantesView.vue b/frontend/src/views/PlantesView.vue
index 7b83d55..3ca5f5e 100644
--- a/frontend/src/views/PlantesView.vue
+++ b/frontend/src/views/PlantesView.vue
@@ -85,7 +85,7 @@
-
+
@@ -134,6 +134,14 @@
Mois: {{ detailPlant.plantation_mois }}
+
+ T° germination
+ {{ detailPlantObj.temp_germination }}
+
+
+ Temps de levée
+ {{ detailPlantObj.temps_levee_j }}
+
@@ -203,6 +211,28 @@
+
+
+
+ 🌿 Variétés ({{ detailVarieties.length }})
+
+
+
+
+ {{ v.variete || '(sans nom)' }}
+ 🛒 {{ v.boutique_nom }}
+ {{ v.prix_achat.toFixed(2) }}€
+ ⚠️ DLUO
+
+
+ ✏️
+ ✕
+
+
+
+
+
@@ -228,6 +258,10 @@
+
+ ➕ Variété
+
Modifier la fiche
Supprimer
@@ -462,6 +496,81 @@
+
+
+
+
+
+
+ {{ editVariety ? 'Modifier la variété' : '➕ Nouvelle variété' }}
+
+ ✕
+
+
+ Plante : {{ detailPlantObj?.nom_commun }}
+
+
+
+
@@ -469,7 +578,7 @@
import { computed, onMounted, reactive, ref } from 'vue'
import axios from 'axios'
import { usePlantsStore } from '@/stores/plants'
-import type { Plant } from '@/api/plants'
+import type { Plant, PlantVariety } from '@/api/plants'
import { useToast } from '@/composables/useToast'
const plantsStore = usePlantsStore()
@@ -485,17 +594,35 @@ const lightbox = ref
(null)
const fileInput = ref(null)
const uploadTarget = ref(null)
-// Navigation variétés
-const detailVarieties = ref([])
+// Navigation variétés (groupe de Plant par nom_commun)
+const detailPlantGroup = ref([])
const detailVarietyIdx = ref(0)
-const detailPlant = computed(() => detailVarieties.value[detailVarietyIdx.value] ?? null)
+const detailPlant = computed(() => detailPlantGroup.value[detailVarietyIdx.value] ?? null)
+
+// detailPlantObj : ref sur la plante ouverte en détail (Plant complet)
+const detailPlantObj = ref(null)
+
+// detailVarieties : variétés (PlantVariety) de la plante affichée
+const detailVarieties = computed(() => {
+ if (!detailPlantObj.value) return []
+ return detailPlantObj.value.varieties ?? []
+})
// Associations au niveau nom_commun (première variété ayant des données)
const detailAssociations = computed(() =>
- detailVarieties.value.find(v => v.associations_favorables?.length || v.associations_defavorables?.length)
+ detailPlantGroup.value.find(v => v.associations_favorables?.length || v.associations_defavorables?.length)
?? detailPlant.value
)
+// Refs pour le formulaire variété
+const showFormVariety = ref(false)
+const editVariety = ref(null)
+const formVariety = reactive>({
+ variete: '', tags: '', notes_variete: '',
+ boutique_nom: '', boutique_url: '', prix_achat: undefined,
+ date_achat: '', poids: '', dluo: '',
+})
+
interface Media {
id: number; entity_type: string; entity_id: number
url: string; thumbnail_url?: string; titre?: string
@@ -637,7 +764,8 @@ function catTextClass(cat: string) {
}
function closeDetail() {
- detailVarieties.value = []
+ detailPlantGroup.value = []
+ detailPlantObj.value = null
detailVarietyIdx.value = 0
plantPhotos.value = []
}
@@ -645,21 +773,24 @@ function closeDetail() {
async function openDetails(p: Plant) {
const key = (p.nom_commun || '').toLowerCase()
const group = plantGroups.value.get(key) || [p]
- detailVarieties.value = [...group].sort((a, b) => (a.id || 0) - (b.id || 0))
+ detailPlantGroup.value = [...group].sort((a, b) => (a.id || 0) - (b.id || 0))
detailVarietyIdx.value = 0
- await fetchPhotos(detailVarieties.value[0].id!)
+ detailPlantObj.value = detailPlantGroup.value[0]
+ await fetchPhotos(detailPlantGroup.value[0].id!)
}
async function prevVariety() {
if (detailVarietyIdx.value > 0) {
detailVarietyIdx.value--
+ detailPlantObj.value = detailPlant.value
await fetchPhotos(detailPlant.value!.id!)
}
}
async function nextVariety() {
- if (detailVarietyIdx.value < detailVarieties.value.length - 1) {
+ if (detailVarietyIdx.value < detailPlantGroup.value.length - 1) {
detailVarietyIdx.value++
+ detailPlantObj.value = detailPlant.value
await fetchPhotos(detailPlant.value!.id!)
}
}
@@ -712,6 +843,52 @@ function closeForm() {
})
}
+function openAddVariety() {
+ if (!detailPlantObj.value) return
+ editVariety.value = null
+ Object.assign(formVariety, {
+ variete: '', tags: '', notes_variete: '',
+ boutique_nom: '', boutique_url: '', prix_achat: undefined,
+ date_achat: '', poids: '', dluo: '',
+ })
+ showFormVariety.value = true
+}
+
+function openEditVariety(v: PlantVariety) {
+ editVariety.value = v
+ Object.assign(formVariety, { ...v })
+ showFormVariety.value = true
+}
+
+function closeFormVariety() {
+ showFormVariety.value = false
+ editVariety.value = null
+}
+
+async function submitVariety() {
+ if (!detailPlantObj.value?.id) return
+ const payload = { ...formVariety, prix_achat: formVariety.prix_achat ?? undefined }
+ if (editVariety.value?.id) {
+ await plantsStore.updateVariety(detailPlantObj.value.id, editVariety.value.id, payload)
+ toast.success('Variété modifiée')
+ } else {
+ await plantsStore.createVariety(detailPlantObj.value.id, payload)
+ toast.success('Variété ajoutée')
+ }
+ // Refresh plant data so detailPlantObj reflects updated varieties
+ await plantsStore.fetchAll()
+ const updatedPlant = plantsStore.plants.find(p => p.id === detailPlantObj.value?.id)
+ if (updatedPlant) detailPlantObj.value = updatedPlant
+ closeFormVariety()
+}
+
+async function deleteVariety(vid: number) {
+ if (!detailPlantObj.value?.id) return
+ if (!confirm('Supprimer cette variété ?')) return
+ await plantsStore.removeVariety(detailPlantObj.value.id, vid)
+ toast.success('Variété supprimée')
+}
+
async function submitPlant() {
if (submitting.value) return
submitting.value = true