Refonte inventaire et objets #236
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