197 lines
7.4 KiB
Vue
197 lines
7.4 KiB
Vue
<script setup>
|
|
import DataTable from '@/Components/Supervisor/DataTable.vue';
|
|
import Pagination from '@/Components/Supervisor/Pagination.vue';
|
|
import StatusBadge from '@/Components/Supervisor/StatusBadge.vue';
|
|
import TableHeaderCell from '@/Components/Supervisor/TableHeaderCell.vue';
|
|
import { useListFilters } from '@/Components/Supervisor/useListFilters.js';
|
|
import {
|
|
filterInputClass,
|
|
filterSelectClass,
|
|
getStatusColor,
|
|
linkClass,
|
|
rowClass,
|
|
tdClass,
|
|
washStatusColors,
|
|
} from '@/Components/Supervisor/ui.js';
|
|
import SupervisorLayout from '@/Layouts/SupervisorLayout.vue';
|
|
import { Head, Link } from '@inertiajs/vue3';
|
|
import { computed } from 'vue';
|
|
|
|
const props = defineProps({
|
|
washes: {
|
|
type: Object,
|
|
required: true,
|
|
},
|
|
establishments: {
|
|
type: Array,
|
|
default: () => [],
|
|
},
|
|
filters: {
|
|
type: Object,
|
|
default: () => ({}),
|
|
},
|
|
statusOptions: {
|
|
type: Object,
|
|
default: () => ({}),
|
|
},
|
|
});
|
|
|
|
const { localFilters, toggleSort } = useListFilters('supervisor.washes.index', {
|
|
establishment_id: props.filters.establishment_id ?? '',
|
|
user: props.filters.user ?? '',
|
|
status: props.filters.status ?? '',
|
|
date: props.filters.date ?? '',
|
|
sort: props.filters.sort ?? 'started_at',
|
|
direction: props.filters.direction ?? 'desc',
|
|
per_page: props.filters.per_page ?? 10,
|
|
}, { debounceKeys: ['user'] });
|
|
|
|
const showEstablishmentFilter = computed(() => props.establishments.length > 1);
|
|
|
|
const handleSort = (key) => toggleSort(key, ['started_at', 'duration_minutes', 'cost']);
|
|
|
|
const formatDate = (iso) => {
|
|
if (!iso) return '—';
|
|
return new Intl.DateTimeFormat('fr-FR', {
|
|
dateStyle: 'short',
|
|
timeStyle: 'short',
|
|
}).format(new Date(iso));
|
|
};
|
|
|
|
const formatCurrency = (value) =>
|
|
new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR' }).format(value ?? 0);
|
|
</script>
|
|
|
|
<template>
|
|
<Head title="Lavages" />
|
|
|
|
<SupervisorLayout title="Lavages">
|
|
<DataTable>
|
|
<template #head>
|
|
<tr>
|
|
<TableHeaderCell
|
|
label="Début"
|
|
sortable
|
|
sort-key="started_at"
|
|
:active-sort="localFilters.sort"
|
|
:sort-direction="localFilters.direction"
|
|
@sort="handleSort"
|
|
>
|
|
<input v-model="localFilters.date" type="date" :class="filterInputClass" />
|
|
</TableHeaderCell>
|
|
<TableHeaderCell
|
|
label="Utilisateur"
|
|
sortable
|
|
sort-key="user"
|
|
:active-sort="localFilters.sort"
|
|
:sort-direction="localFilters.direction"
|
|
@sort="handleSort"
|
|
>
|
|
<input
|
|
v-model="localFilters.user"
|
|
type="text"
|
|
placeholder="Nom ou e-mail…"
|
|
:class="filterInputClass"
|
|
/>
|
|
</TableHeaderCell>
|
|
<TableHeaderCell
|
|
label="Machine"
|
|
sortable
|
|
sort-key="machine"
|
|
:active-sort="localFilters.sort"
|
|
:sort-direction="localFilters.direction"
|
|
@sort="handleSort"
|
|
>
|
|
<select
|
|
v-if="showEstablishmentFilter"
|
|
v-model="localFilters.establishment_id"
|
|
:class="filterSelectClass"
|
|
>
|
|
<option value="">Toutes</option>
|
|
<option v-for="est in establishments" :key="est.id" :value="est.id">
|
|
{{ est.name }}
|
|
</option>
|
|
</select>
|
|
</TableHeaderCell>
|
|
<TableHeaderCell
|
|
label="Statut"
|
|
sortable
|
|
sort-key="status"
|
|
:active-sort="localFilters.sort"
|
|
:sort-direction="localFilters.direction"
|
|
@sort="handleSort"
|
|
>
|
|
<select v-model="localFilters.status" :class="filterSelectClass">
|
|
<option value="">Tous</option>
|
|
<option v-for="(label, value) in statusOptions" :key="value" :value="value">
|
|
{{ label }}
|
|
</option>
|
|
</select>
|
|
</TableHeaderCell>
|
|
<TableHeaderCell
|
|
label="Durée"
|
|
sortable
|
|
sort-key="duration_minutes"
|
|
:active-sort="localFilters.sort"
|
|
:sort-direction="localFilters.direction"
|
|
@sort="handleSort"
|
|
/>
|
|
<TableHeaderCell
|
|
label="Coût"
|
|
sortable
|
|
sort-key="cost"
|
|
:active-sort="localFilters.sort"
|
|
:sort-direction="localFilters.direction"
|
|
@sort="handleSort"
|
|
/>
|
|
</tr>
|
|
</template>
|
|
|
|
<tr v-if="washes.data.length === 0">
|
|
<td colspan="6" class="px-6 py-12 text-center text-sm text-slate-400">
|
|
Aucun lavage trouvé.
|
|
</td>
|
|
</tr>
|
|
<tr v-for="wash in washes.data" :key="wash.uuid" :class="rowClass">
|
|
<td :class="[tdClass, 'font-medium text-slate-800']">
|
|
{{ formatDate(wash.started_at) }}
|
|
</td>
|
|
<td :class="tdClass">
|
|
<div class="font-medium text-slate-800">{{ wash.user?.name ?? '—' }}</div>
|
|
<div class="text-xs text-slate-400">{{ wash.user?.email }}</div>
|
|
</td>
|
|
<td :class="tdClass">
|
|
<Link
|
|
v-if="wash.machine"
|
|
:href="route('supervisor.machines.show', wash.machine.uuid)"
|
|
:class="linkClass"
|
|
>
|
|
{{ wash.machine.name }}
|
|
</Link>
|
|
<span v-else>—</span>
|
|
</td>
|
|
<td :class="tdClass">
|
|
<StatusBadge
|
|
:label="wash.status_label"
|
|
:color-class="getStatusColor(wash.status, washStatusColors)"
|
|
/>
|
|
</td>
|
|
<td :class="tdClass">
|
|
{{ wash.duration_minutes ? `${wash.duration_minutes} min` : '—' }}
|
|
</td>
|
|
<td :class="[tdClass, 'font-semibold text-slate-800']">
|
|
{{ formatCurrency(wash.cost) }}
|
|
</td>
|
|
</tr>
|
|
|
|
<template #footer>
|
|
<Pagination
|
|
:paginator="washes"
|
|
:per-page="localFilters.per_page"
|
|
@update:per-page="(value) => { localFilters.per_page = value; }"
|
|
/>
|
|
</template>
|
|
</DataTable>
|
|
</SupervisorLayout>
|
|
</template>
|