feat: ajout tableau dynamiques
This commit is contained in:
parent
ce2fdfc08f
commit
52807890ec
1 changed files with 224 additions and 0 deletions
224
src/components/tableaux/DynTable.vue
Normal file
224
src/components/tableaux/DynTable.vue
Normal file
|
@ -0,0 +1,224 @@
|
|||
<script lang="ts" setup>
|
||||
import { computed, ref, onMounted } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import axios from "axios";
|
||||
|
||||
interface TableField {
|
||||
key: string;
|
||||
label: string;
|
||||
canBeFiltered?: boolean;
|
||||
}
|
||||
|
||||
interface Filters {
|
||||
[key: string]: boolean;
|
||||
}
|
||||
|
||||
interface FilterList {
|
||||
[key: string]: { title: string; filters: Filters };
|
||||
}
|
||||
|
||||
interface TableItem {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
fields: {
|
||||
type: Array as PropType<TableField[]>,
|
||||
default: () => [],
|
||||
},
|
||||
files: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const items = ref([] as TableItem[]);
|
||||
const filters = ref({} as FilterList);
|
||||
const pageNumber = ref(0);
|
||||
const elemByPage = ref(10);
|
||||
|
||||
const displayedFieldKeys = computed(() => {
|
||||
return Object.entries(props.fields).map(([key, value]) => value.key);
|
||||
});
|
||||
|
||||
function haveFilter(filterName: string) {
|
||||
for (const val in filters.value[filterName].filters) {
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(
|
||||
filters.value[filterName].filters,
|
||||
val
|
||||
)
|
||||
) {
|
||||
if (filters.value[filterName].filters[val]) {
|
||||
console.log(filterName, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(filterName, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
const filteredItems = computed(() => {
|
||||
var filteredItem = items.value as TableItem[];
|
||||
|
||||
for (const filter in filters.value) {
|
||||
if (haveFilter(filter)) {
|
||||
filteredItem = filteredItem.filter((value) => {
|
||||
return filters.value[filter].filters[value[filter] as string];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return filteredItem;
|
||||
});
|
||||
|
||||
const paginatedList = computed(() => {
|
||||
var filteredItem = filteredItems.value as TableItem[];
|
||||
|
||||
filteredItem = filteredItem.filter((value, index) => {
|
||||
const pageBegin = pageNumber.value * elemByPage.value;
|
||||
return index >= pageBegin && index < pageBegin + elemByPage.value;
|
||||
});
|
||||
|
||||
return filteredItem;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
for (const field of props.fields) {
|
||||
if (field.canBeFiltered) {
|
||||
filters.value[field.key] = {
|
||||
title: field.label,
|
||||
filters: {} as Filters,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
for (const file of props.files) {
|
||||
const listItems = `/jdr/objets/${file}.json`;
|
||||
axios.get(listItems).then((response) => {
|
||||
items.value = items.value.concat(response.data);
|
||||
response.data.forEach((element: TableItem) => {
|
||||
for (const key in element) {
|
||||
if (Object.prototype.hasOwnProperty.call(element, key)) {
|
||||
if (filters.value[key]) {
|
||||
filters.value[key].filters[element[key] as string] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function switchFilter(filterSet: string | number, filterName: string | number) {
|
||||
if (filters.value[filterSet]?.filters[filterName] !== undefined) {
|
||||
filters.value[filterSet].filters[filterName] =
|
||||
!filters.value[filterSet].filters[filterName];
|
||||
}
|
||||
setPage(0);
|
||||
}
|
||||
|
||||
function removeFilter(filterSet: string | number) {
|
||||
for (const val in filters.value[filterSet].filters) {
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(
|
||||
filters.value[filterSet].filters,
|
||||
val
|
||||
)
|
||||
) {
|
||||
filters.value[filterSet].filters[val] = false;
|
||||
}
|
||||
}
|
||||
setPage(0);
|
||||
}
|
||||
|
||||
const getTotalPage = computed(() => {
|
||||
return Math.floor((filteredItems.value.length - 1) / elemByPage.value);
|
||||
});
|
||||
|
||||
function setPage(page: number) {
|
||||
pageNumber.value = page;
|
||||
}
|
||||
|
||||
function canGo(rel: number) {
|
||||
return (
|
||||
pageNumber.value + rel >= 0 && pageNumber.value + rel <= getTotalPage.value
|
||||
);
|
||||
}
|
||||
|
||||
function go(rel: number) {
|
||||
if (canGo(rel)) {
|
||||
setPage(pageNumber.value + rel);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="small-text" v-for="(filter, key) in filters" :key="key">
|
||||
<strong>{{ filter.title }} : </strong>
|
||||
<button
|
||||
v-for="(isTrue, filterName) in filter.filters"
|
||||
:key="filterName"
|
||||
class="btn-small mb-0"
|
||||
:class="{ 'btn-grey': !isTrue, 'btn-primary': isTrue }"
|
||||
@click="switchFilter(key, filterName)"
|
||||
>
|
||||
{{ filterName }}
|
||||
</button>
|
||||
<button class="btn-small btn-secondary mb-0" @click="removeFilter(key)">
|
||||
Vider filtres
|
||||
</button>
|
||||
</div>
|
||||
<table class="pb-0 table-auto">
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="field in fields" :key="field.key">
|
||||
{{ field.label }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(item, index) of paginatedList" :key="index">
|
||||
<td v-for="(key, index2) in displayedFieldKeys" :key="index2">
|
||||
{{ item[key] }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="d-flex f-between f-middle nextprevious small-text">
|
||||
<div>
|
||||
<strong class="btn m-0 pages pl-0">
|
||||
Page {{ pageNumber + 1 }} / {{ getTotalPage + 1 }}
|
||||
</strong>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button
|
||||
class="btn btn-grey m-0 mr-1"
|
||||
:class="{ 'bg-grey': !canGo(-1), 'btn-secondary': canGo(-1) }"
|
||||
@click="go(-1)"
|
||||
>
|
||||
Page précédante
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-grey m-0"
|
||||
:class="{ 'bg-grey': !canGo(1), 'btn-secondary': canGo(1) }"
|
||||
@click="go(1)"
|
||||
>
|
||||
Page suivante
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.small-text {
|
||||
font-size: 0.8rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.pages {
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
Loading…
Reference in a new issue