v-sistec-features 1.5.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/v-sistec-features.css +1 -1
- package/dist/vDataTable.js +695 -507
- package/package.json +4 -2
- package/src/DatatableVue/components/PaginationDatatable.vue +21 -17
- package/src/DatatableVue/components/SearchDatatable.vue +28 -6
- package/src/DatatableVue/components/VColumn.vue +13 -0
- package/src/DatatableVue/components/VDataTable.vue +187 -30
- package/src/DatatableVue/keys.ts +4 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "v-sistec-features",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.6.1",
|
|
5
5
|
"author": "Márlon Bento Azevedo (https://github.com/marlon-bento)",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -46,7 +46,9 @@
|
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"@tabler/icons-vue": "^3.35.0",
|
|
48
48
|
"vue": "^3.2.0",
|
|
49
|
-
"vuedraggable": "^4.1.0"
|
|
49
|
+
"vuedraggable": "^4.1.0",
|
|
50
|
+
"v-api-fetch": "^1.3.0",
|
|
51
|
+
"v-required": "^2.0.2"
|
|
50
52
|
},
|
|
51
53
|
"devDependencies": {
|
|
52
54
|
"@semantic-release/changelog": "^6.0.3",
|
|
@@ -5,13 +5,14 @@ import { computed } from "vue";
|
|
|
5
5
|
// 1. DEFINIÇÃO DE TIPOS E INTERFACES
|
|
6
6
|
// =======================================================
|
|
7
7
|
interface PaginationObject {
|
|
8
|
-
current_page: number;
|
|
8
|
+
current_page: number; // Este é o valor da API (pode ser 0 ou 1 para a primeira pág)
|
|
9
9
|
count: number;
|
|
10
10
|
limit_per_page: number;
|
|
11
11
|
}
|
|
12
12
|
interface PaginationProps {
|
|
13
13
|
pagination: PaginationObject;
|
|
14
14
|
filtering?: boolean;
|
|
15
|
+
page_starts_at?: number; // 0 ou 1, define o que a API espera para a primeira página
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
// =======================================================
|
|
@@ -19,6 +20,7 @@ interface PaginationProps {
|
|
|
19
20
|
// =======================================================
|
|
20
21
|
const props = withDefaults(defineProps<PaginationProps>(), {
|
|
21
22
|
filtering: false,
|
|
23
|
+
page_starts_at: 0 // Padrão para API base 0
|
|
22
24
|
});
|
|
23
25
|
const emit = defineEmits<{
|
|
24
26
|
(e: 'tradePage'): void
|
|
@@ -33,8 +35,8 @@ const total_pages = computed<number>(() => {
|
|
|
33
35
|
});
|
|
34
36
|
|
|
35
37
|
const next = computed(() => {
|
|
36
|
-
return
|
|
37
|
-
?
|
|
38
|
+
return paginaAtual.value < total_pages.value
|
|
39
|
+
? paginaAtual.value
|
|
38
40
|
: null;
|
|
39
41
|
});
|
|
40
42
|
|
|
@@ -44,19 +46,19 @@ const nextPage = (): void => {
|
|
|
44
46
|
emit("tradePage");
|
|
45
47
|
};
|
|
46
48
|
const setPage = (newPage: number): void => {
|
|
47
|
-
props.pagination.current_page = newPage - 1;
|
|
49
|
+
props.pagination.current_page = newPage + (props.page_starts_at - 1);
|
|
48
50
|
emit("tradePage");
|
|
49
51
|
};
|
|
50
52
|
const lastPage = (): void => {
|
|
51
|
-
props.pagination.current_page = total_pages.value - 1;
|
|
53
|
+
props.pagination.current_page = total_pages.value + (props.page_starts_at - 1);
|
|
52
54
|
emit("tradePage");
|
|
53
55
|
};
|
|
54
56
|
const firstPage = (): void => {
|
|
55
|
-
props.pagination.current_page =
|
|
57
|
+
props.pagination.current_page = props.page_starts_at;
|
|
56
58
|
emit("tradePage");
|
|
57
59
|
};
|
|
58
60
|
const prevPage = (): void => {
|
|
59
|
-
if (props.pagination.current_page >
|
|
61
|
+
if (props.pagination.current_page > props.page_starts_at) {
|
|
60
62
|
props.pagination.current_page--;
|
|
61
63
|
emit("tradePage");
|
|
62
64
|
}
|
|
@@ -65,7 +67,9 @@ const prevPage = (): void => {
|
|
|
65
67
|
// =======================================================
|
|
66
68
|
// 4. LÓGICA DE GERAÇÃO DE PÁGINAS
|
|
67
69
|
// =======================================================
|
|
68
|
-
|
|
70
|
+
const paginaAtual = computed(() => {
|
|
71
|
+
return props.pagination.current_page - (props.page_starts_at - 1);
|
|
72
|
+
});
|
|
69
73
|
/**
|
|
70
74
|
* @description Computa um array com os números das páginas e as reticências a serem exibidas.
|
|
71
75
|
* Ex: [1, 2, '...', 10, 11, 12, '...', 33, 34]
|
|
@@ -75,15 +79,15 @@ const paginasParaExibir = computed(() => {
|
|
|
75
79
|
if (total_pages.value <= 7) {
|
|
76
80
|
return Array.from({ length: total_pages.value }, (_, i) => i + 1);
|
|
77
81
|
}
|
|
82
|
+
|
|
78
83
|
|
|
79
|
-
const paginaAtual = props.pagination.current_page + 1;
|
|
80
84
|
const total = total_pages.value;
|
|
81
85
|
|
|
82
86
|
// O conjunto de páginas visíveis sempre inclui as 2 primeiras, 2 últimas,
|
|
83
87
|
// a atual e suas duas vizinhas. O Set cuida de remover duplicatas.
|
|
84
88
|
const paginasEssenciais = new Set([
|
|
85
89
|
1, 2, // Sempre mostra as 2 primeiras
|
|
86
|
-
paginaAtual - 1, paginaAtual, paginaAtual + 1, // Mostra a atual e vizinhas
|
|
90
|
+
paginaAtual.value - 1, paginaAtual.value, paginaAtual.value + 1, // Mostra a atual e vizinhas
|
|
87
91
|
total - 1, total // Sempre mostra as 2 últimas
|
|
88
92
|
]);
|
|
89
93
|
|
|
@@ -133,27 +137,27 @@ const svg_uma_seta = `
|
|
|
133
137
|
Mostrando de
|
|
134
138
|
{{
|
|
135
139
|
props.pagination.count !== 0
|
|
136
|
-
? props.pagination.limit_per_page *
|
|
140
|
+
? props.pagination.limit_per_page * (paginaAtual - 1) + 1
|
|
137
141
|
: 0
|
|
138
142
|
}}
|
|
139
143
|
até
|
|
140
144
|
{{
|
|
141
|
-
props.pagination.limit_per_page * (
|
|
142
|
-
props.pagination.limit_per_page * (
|
|
145
|
+
props.pagination.limit_per_page * (paginaAtual) < props.pagination.count ?
|
|
146
|
+
props.pagination.limit_per_page * (paginaAtual) : props.pagination.count }} de {{
|
|
143
147
|
props.pagination.count }} registros </span>
|
|
144
148
|
<div class="d-flex align-items-center gap-2" v-if="total_pages > 0">
|
|
145
149
|
<div class="d-flex">
|
|
146
|
-
<button class="btn btn-estilo" @click.prevent="firstPage" :disabled="
|
|
150
|
+
<button class="btn btn-estilo" @click.prevent="firstPage" :disabled="paginaAtual === 1" v-html="svg_duas_setas">
|
|
147
151
|
</button>
|
|
148
|
-
<button class="btn btn-estilo" @click.prevent="prevPage" :disabled="
|
|
152
|
+
<button class="btn btn-estilo" @click.prevent="prevPage" :disabled="paginaAtual === 1" v-html="svg_uma_seta">
|
|
149
153
|
</button>
|
|
150
154
|
</div>
|
|
151
155
|
|
|
152
156
|
<div class="d-flex gap-2">
|
|
153
157
|
<template v-for="(pagina, index) in paginasParaExibir" :key="index">
|
|
154
158
|
<button v-if="typeof pagina === 'number'"
|
|
155
|
-
:class="
|
|
156
|
-
@click.prevent="setPage(pagina)" :disabled="
|
|
159
|
+
:class="paginaAtual == pagina ? 'page-select' : ''" class="page-estilo"
|
|
160
|
+
@click.prevent="setPage(pagina)" :disabled="paginaAtual == pagina">
|
|
157
161
|
{{ pagina }}
|
|
158
162
|
</button>
|
|
159
163
|
<span v-else class="m-0 p-0">...</span>
|
|
@@ -15,9 +15,14 @@
|
|
|
15
15
|
<input type="text" class="form-control ms-1" id="inputSearchLaudos" v-model="modelSearch"
|
|
16
16
|
@keyup.enter="$emit('search')" placeholder="Buscar...">
|
|
17
17
|
|
|
18
|
-
<span v-if="modelSearch" @click="cleanSearch()" class=" inputClose"
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
<span v-if="modelSearch" @click="cleanSearch()" class=" inputClose" title="Limpar pesquisa">
|
|
19
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
|
|
20
|
+
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
|
21
|
+
class="icon icon-tabler icons-tabler-outline icon-tabler-x">
|
|
22
|
+
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
|
23
|
+
<path d="M18 6l-12 12" />
|
|
24
|
+
<path d="M6 6l12 12" />
|
|
25
|
+
</svg>
|
|
21
26
|
</span>
|
|
22
27
|
<span v-else class="input-icon-addon">
|
|
23
28
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
|
|
@@ -30,19 +35,24 @@
|
|
|
30
35
|
</div>
|
|
31
36
|
<div v-if="item_use.includes(2)" class="dropdown-menu">
|
|
32
37
|
<template v-for="(filter, index) in props.list_filter" :key="index">
|
|
33
|
-
<router-link v-if="'type' in filter ? filter.type === 1 : false" :to="filter?.to"
|
|
38
|
+
<router-link v-if="('type' in filter ? filter.type === 1 : false) && ('visible' in filter ? filter.visible : true)" :to="filter?.to"
|
|
34
39
|
class="dropdown-item cursor-pointer">
|
|
35
40
|
{{ filter.text }}
|
|
36
41
|
</router-link>
|
|
37
|
-
<a v-else-if="'type' in filter ? filter.type === 2 : true"
|
|
42
|
+
<a v-else-if="('type' in filter ? filter.type === 2 : true) && ('visible' in filter ? filter.visible : true)"
|
|
38
43
|
@click.prevent="tradeFilter(String(filter.value))" class="dropdown-item cursor-pointer"
|
|
39
44
|
:class="modelFilter === filter?.value ? 'bg-info text-dark selected' : ''">
|
|
40
45
|
{{ filter.text }}
|
|
41
46
|
</a>
|
|
47
|
+
<a v-else-if="('type' in filter ? filter.type === 3 : true) && ('visible' in filter ? filter.visible : true)" @click.prevent="clickItem(filter)"
|
|
48
|
+
class="dropdown-item cursor-pointer"
|
|
49
|
+
:class="filter?.active ? 'bg-info text-dark selected' : ''"
|
|
50
|
+
>
|
|
51
|
+
{{ filter.text }}
|
|
52
|
+
</a>
|
|
42
53
|
</template>
|
|
43
54
|
</div>
|
|
44
55
|
</div>
|
|
45
|
-
|
|
46
56
|
</template>
|
|
47
57
|
<script setup lang="ts">
|
|
48
58
|
import { computed, watch } from 'vue';
|
|
@@ -83,6 +93,8 @@ const props = withDefaults(defineProps<SearchProps>(), {
|
|
|
83
93
|
// até o momento existem 2 items: 1 (search) e 2 (filter)
|
|
84
94
|
item_use: () => [1, 2], // se não for passado, assume que é para todos os itens
|
|
85
95
|
// até o momento existem 2 items: 1 (search) e 2 (filter)
|
|
96
|
+
|
|
97
|
+
click: null,
|
|
86
98
|
});
|
|
87
99
|
|
|
88
100
|
const emit = defineEmits(['update:search', 'update:filter', "search"])
|
|
@@ -128,10 +140,20 @@ function tradeFilter(newFilter: string): void {
|
|
|
128
140
|
modelFilter.value = newFilter;
|
|
129
141
|
}
|
|
130
142
|
}
|
|
143
|
+
|
|
131
144
|
function cleanSearch(): void {
|
|
132
145
|
modelSearch.value = ""
|
|
133
146
|
emit('search'); // emite o evento de busca para atualizar a lista
|
|
134
147
|
}
|
|
148
|
+
|
|
149
|
+
function clickItem(filter: any): void {
|
|
150
|
+
if (filter.click && typeof filter.click === 'function') {
|
|
151
|
+
filter.click();
|
|
152
|
+
} else {
|
|
153
|
+
console.error("O filtro selecionado não possui uma função de clique válida.");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
135
157
|
</script>
|
|
136
158
|
<style scoped>
|
|
137
159
|
.inputClose {
|
|
@@ -20,6 +20,10 @@ interface VColumnProps {
|
|
|
20
20
|
click?: Function | null;
|
|
21
21
|
// bloqueia a coluna para não ser movida
|
|
22
22
|
locked?: boolean;
|
|
23
|
+
use_ordering?: boolean;
|
|
24
|
+
param_ordering?: string;
|
|
25
|
+
decreasing_value?: string;
|
|
26
|
+
increasing_value?: string;
|
|
23
27
|
}
|
|
24
28
|
const props = withDefaults(defineProps<VColumnProps>(), {
|
|
25
29
|
field: null,
|
|
@@ -46,6 +50,11 @@ const props = withDefaults(defineProps<VColumnProps>(), {
|
|
|
46
50
|
transform_function: null ,
|
|
47
51
|
click: null,
|
|
48
52
|
locked: false,
|
|
53
|
+
|
|
54
|
+
use_ordering: false,
|
|
55
|
+
param_ordering: '',
|
|
56
|
+
decreasing_value: '',
|
|
57
|
+
increasing_value: '',
|
|
49
58
|
});
|
|
50
59
|
|
|
51
60
|
const slots = useSlots();
|
|
@@ -91,6 +100,10 @@ onMounted(() => {
|
|
|
91
100
|
click: props.click,
|
|
92
101
|
transform_function: props.transform_function,
|
|
93
102
|
locked: props.locked,
|
|
103
|
+
use_ordering: props.use_ordering,
|
|
104
|
+
param_ordering: props.param_ordering,
|
|
105
|
+
decreasing_value: props.decreasing_value,
|
|
106
|
+
increasing_value: props.increasing_value,
|
|
94
107
|
|
|
95
108
|
bodySlot: slots.body,
|
|
96
109
|
...(props.type === 'text' && { limite_text: Number(props.limite_text) }),
|
|
@@ -23,12 +23,16 @@
|
|
|
23
23
|
<Search v-model:search="pagination.search" v-model:filter="pagination.filter" :list_filter="props.list_filter"
|
|
24
24
|
:item_use="item_use" @search="reSearch" />
|
|
25
25
|
</div>
|
|
26
|
+
<slot name="item-selected-info" :selected_items="selected_items" :clearSelection="() => selected_items = []">
|
|
27
|
+
<div v-if="(props.use_checkbox && selected_items.length > 0) && !props.deactivate_selected_info"
|
|
28
|
+
class="alert alert-cyan d-flex justify-content-center align-items-center py-2" role="alert">
|
|
29
|
+
<h4 class="alert-title m-0"> <strong>Itens Selecionados:</strong> <span class="badge bg-azure text-azure-fg">{{ selected_items.length }}</span></h4>
|
|
30
|
+
<a class=" cursor-pointer " @click="selected_items = []">
|
|
31
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-trash"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M4 7l16 0" /><path d="M10 11l0 6" /><path d="M14 11l0 6" /><path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12" /><path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3" /></svg>
|
|
32
|
+
Limpar Seleção</a>
|
|
33
|
+
</div>
|
|
34
|
+
</slot>
|
|
26
35
|
|
|
27
|
-
<div v-if="props.use_checkbox && selected_items.length > 0"
|
|
28
|
-
class="alert alert-cyan d-flex justify-content-center align-items-center py-3" role="alert">
|
|
29
|
-
<h4 class="alert-title m-0"> <strong>Itens Selecionados:</strong> {{ selected_items.length }}</h4>
|
|
30
|
-
<button class="btn btn-outline-danger ms-3 bold " @click="selected_items = []">Limpar Seleção</button>
|
|
31
|
-
</div>
|
|
32
36
|
<template v-if="showLoadingState">
|
|
33
37
|
<template v-if="props.custom_loading">
|
|
34
38
|
<component :is="props.custom_loading" />
|
|
@@ -156,16 +160,110 @@
|
|
|
156
160
|
</template>
|
|
157
161
|
|
|
158
162
|
<template #item="{ element: col }">
|
|
159
|
-
<
|
|
160
|
-
|
|
161
|
-
|
|
163
|
+
<template v-if="col.use_ordering">
|
|
164
|
+
<th class="header-draggable" :class="col.class_column">
|
|
165
|
+
<div class="header-ordering">
|
|
166
|
+
<span>{{ col.header }}</span>
|
|
167
|
+
|
|
168
|
+
<span @click="() => toggleOrderingState(col.header)" class="ms-2 cursor-pointer">
|
|
169
|
+
<svg v-if="!orderings_state[col.header] || orderings_state[col.header] === 'none'"
|
|
170
|
+
xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none"
|
|
171
|
+
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
172
|
+
<path d="m3 8 4-4 4 4"></path>
|
|
173
|
+
<path d="m11 16-4 4-4-4"></path>
|
|
174
|
+
<path d="M7 4v16"></path>
|
|
175
|
+
<path d="M15 8h6"></path>
|
|
176
|
+
<path d="M15 16h6"></path>
|
|
177
|
+
<path d="M13 12h8"></path>
|
|
178
|
+
</svg>
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
<svg v-else-if="orderings_state[col.header] === 'decreasing'"
|
|
182
|
+
xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none"
|
|
183
|
+
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
184
|
+
<path d="m3 16 4 4 4-4"></path>
|
|
185
|
+
<path d="M7 20V4"></path>
|
|
186
|
+
<path d="M11 4h10"></path>
|
|
187
|
+
<path d="M11 8h7"></path>
|
|
188
|
+
<path d="M11 12h4"></path>
|
|
189
|
+
</svg>
|
|
190
|
+
|
|
191
|
+
<svg v-else-if="orderings_state[col.header] === 'increasing'"
|
|
192
|
+
xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none"
|
|
193
|
+
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
194
|
+
<path d="m3 8 4-4 4 4"></path>
|
|
195
|
+
<path d="M7 4v16"></path>
|
|
196
|
+
<path d="M11 12h4"></path>
|
|
197
|
+
<path d="M11 16h7"></path>
|
|
198
|
+
<path d="M11 20h10"></path>
|
|
199
|
+
</svg>
|
|
200
|
+
|
|
201
|
+
</span>
|
|
202
|
+
</div>
|
|
203
|
+
|
|
204
|
+
</th>
|
|
205
|
+
</template>
|
|
206
|
+
<template v-else>
|
|
207
|
+
<th class="header-draggable" :class="col.class_column">
|
|
208
|
+
{{ col.header }}
|
|
209
|
+
</th>
|
|
210
|
+
</template>
|
|
211
|
+
|
|
162
212
|
</template>
|
|
163
213
|
|
|
164
214
|
<template #footer>
|
|
165
215
|
<template v-for="col in lockedColumns" :key="col.field || col.header">
|
|
166
|
-
<
|
|
167
|
-
|
|
168
|
-
|
|
216
|
+
<template v-if="col.use_ordering">
|
|
217
|
+
<th class="header-locked header-ordering" :class="col.class_column">
|
|
218
|
+
<div class="header-ordering">
|
|
219
|
+
<span>{{ col.header }}</span>
|
|
220
|
+
|
|
221
|
+
<span @click="() => toggleOrderingState(col.header)" class="ms-2 cursor-pointer">
|
|
222
|
+
<svg v-if="!orderings_state[col.header] || orderings_state[col.header] === 'none'"
|
|
223
|
+
xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"
|
|
224
|
+
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
|
225
|
+
stroke-linejoin="round">
|
|
226
|
+
<path d="m3 8 4-4 4 4"></path>
|
|
227
|
+
<path d="m11 16-4 4-4-4"></path>
|
|
228
|
+
<path d="M7 4v16"></path>
|
|
229
|
+
<path d="M15 8h6"></path>
|
|
230
|
+
<path d="M15 16h6"></path>
|
|
231
|
+
<path d="M13 12h8"></path>
|
|
232
|
+
</svg>
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
<svg v-else-if="orderings_state[col.header] === 'decreasing'"
|
|
236
|
+
xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"
|
|
237
|
+
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
|
238
|
+
stroke-linejoin="round">
|
|
239
|
+
<path d="m3 16 4 4 4-4"></path>
|
|
240
|
+
<path d="M7 20V4"></path>
|
|
241
|
+
<path d="M11 4h10"></path>
|
|
242
|
+
<path d="M11 8h7"></path>
|
|
243
|
+
<path d="M11 12h4"></path>
|
|
244
|
+
</svg>
|
|
245
|
+
|
|
246
|
+
<svg v-else-if="orderings_state[col.header] === 'increasing'"
|
|
247
|
+
xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"
|
|
248
|
+
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
|
249
|
+
stroke-linejoin="round">
|
|
250
|
+
<path d="m3 8 4-4 4 4"></path>
|
|
251
|
+
<path d="M7 4v16"></path>
|
|
252
|
+
<path d="M11 12h4"></path>
|
|
253
|
+
<path d="M11 16h7"></path>
|
|
254
|
+
<path d="M11 20h10"></path>
|
|
255
|
+
</svg>
|
|
256
|
+
</span>
|
|
257
|
+
</div>
|
|
258
|
+
</th>
|
|
259
|
+
</template>
|
|
260
|
+
|
|
261
|
+
<template v-else>
|
|
262
|
+
<th class="header-locked" :class="col.class_column">
|
|
263
|
+
{{ col.header }}
|
|
264
|
+
</th>
|
|
265
|
+
</template>
|
|
266
|
+
|
|
169
267
|
</template>
|
|
170
268
|
</template>
|
|
171
269
|
</draggable>
|
|
@@ -188,10 +286,10 @@
|
|
|
188
286
|
<span @click="col.click ? col.click(item) : null" v-else-if="col.type === 'date'"
|
|
189
287
|
:class="col.class_item + (col.click ? ' cursor-pointer' : '')">
|
|
190
288
|
<span v-if="col.format === 'complete'">{{ new Date(getSubItem(col.field, item)).toLocaleString()
|
|
191
|
-
|
|
289
|
+
}}</span>
|
|
192
290
|
<span v-if="col.format === 'simple'"> {{ new Date(getSubItem(col.field,
|
|
193
291
|
item)).toLocaleDateString()
|
|
194
|
-
|
|
292
|
+
}} </span>
|
|
195
293
|
</span>
|
|
196
294
|
<div @click="col.click ? col.click(item) : null"
|
|
197
295
|
:class="col.class_item + (col.click ? ' cursor-pointer' : '')" v-else-if="col.type === 'html'"
|
|
@@ -232,7 +330,8 @@
|
|
|
232
330
|
</div>
|
|
233
331
|
<slot name="pagination" :pagination="pagination" :tradePage="fetchDataWithDelay" :error="error">
|
|
234
332
|
<div v-if="!error && pagination.count > 0" class="px-3" :class="props.class_pagination">
|
|
235
|
-
<PaginationDatatable :filtering="true" :pagination="pagination"
|
|
333
|
+
<PaginationDatatable :page_starts_at="props.page_starts_at" :filtering="true" :pagination="pagination"
|
|
334
|
+
@tradePage="fetchDataWithDelay" />
|
|
236
335
|
</div>
|
|
237
336
|
</slot>
|
|
238
337
|
|
|
@@ -316,10 +415,14 @@ interface VDataTableProps {
|
|
|
316
415
|
item_key?: string;
|
|
317
416
|
|
|
318
417
|
limit_per_page?: number;
|
|
418
|
+
page_starts_at?: number;
|
|
419
|
+
deactivate_selected_info?: boolean;
|
|
420
|
+
|
|
319
421
|
}
|
|
320
422
|
|
|
321
423
|
interface ExposedFunctions {
|
|
322
424
|
execute: () => void;
|
|
425
|
+
reSearch: () => void;
|
|
323
426
|
pagination: Ref<PaginationObject>;
|
|
324
427
|
default_params: Record<string, any>;
|
|
325
428
|
selected_items: Ref<T[]>;
|
|
@@ -359,6 +462,8 @@ const props = withDefaults(defineProps<VDataTableProps>(), {
|
|
|
359
462
|
first_text_page_size: 'Mostrar',
|
|
360
463
|
second_text_page_size: 'registros',
|
|
361
464
|
limit_per_page: 5,
|
|
465
|
+
page_starts_at: 0,
|
|
466
|
+
deactivate_selected_info: false,
|
|
362
467
|
});
|
|
363
468
|
|
|
364
469
|
|
|
@@ -367,6 +472,7 @@ const props = withDefaults(defineProps<VDataTableProps>(), {
|
|
|
367
472
|
// =======================================================
|
|
368
473
|
|
|
369
474
|
|
|
475
|
+
const orderings_state = ref<Record<string, 'none' | 'increasing' | 'decreasing'>>({});
|
|
370
476
|
const columns = ref<ColumnConfiguration[]>([]);
|
|
371
477
|
const items = ref<T[]>([]) as Ref<T[]>;
|
|
372
478
|
const totalItems = ref<number>(0);
|
|
@@ -378,36 +484,45 @@ const delayTimer = ref<ReturnType<typeof setTimeout> | null>(null);
|
|
|
378
484
|
|
|
379
485
|
/*--------- definição de páginação ---------------*/
|
|
380
486
|
const pagination = ref<PaginationObject>({
|
|
381
|
-
current_page:
|
|
487
|
+
current_page: props.page_starts_at, // pagina atual
|
|
382
488
|
count: 0, // total de itens
|
|
383
489
|
limit_per_page: props.limit_per_page, // limite de itens por página
|
|
384
490
|
search: '', // termo de busca
|
|
385
491
|
filter: '', // filtro selecionado
|
|
386
492
|
})
|
|
387
493
|
|
|
494
|
+
const urlReativa = computed(() => {
|
|
495
|
+
pagination.value.current_page = props.page_starts_at;
|
|
496
|
+
return props.endpoint;
|
|
497
|
+
});
|
|
388
498
|
// =======================================================
|
|
389
499
|
// 3. LÓGICA DA API (useFetch)
|
|
390
500
|
// =======================================================
|
|
391
|
-
const { data: response, pending, error, execute, attempt } = props.fetch(
|
|
501
|
+
const { data: response, pending, error, execute, attempt } = props.fetch(urlReativa, {
|
|
392
502
|
params: () => {
|
|
393
|
-
|
|
394
503
|
if (props.deactivate_default_params) {
|
|
395
504
|
if (props.add_params && typeof props.add_params === 'function') {
|
|
396
|
-
return
|
|
505
|
+
return {
|
|
506
|
+
...props.add_params(),
|
|
507
|
+
...params_ordering.value
|
|
508
|
+
};
|
|
397
509
|
}
|
|
398
510
|
return {
|
|
399
511
|
...props.add_params,
|
|
512
|
+
...params_ordering.value
|
|
400
513
|
};
|
|
401
514
|
}
|
|
402
515
|
else if (props.add_params && typeof props.add_params === 'function') {
|
|
403
516
|
return {
|
|
404
517
|
...default_params.value,
|
|
405
518
|
...props.add_params(),
|
|
519
|
+
...params_ordering.value
|
|
406
520
|
}
|
|
407
521
|
}
|
|
408
522
|
return {
|
|
409
523
|
...default_params.value,
|
|
410
524
|
...props.add_params,
|
|
525
|
+
...params_ordering.value
|
|
411
526
|
};
|
|
412
527
|
},
|
|
413
528
|
retry: props.retry_attempts,
|
|
@@ -446,6 +561,24 @@ const item_use = computed<number[]>(() => {
|
|
|
446
561
|
}
|
|
447
562
|
return use;
|
|
448
563
|
});
|
|
564
|
+
const params_ordering = computed(() => {
|
|
565
|
+
const objectOrdering: Record<string, any> = {};
|
|
566
|
+
for (const col of columns.value) {
|
|
567
|
+
if (col.use_ordering) {
|
|
568
|
+
if (orderings_state.value[col.header] === 'increasing') {
|
|
569
|
+
objectOrdering[col.param_ordering] = col.increasing_value || 'increasing';
|
|
570
|
+
} else if (orderings_state.value[col.header] === 'decreasing') {
|
|
571
|
+
objectOrdering[col.param_ordering] = col.decreasing_value || 'decreasing';
|
|
572
|
+
} else {
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
} else {
|
|
576
|
+
continue;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
return objectOrdering;
|
|
581
|
+
});
|
|
449
582
|
|
|
450
583
|
const default_params = computed<Record<string, any>>(() => ({
|
|
451
584
|
[props.page_param_name]: pagination.value.current_page + 1,
|
|
@@ -573,7 +706,7 @@ function fetchDataWithDelay(): void {
|
|
|
573
706
|
}
|
|
574
707
|
|
|
575
708
|
function reSearch(): void {
|
|
576
|
-
pagination.value.current_page =
|
|
709
|
+
pagination.value.current_page = props.page_starts_at;
|
|
577
710
|
fetchDataWithDelay();
|
|
578
711
|
}
|
|
579
712
|
|
|
@@ -583,8 +716,7 @@ const changePageSize = (event: Event): void => {
|
|
|
583
716
|
if (newSize > 0) {
|
|
584
717
|
pagination.value.limit_per_page = newSize;
|
|
585
718
|
pagination.value.limit_per_page = newSize; // Atualiza o limite de itens por página
|
|
586
|
-
|
|
587
|
-
fetchDataWithDelay();
|
|
719
|
+
reSearch();
|
|
588
720
|
}
|
|
589
721
|
};
|
|
590
722
|
|
|
@@ -617,32 +749,49 @@ function limiteText(text: string | null, limite: number | null): string | null {
|
|
|
617
749
|
return text;
|
|
618
750
|
}
|
|
619
751
|
|
|
752
|
+
function toggleOrderingState(header: string) {
|
|
753
|
+
// desabilita todos que não são o header clicado
|
|
754
|
+
for (const key in orderings_state.value) {
|
|
755
|
+
if (key !== header) {
|
|
756
|
+
orderings_state.value[key] = 'none';
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
const currentState = orderings_state.value[header] || 'none';
|
|
761
|
+
if (currentState === 'none') {
|
|
762
|
+
orderings_state.value[header] = 'increasing';
|
|
763
|
+
} else if (currentState === 'increasing') {
|
|
764
|
+
orderings_state.value[header] = 'decreasing';
|
|
765
|
+
} else {
|
|
766
|
+
orderings_state.value[header] = 'none';
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
reSearch();
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
|
|
620
773
|
// =======================================================
|
|
621
774
|
// 7. EXPOSE E CICLO DE VIDA
|
|
622
775
|
// =======================================================
|
|
623
776
|
function set_limit_per_page(newLimit: number): void {
|
|
624
777
|
if (newLimit > 0) {
|
|
625
778
|
pagination.value.limit_per_page = newLimit;
|
|
626
|
-
|
|
627
|
-
fetchDataWithDelay();
|
|
779
|
+
reSearch();
|
|
628
780
|
} else {
|
|
629
781
|
console.warn("O limite deve ser um número maior que zero.");
|
|
630
782
|
}
|
|
631
783
|
}
|
|
632
784
|
function set_search(newSearch: string): void {
|
|
633
785
|
pagination.value.search = newSearch;
|
|
634
|
-
|
|
635
|
-
fetchDataWithDelay();
|
|
786
|
+
reSearch();
|
|
636
787
|
}
|
|
637
788
|
function set_filter(newFilter: string): void {
|
|
638
789
|
pagination.value.filter = newFilter;
|
|
639
|
-
|
|
640
|
-
fetchDataWithDelay();
|
|
790
|
+
reSearch();
|
|
641
791
|
}
|
|
642
792
|
function set_page(newPage: number): void {
|
|
643
|
-
if (newPage >=
|
|
644
|
-
|
|
645
|
-
fetchDataWithDelay();
|
|
793
|
+
if (newPage >= 0 && newPage <= Math.ceil(pagination.value.count / pagination.value.limit_per_page)) {
|
|
794
|
+
reSearch();
|
|
646
795
|
} else {
|
|
647
796
|
console.warn("Número de página inválido.");
|
|
648
797
|
}
|
|
@@ -652,6 +801,7 @@ defineExpose<
|
|
|
652
801
|
ExposedFunctions
|
|
653
802
|
>({
|
|
654
803
|
execute: fetchDataWithDelay,
|
|
804
|
+
reSearch:reSearch,
|
|
655
805
|
pagination: readonly(pagination),
|
|
656
806
|
set_limit_per_page: set_limit_per_page,
|
|
657
807
|
set_search: set_search,
|
|
@@ -835,6 +985,7 @@ $max-width-preview: 250px;
|
|
|
835
985
|
cursor: grab;
|
|
836
986
|
}
|
|
837
987
|
|
|
988
|
+
|
|
838
989
|
/*
|
|
839
990
|
Animações para movimentação de colunas
|
|
840
991
|
*/
|
|
@@ -846,4 +997,10 @@ $max-width-preview: 250px;
|
|
|
846
997
|
.column-move-leave-active {
|
|
847
998
|
transition: all 0.4s ease;
|
|
848
999
|
}
|
|
1000
|
+
|
|
1001
|
+
|
|
1002
|
+
.header-ordering {
|
|
1003
|
+
display: flex;
|
|
1004
|
+
justify-content: space-between;
|
|
1005
|
+
}
|
|
849
1006
|
</style>
|
package/src/DatatableVue/keys.ts
CHANGED
|
@@ -15,6 +15,10 @@ export interface ColumnConfiguration {
|
|
|
15
15
|
format?: 'complete' | 'simple';
|
|
16
16
|
click: Function | null;
|
|
17
17
|
locked: boolean;
|
|
18
|
+
use_ordering: boolean;
|
|
19
|
+
param_ordering: string;
|
|
20
|
+
decreasing_value: string;
|
|
21
|
+
increasing_value: string;
|
|
18
22
|
}
|
|
19
23
|
|
|
20
24
|
// A API que o VDataTable "fornece" para os filhos
|