From 74de31721c6b149d2c6ca805cef8d30e403a927b Mon Sep 17 00:00:00 2001 From: kevin Date: Tue, 17 Feb 2026 14:52:23 +0100 Subject: [PATCH] feat : creation du composant datatable (WIP) --- frontend/components/ui/UiDataTable.vue | 203 ++++++++++-------- frontend/pages/admin/carrier/carrier-list.vue | 60 +++--- frontend/pages/admin/customer/[[id]].vue | 80 ++----- .../pages/admin/customer/customer-list.vue | 100 ++------- frontend/pages/admin/supplier/[[id]].vue | 80 ++----- .../pages/admin/supplier/supplier-list.vue | 95 ++------ frontend/pages/admin/user/list.vue | 56 ++--- frontend/pages/datatable.vue | 19 -- frontend/pages/reception/finish-reception.vue | 13 +- .../pages/reception/waiting-reception.vue | 59 ++--- frontend/pages/shipment/finish-shipment.vue | 4 +- frontend/pages/shipment/waiting-shipment.vue | 79 ++----- frontend/services/datatable.ts | 18 ++ frontend/utils/datatable-formatters.ts | 54 +++-- src/Entity/Reception.php | 2 + 15 files changed, 355 insertions(+), 567 deletions(-) delete mode 100644 frontend/pages/datatable.vue create mode 100644 frontend/services/datatable.ts diff --git a/frontend/components/ui/UiDataTable.vue b/frontend/components/ui/UiDataTable.vue index 467228b..85d41f9 100644 --- a/frontend/components/ui/UiDataTable.vue +++ b/frontend/components/ui/UiDataTable.vue @@ -1,7 +1,7 @@ @@ -78,6 +48,7 @@ import {computed, reactive, ref, watch} from "vue" import {createCustomer, getCustomer, updateCustomer} from "~/services/customer" import type {CustomerData, CustomerFormData, CustomerPayload} from "~/services/dto/customer-data" +import type {ColumnConfig, Row} from "~/services/datatable" import {useAuthStore} from "~/stores/auth" definePageMeta({layout: "default"}) @@ -100,6 +71,14 @@ const form = reactive({ email: "", addresses: [], }) +const addressColumns: ColumnConfig[] = [ + {key: "label", label: "Libellé"}, + {key: "street", label: "Rue"}, + {key: "street2", label: "Complément"}, + {key: "postalCode", label: "Code postal"}, + {key: "city", label: "Ville"}, + {key: "countryCode", label: "Pays"}, +] const goToAddAddress = () => { if (customerId.value === null || !auth.isAdmin) return @@ -122,29 +101,16 @@ const goToEditAddress = (addressId: number | null) => { }) } +const onAddressRowClick = (row: Row) => { + const id = Number(row.id) + goToEditAddress(Number.isFinite(id) ? id : null) +} + const hydrateFromCustomer = (customer: CustomerData | null) => { if (!customer) return form.name = customer.name ?? "" form.phone = customer.phone ?? "" form.email = customer.email ?? "" - if (!Array.isArray(customer.addresses) || customer.addresses.length === 0) { - form.addresses = [] - return - } - if (typeof customer.addresses[0] === "string") { - form.addresses = [] - return - } - - form.addresses = customer.addresses.map((address) => ({ - id: address.id ?? null, - label: address.label ?? "", - street: address.street ?? "", - street2: address.street2 ?? null, - postalCode: address.postalCode ?? "", - city: address.city ?? "", - countryCode: address.countryCode ?? "", - })) } watch( diff --git a/frontend/pages/admin/customer/customer-list.vue b/frontend/pages/admin/customer/customer-list.vue index cdd5eb1..660ee5d 100644 --- a/frontend/pages/admin/customer/customer-list.vue +++ b/frontend/pages/admin/customer/customer-list.vue @@ -12,106 +12,48 @@ -
-
-
-
Nom
-
Téléphone
-
Email
-
Rue
-
Complément
-
Code Postal
-
Ville
-
Pays
-
- -
- Aucun client. -
- -
-
-
{{ customer.name || "—" }}
-
{{ customer.phone || "—" }}
-
{{ customer.email || "—" }}
-
Pas d'adresse
-
{{"—"}}
-
{{"—"}}
-
{{"—"}}
-
{{"—"}}
-
- - - - -
-
-
+
Accès réservé aux administrateurs.
diff --git a/frontend/pages/admin/supplier/[[id]].vue b/frontend/pages/admin/supplier/[[id]].vue index 264be7b..dba878d 100644 --- a/frontend/pages/admin/supplier/[[id]].vue +++ b/frontend/pages/admin/supplier/[[id]].vue @@ -32,45 +32,15 @@ Ajouter -
- - - - - - - - - - - - - - - -
LibelléRueComplémentCode postalVillePays
-
+ @@ -78,6 +48,7 @@ import {computed, reactive, ref, watch} from "vue" import {createSupplier, getSupplier, updateSupplier} from "~/services/supplier" import type {SupplierData, SupplierFormData, SupplierPayload} from "~/services/dto/supplier-data" +import type {ColumnConfig, Row} from "~/services/datatable" import {useAuthStore} from "~/stores/auth" definePageMeta({layout: "default"}) @@ -100,6 +71,14 @@ const form = reactive({ phone: "", addresses: [], }) +const addressColumns: ColumnConfig[] = [ + {key: "label", label: "Libellé"}, + {key: "street", label: "Rue"}, + {key: "street2", label: "Complément"}, + {key: "postalCode", label: "Code postal"}, + {key: "city", label: "Ville"}, + {key: "countryCode", label: "Pays"}, +] const goToAddAddress = () => { if (supplierId.value === null || !auth.isAdmin) return @@ -124,29 +103,16 @@ const goToEditAddress = (addressId: number | null) => { }) } +const onAddressRowClick = (row: Row) => { + const id = Number(row.id) + goToEditAddress(Number.isFinite(id) ? id : null) +} + const hydrateFromSupplier = (supplier: SupplierData | null) => { if (!supplier) return form.name = supplier.name ?? "" form.email = supplier.email ?? "" form.phone = supplier.phone ?? "" - if (!Array.isArray(supplier.addresses) || supplier.addresses.length === 0) { - form.addresses = [] - return - } - if (typeof supplier.addresses[0] === "string") { - form.addresses = [] - return - } - - form.addresses = supplier.addresses.map((address) => ({ - id: address.id ?? null, - label: address.label ?? "", - street: address.street ?? "", - street2: address.street2 ?? null, - postalCode: address.postalCode ?? "", - city: address.city ?? "", - countryCode: address.countryCode ?? "", - })) } watch( diff --git a/frontend/pages/admin/supplier/supplier-list.vue b/frontend/pages/admin/supplier/supplier-list.vue index 2008cb3..c4a7710 100644 --- a/frontend/pages/admin/supplier/supplier-list.vue +++ b/frontend/pages/admin/supplier/supplier-list.vue @@ -12,102 +12,47 @@ -
-
-
-
Nom
-
Mail
-
Rue
-
Complément
-
Code Postal
-
Ville
-
Pays
-
- -
- Aucun fournisseur. -
- -
-
-
{{ supplier.name }}
-
{{ supplier.email }}
-
Pas d'adresse
-
{{"—"}}
-
{{"—"}}
-
{{"—"}}
-
{{"—"}}
-
- - - - -
-
-
+
Accès réservé aux administrateurs.
diff --git a/frontend/pages/admin/user/list.vue b/frontend/pages/admin/user/list.vue index 71714ca..655befe 100644 --- a/frontend/pages/admin/user/list.vue +++ b/frontend/pages/admin/user/list.vue @@ -11,29 +11,11 @@ -
-
-
-
Username
-
Role
-
-
-
- {{ user.username }} -
-
- {{ getRoleLabels(user.roles) }} -
-
-
-
+ @@ -42,29 +24,21 @@ definePageMeta({ layout: 'default' }) -import type {UserData} from "~/services/dto/user-data"; -import {getAdminUsers} from "~/services/auth"; import {ROLE} from "~/utils/constants"; +import type {ColumnConfig, Row} from "~/services/datatable"; +import {formatRoleLabels} from "~/utils/datatable-formatters"; -const userList = ref([]) const router = useRouter() const roleLabelByValue = new Map(ROLE.map((role) => [role.value, role.label])) -const goToUser = (id: number) => { +const columns: ColumnConfig[] = [ + { key: "username", label: "Username" }, + { key: "roles", label: "Role", format: (value) => formatRoleLabels(value, roleLabelByValue) }, +] + +const onUserRowClick = (row: Row) => { + const id = Number(row.id) + if (!Number.isFinite(id)) return router.push(`/admin/user/${id}`) } - -const getRoleLabels = (roles?: string[]) => { - if (!roles || roles.length === 0) { - return ' ---' - } - - return roles - .map((role) => roleLabelByValue.get(role) ?? role) - .join(', ') -} - -onMounted(async () => { - userList.value = await getAdminUsers() -}) diff --git a/frontend/pages/datatable.vue b/frontend/pages/datatable.vue deleted file mode 100644 index 402cc73..0000000 --- a/frontend/pages/datatable.vue +++ /dev/null @@ -1,19 +0,0 @@ - - - - diff --git a/frontend/pages/reception/finish-reception.vue b/frontend/pages/reception/finish-reception.vue index 9432652..5812508 100644 --- a/frontend/pages/reception/finish-reception.vue +++ b/frontend/pages/reception/finish-reception.vue @@ -14,6 +14,12 @@ diff --git a/frontend/pages/reception/waiting-reception.vue b/frontend/pages/reception/waiting-reception.vue index b6db72c..79ff634 100644 --- a/frontend/pages/reception/waiting-reception.vue +++ b/frontend/pages/reception/waiting-reception.vue @@ -5,47 +5,34 @@

listes des réceptions en attente

- -
-
-
-
Fournisseur
-
Adresse
-
Type réception
-
Transporteur
-
Immatriculation
-
-
-
{{ reception.supplier?.name }}
-
{{ reception.address?.fullAddress }}
-
{{ reception.receptionType?.label }}
-
{{ reception.carrier?.name }}
-
{{ reception.licensePlate }}
-
-
-
+ diff --git a/frontend/pages/shipment/finish-shipment.vue b/frontend/pages/shipment/finish-shipment.vue index 817b80a..c49d1a7 100644 --- a/frontend/pages/shipment/finish-shipment.vue +++ b/frontend/pages/shipment/finish-shipment.vue @@ -13,10 +13,8 @@ diff --git a/frontend/services/datatable.ts b/frontend/services/datatable.ts new file mode 100644 index 0000000..35e2c6f --- /dev/null +++ b/frontend/services/datatable.ts @@ -0,0 +1,18 @@ +export type Row = Record + +export type ColumnConfig = { + key: string + label?: string + format?: (value: unknown, row: Row) => string +} +type HydraCollection = { + 'hydra:member': T[] + 'hydra:totalItems': number +} +export type AnyCollection = HydraCollection & { + member?: T[] + items?: T[] + totalItems?: number +} + +export type PaginationItem = number | '...' diff --git a/frontend/utils/datatable-formatters.ts b/frontend/utils/datatable-formatters.ts index 860e22a..8483ffa 100644 --- a/frontend/utils/datatable-formatters.ts +++ b/frontend/utils/datatable-formatters.ts @@ -4,7 +4,7 @@ export const formatBovinShipments = (value: unknown): string => { const label = item?.shipmentType?.label ?? item?.shipmentType?.code ?? 'Type inconnu' const qty = item?.nbBovinSend ?? '-' - return `${label} (${qty})` + return `${label} : ${qty}` }).join(', ') } @@ -13,29 +13,53 @@ export const formatWeights = (value: unknown): string => { return value .map((item: any) => { - const type = item?.type === 'tare' - ? 'Poids à vide' - : item?.type === 'gross' - ? 'Poids à plein' - : (item?.type ?? 'Poids') - + const type = item?.type === 'tare' ? 'Poids à vide': item?.type === 'gross' ? 'Poids à plein': (item?.type ?? 'Poids') const weight = item?.weight ?? '-' return `${type}: ${weight}` }) + .join('\n ') +} + +export const formatRoleLabels = ( + value: unknown, + roleLabelByValue: Map, +): string => { + if (!Array.isArray(value) || value.length === 0) { + return ' - ' + } + + return value + .map((role) => { + const key = String(role) + return roleLabelByValue.get(key) ?? key + }) .join(', ') } -export const formatPelletBuildings = (value: unknown): string => { - if (!Array.isArray(value) || value.length === 0) return '-' +export const formatAddresses = (value: unknown): string => { + if (!Array.isArray(value) || value.length === 0) { + return " - " + } + + if (typeof value[0] === 'string') { + return 'Adresses non chargées' + } return value - .map((item: any) => { - const pelletLabel = - item?.pelletType?.label ?? item?.pelletType?.code ?? 'Granule inconnu' - const buildingLabel = - item?.building?.label ?? item?.building?.code ?? 'Bâtiment inconnu' + .map((item) => { + if (!item || typeof item !== 'object') return '-' + const address = item as Record + const street = String(address.street ?? '').trim() + const street2 = String(address.street2 ?? '').trim() + const postalCode = String(address.postalCode ?? '').trim() + const city = String(address.city ?? '').trim() + const countryCode = String(address.countryCode ?? '').trim().toUpperCase() - return `${pelletLabel} : ${buildingLabel}` + const firstLine = [street, street2].filter(Boolean).join(', ') + const secondLine = [postalCode, city].filter(Boolean).join(' ') + const finalLine = [firstLine, secondLine, countryCode].filter(Boolean).join(', ') + + return finalLine || '-' }) .join('\n') } diff --git a/src/Entity/Reception.php b/src/Entity/Reception.php index 66305a0..0c3cee3 100644 --- a/src/Entity/Reception.php +++ b/src/Entity/Reception.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace App\Entity; use ApiPlatform\Doctrine\Orm\Filter\BooleanFilter; +use ApiPlatform\Doctrine\Orm\Filter\SearchFilter; use ApiPlatform\Metadata\ApiFilter; use ApiPlatform\Metadata\ApiProperty; use ApiPlatform\Metadata\ApiResource; @@ -29,6 +30,7 @@ use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; #[ORM\HasLifecycleCallbacks] #[ORM\Table(name: 'reception')] #[ApiFilter(BooleanFilter::class, properties: ['isValid'])] +#[ApiFilter(SearchFilter::class, properties: ['licensePlate' => 'exact'])] #[ApiResource( operations: [ new Get(