pagiantion defunt liste
This commit is contained in:
parent
67b15ab337
commit
9951ed0ee6
@ -20,18 +20,30 @@ class InterventionSeeder extends Seeder
|
|||||||
$products = Product::query()
|
$products = Product::query()
|
||||||
->whereHas('category', fn ($query) => $query->where('intervention', true))
|
->whereHas('category', fn ($query) => $query->where('intervention', true))
|
||||||
->get();
|
->get();
|
||||||
$deceasedCollection = Deceased::query()->get();
|
|
||||||
$practitioners = Thanatopractitioner::query()->get();
|
$practitioners = Thanatopractitioner::query()->get();
|
||||||
$clients = Client::query()->limit(12)->get();
|
$clients = Client::query()->limit(12)->get();
|
||||||
$creatorId = User::query()->value('id');
|
$creatorId = User::query()->value('id');
|
||||||
$types = ['thanatopraxie', 'toilette_mortuaire', 'exhumation', 'retrait_pacemaker', 'retrait_bijoux', 'autre'];
|
$types = ['thanatopraxie', 'toilette_mortuaire', 'exhumation', 'retrait_pacemaker', 'retrait_bijoux', 'autre'];
|
||||||
$statuses = ['demande', 'planifie', 'en_cours', 'termine', 'annule'];
|
$statuses = ['demande', 'planifie', 'en_cours', 'termine', 'annule'];
|
||||||
|
|
||||||
if ($products->isEmpty() || $deceasedCollection->isEmpty() || $clients->isEmpty()) {
|
if ($products->isEmpty() || $clients->isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($clients as $index => $client) {
|
foreach ($clients as $index => $client) {
|
||||||
|
$deceased = Deceased::updateOrCreate(
|
||||||
|
[
|
||||||
|
'last_name' => sprintf('Défunt Client %d', $client->id),
|
||||||
|
'first_name' => 'Dossier',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'birth_date' => now()->subYears(55 + $index)->subDays($index)->format('Y-m-d'),
|
||||||
|
'death_date' => now()->subDays($index + 1)->format('Y-m-d'),
|
||||||
|
'place_of_death' => $client->billing_city ?: 'Antananarivo',
|
||||||
|
'notes' => sprintf('Défunt de démonstration lié au client #%d pour les interventions seedées.', $client->id),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
$location = ClientLocation::updateOrCreate(
|
$location = ClientLocation::updateOrCreate(
|
||||||
[
|
[
|
||||||
'client_id' => $client->id,
|
'client_id' => $client->id,
|
||||||
@ -54,7 +66,7 @@ class InterventionSeeder extends Seeder
|
|||||||
'type' => $types[$index % count($types)],
|
'type' => $types[$index % count($types)],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'deceased_id' => optional($deceasedCollection->get($index % $deceasedCollection->count()))->id,
|
'deceased_id' => $deceased->id,
|
||||||
'order_giver' => $faker->name,
|
'order_giver' => $faker->name,
|
||||||
'location_id' => $location->id,
|
'location_id' => $location->id,
|
||||||
'product_id' => optional($products->get($index % $products->count()))->id,
|
'product_id' => optional($products->get($index % $products->count()))->id,
|
||||||
|
|||||||
@ -4,13 +4,58 @@
|
|||||||
<add-button text="Ajouter" @click="add" />
|
<add-button text="Ajouter" @click="add" />
|
||||||
</template>
|
</template>
|
||||||
<template #select-filter>
|
<template #select-filter>
|
||||||
|
<div class="defunt-toolbar-controls">
|
||||||
<filter-table />
|
<filter-table />
|
||||||
|
<div class="defunt-search-box ms-2">
|
||||||
|
<soft-input
|
||||||
|
id="deceased-list-search"
|
||||||
|
:model-value="search"
|
||||||
|
placeholder="Rechercher par nom du défunt"
|
||||||
|
icon="fas fa-search"
|
||||||
|
icon-dir="left"
|
||||||
|
@update:model-value="emit('search-change', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #defunt-other-action>
|
<template #defunt-other-action>
|
||||||
<table-action />
|
<table-action />
|
||||||
</template>
|
</template>
|
||||||
|
<template #header-pagination>
|
||||||
|
<div
|
||||||
|
v-if="pagination && pagination.last_page > 1"
|
||||||
|
class="d-flex justify-content-center"
|
||||||
|
>
|
||||||
|
<soft-pagination color="success" size="sm">
|
||||||
|
<soft-pagination-item
|
||||||
|
prev
|
||||||
|
:disabled="pagination.current_page <= 1"
|
||||||
|
@click="changePage(pagination.current_page - 1)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<soft-pagination-item
|
||||||
|
v-for="page in visiblePages"
|
||||||
|
:key="page"
|
||||||
|
:label="page.toString()"
|
||||||
|
:active="pagination.current_page === page"
|
||||||
|
@click="changePage(page)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<soft-pagination-item
|
||||||
|
next
|
||||||
|
:disabled="pagination.current_page >= pagination.last_page"
|
||||||
|
@click="changePage(pagination.current_page + 1)"
|
||||||
|
/>
|
||||||
|
</soft-pagination>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<template #defunt-table>
|
<template #defunt-table>
|
||||||
<defunts-list :defunts="defunts" />
|
<defunts-list
|
||||||
|
:defunts="defunts"
|
||||||
|
:loading="loading"
|
||||||
|
:pagination="pagination"
|
||||||
|
@page-change="emit('page-change', $event)"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</defunts-template>
|
</defunts-template>
|
||||||
</template>
|
</template>
|
||||||
@ -20,19 +65,110 @@ import addButton from "@/components/molecules/new-button/addButton.vue";
|
|||||||
import FilterTable from "@/components/molecules/Tables/FilterTable.vue";
|
import FilterTable from "@/components/molecules/Tables/FilterTable.vue";
|
||||||
import TableAction from "@/components/molecules/Tables/TableAction.vue";
|
import TableAction from "@/components/molecules/Tables/TableAction.vue";
|
||||||
import DefuntsList from "@/components/molecules/Defunts/DefuntsList.vue";
|
import DefuntsList from "@/components/molecules/Defunts/DefuntsList.vue";
|
||||||
import { defineProps } from "vue";
|
import SoftInput from "@/components/SoftInput.vue";
|
||||||
|
import SoftPagination from "@/components/SoftPagination.vue";
|
||||||
|
import SoftPaginationItem from "@/components/SoftPaginationItem.vue";
|
||||||
|
import { computed, defineEmits, defineProps } from "vue";
|
||||||
|
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
defineProps({
|
const emit = defineEmits(["page-change", "search-change"]);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
defunts: {
|
defunts: {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
pagination: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({
|
||||||
|
current_page: 1,
|
||||||
|
last_page: 1,
|
||||||
|
per_page: 10,
|
||||||
|
total: 0,
|
||||||
|
from: 0,
|
||||||
|
to: 0,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
search: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const add = () => {
|
const add = () => {
|
||||||
router.push({ name: "Add Defunts" });
|
router.push({ name: "Add Defunts" });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const changePage = (page) => {
|
||||||
|
if (typeof page !== "number") return;
|
||||||
|
if (page < 1 || page > (props.pagination?.last_page || 1)) return;
|
||||||
|
if (page === props.pagination?.current_page) return;
|
||||||
|
emit("page-change", page);
|
||||||
|
};
|
||||||
|
|
||||||
|
const visiblePages = computed(() => {
|
||||||
|
if (!props.pagination) return [];
|
||||||
|
|
||||||
|
const currentPage = props.pagination.current_page || 1;
|
||||||
|
const lastPage = props.pagination.last_page || 1;
|
||||||
|
|
||||||
|
if (lastPage <= 7) {
|
||||||
|
return Array.from({ length: lastPage }, (_, index) => index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const pages = [1];
|
||||||
|
let start = Math.max(2, currentPage - 1);
|
||||||
|
let end = Math.min(lastPage - 1, currentPage + 1);
|
||||||
|
|
||||||
|
if (currentPage < 4) {
|
||||||
|
start = 2;
|
||||||
|
end = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentPage > lastPage - 3) {
|
||||||
|
start = lastPage - 3;
|
||||||
|
end = lastPage - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let page = start; page <= end; page++) {
|
||||||
|
pages.push(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pages.includes(lastPage)) {
|
||||||
|
pages.push(lastPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...new Set(pages)].filter(
|
||||||
|
(page) => typeof page === "number" && page >= 1 && page <= lastPage
|
||||||
|
);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.defunt-toolbar-controls {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.defunt-search-box {
|
||||||
|
min-width: 280px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 991.98px) {
|
||||||
|
.defunt-toolbar-controls {
|
||||||
|
width: 100%;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.defunt-search-box {
|
||||||
|
min-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,6 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="row">
|
<div>
|
||||||
<div v-if="!defunts || defunts.length === 0" class="empty-state">
|
<div v-if="loading" class="text-center py-5">
|
||||||
|
<div class="spinner-border text-primary" role="status">
|
||||||
|
<span class="visually-hidden">Chargement...</span>
|
||||||
|
</div>
|
||||||
|
<p class="mt-2 mb-0">Chargement des défunts...</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else-if="!defunts || defunts.length === 0" class="empty-state">
|
||||||
<div class="empty-message">
|
<div class="empty-message">
|
||||||
<i class="fas fa-inbox"></i>
|
<i class="fas fa-inbox"></i>
|
||||||
<h3>Aucun défunt trouvé</h3>
|
<h3>Aucun défunt trouvé</h3>
|
||||||
@ -10,6 +17,9 @@
|
|||||||
</soft-button>
|
</soft-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<template v-else>
|
||||||
|
<div class="row">
|
||||||
<div
|
<div
|
||||||
v-for="(defunt, index) in defunts"
|
v-for="(defunt, index) in defunts"
|
||||||
:key="index"
|
:key="index"
|
||||||
@ -28,6 +38,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="(pagination?.last_page || 1) > 1"
|
||||||
|
class="d-flex justify-content-end align-items-center mt-3 px-1 flex-wrap gap-3"
|
||||||
|
>
|
||||||
|
<div class="text-xs text-secondary font-weight-bold">
|
||||||
|
Affichage de {{ safeFrom }} à {{ safeTo }} sur
|
||||||
|
{{ pagination.total || defunts.length }} défunts
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Intervention Add Modal -->
|
<!-- Intervention Add Modal -->
|
||||||
<div v-if="showModal" class="modal-overlay" @click="closeInterventionModal">
|
<div v-if="showModal" class="modal-overlay" @click="closeInterventionModal">
|
||||||
<div class="modal-container" @click.stop>
|
<div class="modal-container" @click.stop>
|
||||||
@ -81,8 +103,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import DefuntCard from "@/components/atoms/Defunts/DefuntCard.vue";
|
import DefuntCard from "@/components/atoms/Defunts/DefuntCard.vue";
|
||||||
import { ref } from "vue";
|
import { computed, defineProps, onMounted, ref } from "vue";
|
||||||
import { defineProps } from "vue";
|
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import SoftButton from "@/components/SoftButton.vue";
|
import SoftButton from "@/components/SoftButton.vue";
|
||||||
import InterventationAddModal from "@/components/molecules/Interventions/InterventationAddModal.vue";
|
import InterventationAddModal from "@/components/molecules/Interventions/InterventationAddModal.vue";
|
||||||
@ -90,7 +111,6 @@ import { useInterventionStore } from "@/stores/interventionStore";
|
|||||||
import { useDeceasedStore } from "@/stores/deceasedStore";
|
import { useDeceasedStore } from "@/stores/deceasedStore";
|
||||||
import { useClientStore } from "@/stores/clientStore";
|
import { useClientStore } from "@/stores/clientStore";
|
||||||
import { useNotificationStore } from "@/stores/notification";
|
import { useNotificationStore } from "@/stores/notification";
|
||||||
import { onMounted } from "vue";
|
|
||||||
|
|
||||||
// Router
|
// Router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -177,11 +197,58 @@ const handleCreateIntervention = async (form) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
defineProps({
|
const props = defineProps({
|
||||||
defunts: {
|
defunts: {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
pagination: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({
|
||||||
|
current_page: 1,
|
||||||
|
last_page: 1,
|
||||||
|
per_page: 10,
|
||||||
|
total: 0,
|
||||||
|
from: 0,
|
||||||
|
to: 0,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const safeFrom = computed(() => {
|
||||||
|
if (props.pagination?.from) {
|
||||||
|
return props.pagination.from;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!props.pagination?.total || props.defunts.length === 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
((Number(props.pagination.current_page) || 1) - 1) *
|
||||||
|
(Number(props.pagination.per_page) || 10) +
|
||||||
|
1
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const safeTo = computed(() => {
|
||||||
|
if (props.pagination?.to) {
|
||||||
|
return props.pagination.to;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!props.pagination?.total || props.defunts.length === 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.min(
|
||||||
|
(Number(props.pagination.current_page) || 1) *
|
||||||
|
(Number(props.pagination.per_page) || 10),
|
||||||
|
Number(props.pagination.total) || 0
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Modal management functions
|
// Modal management functions
|
||||||
|
|||||||
@ -13,6 +13,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
|
<div class="mt-4">
|
||||||
|
<slot name="header-pagination"></slot>
|
||||||
|
</div>
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<slot name="defunt-table"></slot>
|
<slot name="defunt-table"></slot>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -21,6 +21,8 @@ export const useDeceasedStore = defineStore("deceased", () => {
|
|||||||
last_page: 1,
|
last_page: 1,
|
||||||
per_page: 10,
|
per_page: 10,
|
||||||
total: 0,
|
total: 0,
|
||||||
|
from: 0,
|
||||||
|
to: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Getters
|
// Getters
|
||||||
@ -103,6 +105,8 @@ export const useDeceasedStore = defineStore("deceased", () => {
|
|||||||
last_page: meta.last_page || 1,
|
last_page: meta.last_page || 1,
|
||||||
per_page: meta.per_page || 10,
|
per_page: meta.per_page || 10,
|
||||||
total: meta.total || 0,
|
total: meta.total || 0,
|
||||||
|
from: meta.from || 0,
|
||||||
|
to: meta.to || 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -308,6 +312,8 @@ export const useDeceasedStore = defineStore("deceased", () => {
|
|||||||
last_page: 1,
|
last_page: 1,
|
||||||
per_page: 10,
|
per_page: 10,
|
||||||
total: 0,
|
total: 0,
|
||||||
|
from: 0,
|
||||||
|
to: 0,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,52 @@
|
|||||||
<template>
|
<template>
|
||||||
<defunt-presentation :defunts="deceasedStore.deceased" />
|
<defunt-presentation
|
||||||
|
:defunts="deceasedStore.deceased"
|
||||||
|
:loading="deceasedStore.loading"
|
||||||
|
:pagination="deceasedStore.getPagination"
|
||||||
|
:search="search"
|
||||||
|
@page-change="changePage"
|
||||||
|
@search-change="updateSearch"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import DefuntPresentation from "@/components/Organism/Defunts/DefuntPresentation.vue";
|
import DefuntPresentation from "@/components/Organism/Defunts/DefuntPresentation.vue";
|
||||||
import { useDeceasedStore } from "@/stores/deceasedStore";
|
import { useDeceasedStore } from "@/stores/deceasedStore";
|
||||||
import { onMounted } from "vue";
|
import { onMounted, ref } from "vue";
|
||||||
|
|
||||||
const deceasedStore = useDeceasedStore();
|
const deceasedStore = useDeceasedStore();
|
||||||
|
const search = ref("");
|
||||||
|
let searchDebounceTimeout = null;
|
||||||
|
const DEFAULT_PER_PAGE = 10;
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await deceasedStore.fetchDeceased();
|
await deceasedStore.fetchDeceased({
|
||||||
|
page: 1,
|
||||||
|
per_page: DEFAULT_PER_PAGE,
|
||||||
|
search: search.value.trim(),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const changePage = async (page) => {
|
||||||
|
await deceasedStore.fetchDeceased({
|
||||||
|
page,
|
||||||
|
per_page: deceasedStore.getPagination.per_page || DEFAULT_PER_PAGE,
|
||||||
|
search: search.value.trim(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateSearch = (value) => {
|
||||||
|
search.value = value;
|
||||||
|
|
||||||
|
if (searchDebounceTimeout) {
|
||||||
|
window.clearTimeout(searchDebounceTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
searchDebounceTimeout = window.setTimeout(async () => {
|
||||||
|
await deceasedStore.fetchDeceased({
|
||||||
|
page: 1,
|
||||||
|
per_page: deceasedStore.getPagination.per_page || DEFAULT_PER_PAGE,
|
||||||
|
search: search.value.trim(),
|
||||||
|
});
|
||||||
|
}, 300);
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user