feat(front) : page saisie information bovin (accordéons)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
128
frontend/pages/entry-exit/bovine-info/[id].vue
Normal file
128
frontend/pages/entry-exit/bovine-info/[id].vue
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
<template>
|
||||||
|
<div class="px-[86px]">
|
||||||
|
<div class="flex items-center justify-start gap-6 relative mb-8">
|
||||||
|
<Icon
|
||||||
|
@click="router.push('/entry-exit')"
|
||||||
|
name="gg:arrow-left-o"
|
||||||
|
size="44"
|
||||||
|
class="cursor-pointer text-primary-500 absolute -left-[60px]"
|
||||||
|
/>
|
||||||
|
<h1 class="font-bold text-3xl uppercase text-primary-500">
|
||||||
|
Saisie information bovin {{ reception?.identificationNumber ?? '' }}
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="loading" class="text-center text-slate-500">Chargement…</div>
|
||||||
|
|
||||||
|
<div v-else class="space-y-3">
|
||||||
|
<UiAccordion
|
||||||
|
v-for="bovine in sortedBovines"
|
||||||
|
:key="bovine.id"
|
||||||
|
:model-value="openId === bovine.id"
|
||||||
|
@update:model-value="onToggle(bovine.id, $event)"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<span class="flex items-center gap-3 normal-case">
|
||||||
|
<span class="font-bold text-base">{{ bovine.nationalNumber }}</span>
|
||||||
|
<span
|
||||||
|
v-if="isSaisi(bovine)"
|
||||||
|
class="inline-block rounded px-2 py-0.5 text-xs font-semibold bg-green-100 text-green-700"
|
||||||
|
>
|
||||||
|
Saisie
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
v-else
|
||||||
|
class="inline-block rounded px-2 py-0.5 text-xs font-semibold bg-yellow-100 text-yellow-700"
|
||||||
|
>
|
||||||
|
Attente saisie
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<BovineInfoForm
|
||||||
|
:bovine="bovine"
|
||||||
|
:buildings="buildings"
|
||||||
|
@saved="onSaved"
|
||||||
|
/>
|
||||||
|
</UiAccordion>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { BovineData } from '~/services/dto/bovine-data'
|
||||||
|
import type { BuildingData } from '~/services/dto/building-data'
|
||||||
|
import type { ReceptionData } from '~/services/dto/reception-data'
|
||||||
|
import { getBuildingList } from '~/services/building'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const receptionId = computed(() => Number(route.params.id))
|
||||||
|
|
||||||
|
const reception = ref<ReceptionData | null>(null)
|
||||||
|
const bovines = ref<BovineData[]>([])
|
||||||
|
const buildings = ref<BuildingData[]>([])
|
||||||
|
const loading = ref(true)
|
||||||
|
const openId = ref<number | null>(null)
|
||||||
|
|
||||||
|
useHead({
|
||||||
|
title: () => `Saisie information bovin ${reception.value?.identificationNumber ?? ''}`.trim()
|
||||||
|
})
|
||||||
|
|
||||||
|
const isSaisi = (bovine: BovineData) =>
|
||||||
|
bovine.receivedWeight !== null
|
||||||
|
&& bovine.pricePerKg !== null
|
||||||
|
&& bovine.buildingCase !== null
|
||||||
|
|
||||||
|
const sortedBovines = computed(() => {
|
||||||
|
const pending = bovines.value.filter(b => !isSaisi(b))
|
||||||
|
const done = bovines.value.filter(b => isSaisi(b))
|
||||||
|
return [...pending, ...done]
|
||||||
|
})
|
||||||
|
|
||||||
|
const onToggle = (bovineId: number, value: boolean) => {
|
||||||
|
openId.value = value ? bovineId : null
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSaved = (updated: BovineData) => {
|
||||||
|
const idx = bovines.value.findIndex(b => b.id === updated.id)
|
||||||
|
if (idx === -1) return
|
||||||
|
bovines.value[idx] = updated
|
||||||
|
|
||||||
|
const next = sortedBovines.value.find(b => !isSaisi(b) && b.id !== updated.id)
|
||||||
|
openId.value = next?.id ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadBovines = async () => {
|
||||||
|
type Hydra = { 'hydra:member'?: BovineData[] }
|
||||||
|
const response = await api.get<BovineData[] | Hydra>(
|
||||||
|
'bovines',
|
||||||
|
{ reception: receptionId.value, itemsPerPage: 200 }
|
||||||
|
)
|
||||||
|
if (Array.isArray(response)) {
|
||||||
|
bovines.value = response
|
||||||
|
} else if (response && typeof response === 'object' && Array.isArray(response['hydra:member'])) {
|
||||||
|
bovines.value = response['hydra:member']
|
||||||
|
} else {
|
||||||
|
bovines.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
try {
|
||||||
|
const [r, , b] = await Promise.all([
|
||||||
|
api.get<ReceptionData>(`receptions/${receptionId.value}`),
|
||||||
|
loadBovines(),
|
||||||
|
getBuildingList()
|
||||||
|
])
|
||||||
|
reception.value = r
|
||||||
|
buildings.value = b
|
||||||
|
|
||||||
|
const firstPending = sortedBovines.value.find(bv => !isSaisi(bv))
|
||||||
|
openId.value = firstPending?.id ?? null
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
Reference in New Issue
Block a user