Files
Ferme/frontend/pages/entry-exit/index.vue
2026-05-04 11:34:24 +02:00

266 lines
10 KiB
Vue

<template>
<div class="px-[86px]">
<div class="flex items-center justify-start gap-10 relative">
<Icon
@click="router.push('/')"
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">Entrée / Sortie</h1>
</div>
<div class="mt-8 grid grid-cols-2 gap-8">
<section>
<h2 class="text-xl font-bold uppercase text-primary-500 mb-4">Entrées en attente</h2>
<UiDataTable
v-model:page="entryPage"
v-model:per-page="entryPerPage"
:columns="entryColumns"
:items="entries"
:total-items="totalEntries"
:loading="entriesLoading"
row-clickable
@row-click="goToEntry"
>
<template #header-identificationNumber>
<UiTextInput
v-model="entryFilters.identificationNumber"
placeholder="Numéro"
size="compact"
/>
</template>
<template #header-receptionDate>
<UiDateMaskedInput v-model="entryDateFilter" placeholder="Date" size="compact" />
</template>
<template #header-declaredCount>
<UiTextInput :model-value="''" placeholder="Déclarés" size="compact" disabled />
</template>
<template #header-registeredBovineCount>
<UiTextInput :model-value="''" placeholder="Saisis" size="compact" disabled />
</template>
<template #header-status>
<UiTextInput :model-value="''" placeholder="Statut" size="compact" disabled />
</template>
<template #cell-identificationNumber="{ item }">
{{ item.identificationNumber }}
</template>
<template #cell-receptionDate="{ item }">
{{ formatDate(item.receptionDate) }}
</template>
<template #cell-declaredCount="{ item }">
{{ item.declaredBovineCount ?? 0 }}
</template>
<template #cell-registeredBovineCount="{ item }">
{{ item.registeredBovineCount ?? 0 }}
</template>
<template #cell-status="{ item }">
<span
v-if="!item.entryCompleted"
class="inline-block rounded px-2 py-0.5 text-xs font-semibold bg-yellow-100 text-yellow-700"
>
Attente saisie
</span>
<span
v-else
class="inline-block rounded px-2 py-0.5 text-xs font-semibold bg-orange-100 text-orange-700"
>
Attente EDNOTIF
</span>
</template>
</UiDataTable>
</section>
<section>
<h2 class="text-xl font-bold uppercase text-primary-500 mb-4">Entrées validées</h2>
<UiDataTable
v-model:page="validatedPage"
v-model:per-page="validatedPerPage"
:columns="validatedColumns"
:items="validated"
:total-items="totalValidated"
:loading="validatedLoading"
row-clickable
@row-click="goToBovineInfo"
>
<template #header-identificationNumber>
<UiTextInput
v-model="validatedFilters.identificationNumber"
placeholder="Numéro"
size="compact"
/>
</template>
<template #header-receptionDate>
<UiDateMaskedInput v-model="validatedDateFilter" placeholder="Date" size="compact" />
</template>
<template #header-registeredBovineCount>
<UiTextInput :model-value="''" placeholder="Saisis" size="compact" disabled />
</template>
<template #header-validatedAt>
<UiTextInput :model-value="''" placeholder="Validée le" size="compact" disabled />
</template>
<template #header-status>
<UiTextInput :model-value="''" placeholder="Statut" size="compact" disabled />
</template>
<template #cell-identificationNumber="{ item }">
{{ item.identificationNumber }}
</template>
<template #cell-receptionDate="{ item }">
{{ formatDate(item.receptionDate) }}
</template>
<template #cell-registeredBovineCount="{ item }">
{{ item.registeredBovineCount ?? 0 }}
</template>
<template #cell-validatedAt="{ item }">
{{ formatDate(item.validatedAt) }}
</template>
<template #cell-status>
<span
class="inline-block rounded px-2 py-0.5 text-xs font-semibold bg-green-100 text-green-700"
>
Validée
</span>
</template>
</UiDataTable>
</section>
</div>
<div class="mt-12 mb-16 grid grid-cols-2 gap-8">
<section>
<h2 class="text-xl font-bold uppercase text-primary-500 mb-4">Sorties en attente</h2>
<div class="rounded border border-dashed border-slate-300 p-8 text-center text-slate-500">
À venir
</div>
</section>
<section>
<h2 class="text-xl font-bold uppercase text-primary-500 mb-4">Sorties validées</h2>
<div class="rounded border border-dashed border-slate-300 p-8 text-center text-slate-500">
À venir
</div>
</section>
</div>
</div>
</template>
<script setup lang="ts">
import type { ReceptionData } from '~/services/dto/reception-data'
import { useDataTableServerState } from '~/composables/useDataTableServerState'
const router = useRouter()
const {
items: entries,
totalItems: totalEntries,
page: entryPage,
perPage: entryPerPage,
filters: entryFilters,
loading: entriesLoading,
reload
} = useDataTableServerState<ReceptionData>(
'receptions',
{
'isValid': 'true',
'exists[validatedAt]': 'false',
'receptionType.code': 'BOVINS',
'identificationNumber': '',
'receptionDate[after]': '',
'receptionDate[strictly_before]': ''
},
{ initialPerPage: 5 }
)
const {
items: validated,
totalItems: totalValidated,
page: validatedPage,
perPage: validatedPerPage,
filters: validatedFilters,
loading: validatedLoading,
reload: reloadValidated
} = useDataTableServerState<ReceptionData>(
'receptions',
{
'isValid': 'true',
'exists[validatedAt]': 'true',
'receptionType.code': 'BOVINS',
'identificationNumber': '',
'receptionDate[after]': '',
'receptionDate[strictly_before]': ''
},
{ initialPerPage: 5 }
)
const addOneDay = (dateString: string): string => {
const [year, month, day] = dateString.split('-').map(Number)
const next = new Date(Date.UTC(year, month - 1, day + 1))
return next.toISOString().slice(0, 10)
}
const entryDateFilter = computed<string>({
get: () => (entryFilters.value['receptionDate[after]'] as string) ?? '',
set: (value: string) => {
if (!value) {
entryFilters.value['receptionDate[after]'] = ''
entryFilters.value['receptionDate[strictly_before]'] = ''
return
}
entryFilters.value['receptionDate[after]'] = value
entryFilters.value['receptionDate[strictly_before]'] = addOneDay(value)
}
})
const validatedDateFilter = computed<string>({
get: () => (validatedFilters.value['receptionDate[after]'] as string) ?? '',
set: (value: string) => {
if (!value) {
validatedFilters.value['receptionDate[after]'] = ''
validatedFilters.value['receptionDate[strictly_before]'] = ''
return
}
validatedFilters.value['receptionDate[after]'] = value
validatedFilters.value['receptionDate[strictly_before]'] = addOneDay(value)
}
})
const entryColumns = [
{ key: 'identificationNumber', label: 'Numéro', width: '75px' },
{ key: 'receptionDate', label: 'Date', width: '75px' },
{ key: 'declaredCount', label: 'Déclarés', width: '75px' },
{ key: 'registeredBovineCount', label: 'Saisis', width: '70px' },
{ key: 'status', label: 'Statut', width: '1fr' }
]
const validatedColumns = [
{ key: 'identificationNumber', label: 'Numéro', width: '75px' },
{ key: 'receptionDate', label: 'Date', width: '75px' },
{ key: 'registeredBovineCount', label: 'Saisis', width: '50px' },
{ key: 'validatedAt', label: 'Validée le', width: '75px' },
{ key: 'status', label: 'Statut', width: '1fr' }
]
const formatDate = (date: string | null | undefined) => {
if (!date) return '—'
const d = new Date(date.replace(' ', 'T'))
if (isNaN(d.getTime())) return date
return d.toLocaleDateString('fr-FR', {
day: '2-digit',
month: '2-digit',
year: 'numeric'
})
}
const goToEntry = (reception: ReceptionData) => {
router.push(`/entry-exit/entry/${reception.id}`)
}
const goToBovineInfo = (reception: ReceptionData) => {
router.push(`/entry-exit/bovine-info/${reception.id}`)
}
onMounted(() => {
reload()
reloadValidated()
})
</script>