feat : modal d'export inventaire avec filtres par tranches d'âge

- UiModal : composant générique réutilisable (teleport, escape, backdrop, max-width configurable)
- InventoryExportModal : 3 checkboxes pour les tranches d'âge, footer centré sans annuler
- BovineRepository::findActiveForInventoryExport(?array $ageRanges) en DQL
- Endpoint inventory-export accepte ageRanges (comma-separated) en query param
- Aucune coche = export complet (comportement actuel intact)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-28 10:13:30 +02:00
parent 19a29f854e
commit 8eebb63626
5 changed files with 265 additions and 13 deletions

View File

@@ -17,7 +17,7 @@
class="bg-primary-500 p-1 rounded-md flex items-center cursor-pointer hover:opacity-80"
:class="exporting ? 'cursor-not-allowed opacity-60' : ''"
title="Exporter en Excel"
@click="exportInventory"
@click="showExportModal = true"
>
<Icon name="mdi:file-excel-outline" size="32" class="text-white" />
</div>
@@ -136,12 +136,19 @@
</template>
</UiDataTable>
</div>
<InventoryExportModal
v-model="showExportModal"
:loading="exporting"
@submit="exportInventory"
/>
</div>
</template>
<script setup lang="ts">
import type { BovineData } from '~/services/dto/bovine-data'
import type { InventoryExportFilters } from '~/components/inventory/inventory-export-modal.vue'
import { useAuthStore } from '~/stores/auth'
import { useDataTableServerState } from '~/composables/useDataTableServerState'
import { useBovineColumns } from '~/composables/useBovineColumns'
@@ -183,12 +190,17 @@ const loadStats = async () => {
const syncing = ref(false)
const exporting = ref(false)
const showExportModal = ref(false)
const exportInventory = async () => {
const exportInventory = async (filters: InventoryExportFilters) => {
if (exporting.value) return
exporting.value = true
try {
const blob = await api.getBlob('bovines/inventory-export')
const query: Record<string, unknown> = {}
if (filters.ageRanges.length > 0) {
query.ageRanges = filters.ageRanges.join(',')
}
const blob = await api.getBlob('bovines/inventory-export', query)
const filename = `inventaire_bovins_${new Date().toISOString().slice(0, 10)}.xlsx`
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
@@ -199,6 +211,7 @@ const exportInventory = async () => {
a.click()
a.remove()
setTimeout(() => URL.revokeObjectURL(url), 60_000)
showExportModal.value = false
} catch {
// toast déjà géré par useApi onResponseError
} finally {