vue-laravel-crud 2.0.6 → 2.0.8
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/vue-laravel-crud.esm.js +244 -131
- package/dist/vue-laravel-crud.min.js +3 -3
- package/dist/vue-laravel-crud.ssr.js +245 -137
- package/package.json +1 -1
- package/src/components/CrudCards.vue +131 -114
- package/src/components/CrudCustom.vue +58 -41
- package/src/components/CrudFilters.vue +319 -319
- package/src/components/CrudHeader.vue +154 -152
- package/src/components/CrudKanban.vue +36 -36
- package/src/components/CrudModals.vue +98 -15
- package/src/components/CrudPagination.vue +207 -200
- package/src/components/CrudTable.vue +103 -86
- package/src/vue-laravel-crud.vue +718 -718
|
@@ -1,319 +1,319 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="px-3 py-2">
|
|
3
|
-
<div v-for="(column, indexc) in columns" :key="indexc">
|
|
4
|
-
<div v-if="isColumnHasFilter(column)">
|
|
5
|
-
<slot :name="'sidebar-filter-' + column.prop" v-bind:column="column" v-bind:filter="filter"
|
|
6
|
-
v-bind:internalFilterByProp="internalFilterByProp" v-bind:getFilterForColumn="getFilterForColumn">
|
|
7
|
-
<div class="form-group" v-if="column.type == 'boolean'">
|
|
8
|
-
<label>{{ column.label }}</label>
|
|
9
|
-
|
|
10
|
-
<select class="form-control" v-model="getFilterForColumn(column).value"
|
|
11
|
-
@change="onChangeFilter($event)">
|
|
12
|
-
<option value=""></option>
|
|
13
|
-
<option value="1">Sí</option>
|
|
14
|
-
<option value="0">No</option>
|
|
15
|
-
</select>
|
|
16
|
-
</div>
|
|
17
|
-
<div class="form-group" v-else-if="column.type == 'date'">
|
|
18
|
-
<div class="row">
|
|
19
|
-
<div class="col-6">
|
|
20
|
-
<b-form-datepicker v-model="getFilterForDateFrom(column).value
|
|
21
|
-
" today-button reset-button close-button locale="es"></b-form-datepicker>
|
|
22
|
-
</div>
|
|
23
|
-
<div class="col-6">
|
|
24
|
-
<b-form-datepicker v-model="getFilterForDateTo(column).value
|
|
25
|
-
" today-button reset-button close-button locale="es"></b-form-datepicker>
|
|
26
|
-
</div>
|
|
27
|
-
</div>
|
|
28
|
-
</div>
|
|
29
|
-
|
|
30
|
-
<div class="form-group" v-else-if="column.type == 'number' || column.type == 'money'">
|
|
31
|
-
<label>{{ column.label }}</label>
|
|
32
|
-
<div class="row">
|
|
33
|
-
<div class="col-6">
|
|
34
|
-
<input
|
|
35
|
-
type="number"
|
|
36
|
-
class="form-control"
|
|
37
|
-
v-model.number="getFilterForDateFrom(column).value"
|
|
38
|
-
:step="column.type == 'money' ? '0.01' : '1'"
|
|
39
|
-
@change="onChangeFilter($event)"
|
|
40
|
-
placeholder="Desde" />
|
|
41
|
-
</div>
|
|
42
|
-
<div class="col-6">
|
|
43
|
-
<input
|
|
44
|
-
type="number"
|
|
45
|
-
class="form-control"
|
|
46
|
-
v-model.number="getFilterForDateTo(column).value"
|
|
47
|
-
:step="column.type == 'money' ? '0.01' : '1'"
|
|
48
|
-
@change="onChangeFilter($event)"
|
|
49
|
-
placeholder="Hasta" />
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
</div>
|
|
53
|
-
|
|
54
|
-
<div class="form-group" v-else-if="column.type == 'state'">
|
|
55
|
-
<label>{{ column.label }}</label>
|
|
56
|
-
|
|
57
|
-
<select class="form-control" v-model="getFilterForColumn(column).value"
|
|
58
|
-
@change="onChangeFilter($event)" v-if="column.options && Array.isArray(column.options)">
|
|
59
|
-
<option value=""></option>
|
|
60
|
-
<option :value="option.value" v-for="option in column.options"
|
|
61
|
-
:key="option.value || option.id">
|
|
62
|
-
{{ option.text }}
|
|
63
|
-
</option>
|
|
64
|
-
</select>
|
|
65
|
-
</div>
|
|
66
|
-
|
|
67
|
-
<div class="form-group" v-else-if="column.type == 'array'">
|
|
68
|
-
<label>{{ column.label }}</label>
|
|
69
|
-
|
|
70
|
-
<select class="form-control" v-model="getFilterForColumn(column).value"
|
|
71
|
-
@change="onChangeFilter($event)" v-if="column.options && Array.isArray(column.options)">
|
|
72
|
-
<option value=""></option>
|
|
73
|
-
<option :value="option.value" v-for="option in column.options"
|
|
74
|
-
:key="option.value || option.id">
|
|
75
|
-
{{ option.text }}
|
|
76
|
-
</option>
|
|
77
|
-
</select>
|
|
78
|
-
</div>
|
|
79
|
-
|
|
80
|
-
<div class="form-group" v-else>
|
|
81
|
-
<label>{{ column.label }}</label>
|
|
82
|
-
|
|
83
|
-
<input class="form-control" v-model.lazy="getFilterForColumn(column).value"
|
|
84
|
-
@change="onChangeFilter($event)" />
|
|
85
|
-
</div>
|
|
86
|
-
</slot>
|
|
87
|
-
</div>
|
|
88
|
-
</div>
|
|
89
|
-
|
|
90
|
-
<!-- Filtros custom -->
|
|
91
|
-
<div v-for="(customFilter, indexcf) in customFilters" :key="'custom-' + indexcf">
|
|
92
|
-
<div v-if="isCustomFilterEnabled(customFilter)">
|
|
93
|
-
<!-- Slot personalizado para filtro custom -->
|
|
94
|
-
<slot :name="'sidebar-filter-custom-' + customFilter.prop" v-bind:column="customFilter" v-bind:filter="filter"
|
|
95
|
-
v-bind:internalFilterByProp="internalFilterByProp" v-bind:getFilterForColumn="getFilterForColumn">
|
|
96
|
-
|
|
97
|
-
<!-- Si type es una función callback -->
|
|
98
|
-
<RenderCustomFilter
|
|
99
|
-
v-if="typeof customFilter.type === 'function'"
|
|
100
|
-
:render-function="customFilter.type"
|
|
101
|
-
:custom-filter="customFilter"
|
|
102
|
-
:filter="filter"
|
|
103
|
-
:internal-filter-by-prop="internalFilterByProp"
|
|
104
|
-
:get-filter-for-column="getFilterForColumn"
|
|
105
|
-
:on-change-filter="onChangeFilter"
|
|
106
|
-
/>
|
|
107
|
-
|
|
108
|
-
<!-- Si type es string, usar la misma lógica que las columnas -->
|
|
109
|
-
<template v-else>
|
|
110
|
-
<div class="form-group" v-if="customFilter.type == 'boolean'">
|
|
111
|
-
<label>{{ customFilter.label }}</label>
|
|
112
|
-
|
|
113
|
-
<select class="form-control" v-model="getFilterForColumn(customFilter).value"
|
|
114
|
-
@change="onChangeFilter($event)">
|
|
115
|
-
<option value=""></option>
|
|
116
|
-
<option value="1">Sí</option>
|
|
117
|
-
<option value="0">No</option>
|
|
118
|
-
</select>
|
|
119
|
-
</div>
|
|
120
|
-
|
|
121
|
-
<div class="form-group" v-else-if="customFilter.type == 'date'">
|
|
122
|
-
<label>{{ customFilter.label }}</label>
|
|
123
|
-
<div class="row">
|
|
124
|
-
<div class="col-6">
|
|
125
|
-
<b-form-datepicker v-model="getFilterForDateFrom(customFilter).value
|
|
126
|
-
" today-button reset-button close-button locale="es"></b-form-datepicker>
|
|
127
|
-
</div>
|
|
128
|
-
<div class="col-6">
|
|
129
|
-
<b-form-datepicker v-model="getFilterForDateTo(customFilter).value
|
|
130
|
-
" today-button reset-button close-button locale="es"></b-form-datepicker>
|
|
131
|
-
</div>
|
|
132
|
-
</div>
|
|
133
|
-
</div>
|
|
134
|
-
|
|
135
|
-
<div class="form-group" v-else-if="customFilter.type == 'number' || customFilter.type == 'money'">
|
|
136
|
-
<label>{{ customFilter.label }}</label>
|
|
137
|
-
<div class="row">
|
|
138
|
-
<div class="col-6">
|
|
139
|
-
<input
|
|
140
|
-
type="number"
|
|
141
|
-
class="form-control"
|
|
142
|
-
v-model.number="getFilterForDateFrom(customFilter).value"
|
|
143
|
-
:step="customFilter.type == 'money' ? '0.01' : '1'"
|
|
144
|
-
@change="onChangeFilter($event)"
|
|
145
|
-
placeholder="Desde" />
|
|
146
|
-
</div>
|
|
147
|
-
<div class="col-6">
|
|
148
|
-
<input
|
|
149
|
-
type="number"
|
|
150
|
-
class="form-control"
|
|
151
|
-
v-model.number="getFilterForDateTo(customFilter).value"
|
|
152
|
-
:step="customFilter.type == 'money' ? '0.01' : '1'"
|
|
153
|
-
@change="onChangeFilter($event)"
|
|
154
|
-
placeholder="Hasta" />
|
|
155
|
-
</div>
|
|
156
|
-
</div>
|
|
157
|
-
</div>
|
|
158
|
-
|
|
159
|
-
<div class="form-group" v-else-if="customFilter.type == 'state'">
|
|
160
|
-
<label>{{ customFilter.label }}</label>
|
|
161
|
-
|
|
162
|
-
<select class="form-control" v-model="getFilterForColumn(customFilter).value"
|
|
163
|
-
@change="onChangeFilter($event)" v-if="customFilter.options && Array.isArray(customFilter.options)">
|
|
164
|
-
<option value=""></option>
|
|
165
|
-
<option :value="option.value" v-for="option in customFilter.options"
|
|
166
|
-
:key="option.value || option.id">
|
|
167
|
-
{{ option.text }}
|
|
168
|
-
</option>
|
|
169
|
-
</select>
|
|
170
|
-
</div>
|
|
171
|
-
|
|
172
|
-
<div class="form-group" v-else-if="customFilter.type == 'array'">
|
|
173
|
-
<label>{{ customFilter.label }}</label>
|
|
174
|
-
|
|
175
|
-
<select class="form-control" v-model="getFilterForColumn(customFilter).value"
|
|
176
|
-
@change="onChangeFilter($event)" v-if="customFilter.options && Array.isArray(customFilter.options)">
|
|
177
|
-
<option value=""></option>
|
|
178
|
-
<option :value="option.value" v-for="option in customFilter.options"
|
|
179
|
-
:key="option.value || option.id">
|
|
180
|
-
{{ option.text }}
|
|
181
|
-
</option>
|
|
182
|
-
</select>
|
|
183
|
-
</div>
|
|
184
|
-
|
|
185
|
-
<div class="form-group" v-else>
|
|
186
|
-
<label>{{ customFilter.label }}</label>
|
|
187
|
-
|
|
188
|
-
<input class="form-control" v-model.lazy="getFilterForColumn(customFilter).value"
|
|
189
|
-
@change="onChangeFilter($event)" />
|
|
190
|
-
</div>
|
|
191
|
-
</template>
|
|
192
|
-
</slot>
|
|
193
|
-
</div>
|
|
194
|
-
</div>
|
|
195
|
-
|
|
196
|
-
<div class="mt-3 d-flex justify-content-center">
|
|
197
|
-
<button class="btn btn-light" @click="resetFilters()">
|
|
198
|
-
Reset
|
|
199
|
-
</button>
|
|
200
|
-
<button class="btn btn-info" @click="onChangeFilter($event)">
|
|
201
|
-
Filtrar
|
|
202
|
-
</button>
|
|
203
|
-
</div>
|
|
204
|
-
</div>
|
|
205
|
-
</template>
|
|
206
|
-
|
|
207
|
-
<script>
|
|
208
|
-
// Componente funcional para renderizar filtros custom con callback
|
|
209
|
-
const RenderCustomFilter = {
|
|
210
|
-
functional: true,
|
|
211
|
-
props: {
|
|
212
|
-
renderFunction: {
|
|
213
|
-
type: Function,
|
|
214
|
-
required: true
|
|
215
|
-
},
|
|
216
|
-
customFilter: {
|
|
217
|
-
type: Object,
|
|
218
|
-
required: true
|
|
219
|
-
},
|
|
220
|
-
filter: {
|
|
221
|
-
type: Array,
|
|
222
|
-
default: () => []
|
|
223
|
-
},
|
|
224
|
-
internalFilterByProp: {
|
|
225
|
-
type: Function,
|
|
226
|
-
required: true
|
|
227
|
-
},
|
|
228
|
-
getFilterForColumn: {
|
|
229
|
-
type: Function,
|
|
230
|
-
required: true
|
|
231
|
-
},
|
|
232
|
-
onChangeFilter: {
|
|
233
|
-
type: Function,
|
|
234
|
-
required: true
|
|
235
|
-
}
|
|
236
|
-
},
|
|
237
|
-
render(h, context) {
|
|
238
|
-
const { renderFunction, customFilter, filter, internalFilterByProp, getFilterForColumn, onChangeFilter } = context.props;
|
|
239
|
-
return renderFunction(h, {
|
|
240
|
-
column: customFilter,
|
|
241
|
-
filter: filter,
|
|
242
|
-
internalFilterByProp: internalFilterByProp,
|
|
243
|
-
getFilterForColumn: getFilterForColumn,
|
|
244
|
-
onChangeFilter: onChangeFilter
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
export default {
|
|
250
|
-
name: 'CrudFilters',
|
|
251
|
-
components: {
|
|
252
|
-
RenderCustomFilter
|
|
253
|
-
},
|
|
254
|
-
inject: [
|
|
255
|
-
'columns',
|
|
256
|
-
'customFilters',
|
|
257
|
-
'isColumnHasFilter',
|
|
258
|
-
'isCustomFilterEnabled',
|
|
259
|
-
'filter',
|
|
260
|
-
'internalFilterByProp',
|
|
261
|
-
'optionsLoaded',
|
|
262
|
-
'onChangeFilter',
|
|
263
|
-
'resetFilters',
|
|
264
|
-
'setupFilters',
|
|
265
|
-
'internalFilters'
|
|
266
|
-
],
|
|
267
|
-
methods: {
|
|
268
|
-
// Método helper para obtener el filtro de forma segura, creándolo si no existe
|
|
269
|
-
getFilterForColumn(column) {
|
|
270
|
-
let filter = this.internalFilterByProp(column.prop);
|
|
271
|
-
|
|
272
|
-
// Si el filtro no existe, intentar inicializar los filtros
|
|
273
|
-
if (!filter) {
|
|
274
|
-
// Verificar si hay filtros inicializados
|
|
275
|
-
if (this.internalFilters && this.internalFilters.length === 0) {
|
|
276
|
-
this.setupFilters();
|
|
277
|
-
// Intentar obtener el filtro nuevamente después de inicializar
|
|
278
|
-
filter = this.internalFilterByProp(column.prop);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// Si aún no existe, crear un objeto temporal para evitar errores
|
|
283
|
-
if (!filter) {
|
|
284
|
-
return {
|
|
285
|
-
value: null
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
return filter;
|
|
290
|
-
},
|
|
291
|
-
|
|
292
|
-
// Método helper específico para campos de fecha (from)
|
|
293
|
-
getFilterForDateFrom(column) {
|
|
294
|
-
const filter = this.internalFilterByProp(column.prop + '_from');
|
|
295
|
-
if (!filter) {
|
|
296
|
-
if (this.internalFilters && this.internalFilters.length === 0) {
|
|
297
|
-
this.setupFilters();
|
|
298
|
-
return this.internalFilterByProp(column.prop + '_from') || { value: null };
|
|
299
|
-
}
|
|
300
|
-
return { value: null };
|
|
301
|
-
}
|
|
302
|
-
return filter;
|
|
303
|
-
},
|
|
304
|
-
|
|
305
|
-
// Método helper específico para campos de fecha (to)
|
|
306
|
-
getFilterForDateTo(column) {
|
|
307
|
-
const filter = this.internalFilterByProp(column.prop + '_to');
|
|
308
|
-
if (!filter) {
|
|
309
|
-
if (this.internalFilters && this.internalFilters.length === 0) {
|
|
310
|
-
this.setupFilters();
|
|
311
|
-
return this.internalFilterByProp(column.prop + '_to') || { value: null };
|
|
312
|
-
}
|
|
313
|
-
return { value: null };
|
|
314
|
-
}
|
|
315
|
-
return filter;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
};
|
|
319
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<div class="px-3 py-2">
|
|
3
|
+
<div v-for="(column, indexc) in columns" :key="indexc">
|
|
4
|
+
<div v-if="isColumnHasFilter(column)">
|
|
5
|
+
<slot :name="'sidebar-filter-' + column.prop" v-bind:column="column" v-bind:filter="filter"
|
|
6
|
+
v-bind:internalFilterByProp="internalFilterByProp" v-bind:getFilterForColumn="getFilterForColumn">
|
|
7
|
+
<div class="form-group" v-if="column.type == 'boolean'">
|
|
8
|
+
<label>{{ column.label }}</label>
|
|
9
|
+
|
|
10
|
+
<select class="form-control" v-model="getFilterForColumn(column).value"
|
|
11
|
+
@change="onChangeFilter($event)">
|
|
12
|
+
<option value=""></option>
|
|
13
|
+
<option value="1">Sí</option>
|
|
14
|
+
<option value="0">No</option>
|
|
15
|
+
</select>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="form-group" v-else-if="column.type == 'date'">
|
|
18
|
+
<div class="row">
|
|
19
|
+
<div class="col-6">
|
|
20
|
+
<b-form-datepicker v-model="getFilterForDateFrom(column).value
|
|
21
|
+
" today-button reset-button close-button locale="es"></b-form-datepicker>
|
|
22
|
+
</div>
|
|
23
|
+
<div class="col-6">
|
|
24
|
+
<b-form-datepicker v-model="getFilterForDateTo(column).value
|
|
25
|
+
" today-button reset-button close-button locale="es"></b-form-datepicker>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div class="form-group" v-else-if="column.type == 'number' || column.type == 'money'">
|
|
31
|
+
<label>{{ column.label }}</label>
|
|
32
|
+
<div class="row">
|
|
33
|
+
<div class="col-6">
|
|
34
|
+
<input
|
|
35
|
+
type="number"
|
|
36
|
+
class="form-control"
|
|
37
|
+
v-model.number="getFilterForDateFrom(column).value"
|
|
38
|
+
:step="column.type == 'money' ? '0.01' : '1'"
|
|
39
|
+
@change="onChangeFilter($event)"
|
|
40
|
+
placeholder="Desde" />
|
|
41
|
+
</div>
|
|
42
|
+
<div class="col-6">
|
|
43
|
+
<input
|
|
44
|
+
type="number"
|
|
45
|
+
class="form-control"
|
|
46
|
+
v-model.number="getFilterForDateTo(column).value"
|
|
47
|
+
:step="column.type == 'money' ? '0.01' : '1'"
|
|
48
|
+
@change="onChangeFilter($event)"
|
|
49
|
+
placeholder="Hasta" />
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<div class="form-group" v-else-if="column.type == 'state'">
|
|
55
|
+
<label>{{ column.label }}</label>
|
|
56
|
+
|
|
57
|
+
<select class="form-control" v-model="getFilterForColumn(column).value"
|
|
58
|
+
@change="onChangeFilter($event)" v-if="column.options && Array.isArray(column.options)">
|
|
59
|
+
<option value=""></option>
|
|
60
|
+
<option :value="option.value" v-for="option in column.options"
|
|
61
|
+
:key="option.value || option.id">
|
|
62
|
+
{{ option.text }}
|
|
63
|
+
</option>
|
|
64
|
+
</select>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div class="form-group" v-else-if="column.type == 'array'">
|
|
68
|
+
<label>{{ column.label }}</label>
|
|
69
|
+
|
|
70
|
+
<select class="form-control" v-model="getFilterForColumn(column).value"
|
|
71
|
+
@change="onChangeFilter($event)" v-if="column.options && Array.isArray(column.options)">
|
|
72
|
+
<option value=""></option>
|
|
73
|
+
<option :value="option.value" v-for="option in column.options"
|
|
74
|
+
:key="option.value || option.id">
|
|
75
|
+
{{ option.text }}
|
|
76
|
+
</option>
|
|
77
|
+
</select>
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
<div class="form-group" v-else>
|
|
81
|
+
<label>{{ column.label }}</label>
|
|
82
|
+
|
|
83
|
+
<input class="form-control" v-model.lazy="getFilterForColumn(column).value"
|
|
84
|
+
@change="onChangeFilter($event)" />
|
|
85
|
+
</div>
|
|
86
|
+
</slot>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
<!-- Filtros custom -->
|
|
91
|
+
<div v-for="(customFilter, indexcf) in customFilters" :key="'custom-' + indexcf">
|
|
92
|
+
<div v-if="isCustomFilterEnabled(customFilter)">
|
|
93
|
+
<!-- Slot personalizado para filtro custom -->
|
|
94
|
+
<slot :name="'sidebar-filter-custom-' + customFilter.prop" v-bind:column="customFilter" v-bind:filter="filter"
|
|
95
|
+
v-bind:internalFilterByProp="internalFilterByProp" v-bind:getFilterForColumn="getFilterForColumn">
|
|
96
|
+
|
|
97
|
+
<!-- Si type es una función callback -->
|
|
98
|
+
<RenderCustomFilter
|
|
99
|
+
v-if="typeof customFilter.type === 'function'"
|
|
100
|
+
:render-function="customFilter.type"
|
|
101
|
+
:custom-filter="customFilter"
|
|
102
|
+
:filter="filter"
|
|
103
|
+
:internal-filter-by-prop="internalFilterByProp"
|
|
104
|
+
:get-filter-for-column="getFilterForColumn"
|
|
105
|
+
:on-change-filter="onChangeFilter"
|
|
106
|
+
/>
|
|
107
|
+
|
|
108
|
+
<!-- Si type es string, usar la misma lógica que las columnas -->
|
|
109
|
+
<template v-else>
|
|
110
|
+
<div class="form-group" v-if="customFilter.type == 'boolean'">
|
|
111
|
+
<label>{{ customFilter.label }}</label>
|
|
112
|
+
|
|
113
|
+
<select class="form-control" v-model="getFilterForColumn(customFilter).value"
|
|
114
|
+
@change="onChangeFilter($event)">
|
|
115
|
+
<option value=""></option>
|
|
116
|
+
<option value="1">Sí</option>
|
|
117
|
+
<option value="0">No</option>
|
|
118
|
+
</select>
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
<div class="form-group" v-else-if="customFilter.type == 'date'">
|
|
122
|
+
<label>{{ customFilter.label }}</label>
|
|
123
|
+
<div class="row">
|
|
124
|
+
<div class="col-6">
|
|
125
|
+
<b-form-datepicker v-model="getFilterForDateFrom(customFilter).value
|
|
126
|
+
" today-button reset-button close-button locale="es"></b-form-datepicker>
|
|
127
|
+
</div>
|
|
128
|
+
<div class="col-6">
|
|
129
|
+
<b-form-datepicker v-model="getFilterForDateTo(customFilter).value
|
|
130
|
+
" today-button reset-button close-button locale="es"></b-form-datepicker>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
|
|
135
|
+
<div class="form-group" v-else-if="customFilter.type == 'number' || customFilter.type == 'money'">
|
|
136
|
+
<label>{{ customFilter.label }}</label>
|
|
137
|
+
<div class="row">
|
|
138
|
+
<div class="col-6">
|
|
139
|
+
<input
|
|
140
|
+
type="number"
|
|
141
|
+
class="form-control"
|
|
142
|
+
v-model.number="getFilterForDateFrom(customFilter).value"
|
|
143
|
+
:step="customFilter.type == 'money' ? '0.01' : '1'"
|
|
144
|
+
@change="onChangeFilter($event)"
|
|
145
|
+
placeholder="Desde" />
|
|
146
|
+
</div>
|
|
147
|
+
<div class="col-6">
|
|
148
|
+
<input
|
|
149
|
+
type="number"
|
|
150
|
+
class="form-control"
|
|
151
|
+
v-model.number="getFilterForDateTo(customFilter).value"
|
|
152
|
+
:step="customFilter.type == 'money' ? '0.01' : '1'"
|
|
153
|
+
@change="onChangeFilter($event)"
|
|
154
|
+
placeholder="Hasta" />
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
|
|
159
|
+
<div class="form-group" v-else-if="customFilter.type == 'state'">
|
|
160
|
+
<label>{{ customFilter.label }}</label>
|
|
161
|
+
|
|
162
|
+
<select class="form-control" v-model="getFilterForColumn(customFilter).value"
|
|
163
|
+
@change="onChangeFilter($event)" v-if="customFilter.options && Array.isArray(customFilter.options)">
|
|
164
|
+
<option value=""></option>
|
|
165
|
+
<option :value="option.value" v-for="option in customFilter.options"
|
|
166
|
+
:key="option.value || option.id">
|
|
167
|
+
{{ option.text }}
|
|
168
|
+
</option>
|
|
169
|
+
</select>
|
|
170
|
+
</div>
|
|
171
|
+
|
|
172
|
+
<div class="form-group" v-else-if="customFilter.type == 'array'">
|
|
173
|
+
<label>{{ customFilter.label }}</label>
|
|
174
|
+
|
|
175
|
+
<select class="form-control" v-model="getFilterForColumn(customFilter).value"
|
|
176
|
+
@change="onChangeFilter($event)" v-if="customFilter.options && Array.isArray(customFilter.options)">
|
|
177
|
+
<option value=""></option>
|
|
178
|
+
<option :value="option.value" v-for="option in customFilter.options"
|
|
179
|
+
:key="option.value || option.id">
|
|
180
|
+
{{ option.text }}
|
|
181
|
+
</option>
|
|
182
|
+
</select>
|
|
183
|
+
</div>
|
|
184
|
+
|
|
185
|
+
<div class="form-group" v-else>
|
|
186
|
+
<label>{{ customFilter.label }}</label>
|
|
187
|
+
|
|
188
|
+
<input class="form-control" v-model.lazy="getFilterForColumn(customFilter).value"
|
|
189
|
+
@change="onChangeFilter($event)" />
|
|
190
|
+
</div>
|
|
191
|
+
</template>
|
|
192
|
+
</slot>
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
<div class="mt-3 d-flex justify-content-center">
|
|
197
|
+
<button class="btn btn-light" @click="resetFilters()">
|
|
198
|
+
Reset
|
|
199
|
+
</button>
|
|
200
|
+
<button class="btn btn-info" @click="onChangeFilter($event)">
|
|
201
|
+
Filtrar
|
|
202
|
+
</button>
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
</template>
|
|
206
|
+
|
|
207
|
+
<script>
|
|
208
|
+
// Componente funcional para renderizar filtros custom con callback
|
|
209
|
+
const RenderCustomFilter = {
|
|
210
|
+
functional: true,
|
|
211
|
+
props: {
|
|
212
|
+
renderFunction: {
|
|
213
|
+
type: Function,
|
|
214
|
+
required: true
|
|
215
|
+
},
|
|
216
|
+
customFilter: {
|
|
217
|
+
type: Object,
|
|
218
|
+
required: true
|
|
219
|
+
},
|
|
220
|
+
filter: {
|
|
221
|
+
type: Array,
|
|
222
|
+
default: () => []
|
|
223
|
+
},
|
|
224
|
+
internalFilterByProp: {
|
|
225
|
+
type: Function,
|
|
226
|
+
required: true
|
|
227
|
+
},
|
|
228
|
+
getFilterForColumn: {
|
|
229
|
+
type: Function,
|
|
230
|
+
required: true
|
|
231
|
+
},
|
|
232
|
+
onChangeFilter: {
|
|
233
|
+
type: Function,
|
|
234
|
+
required: true
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
render(h, context) {
|
|
238
|
+
const { renderFunction, customFilter, filter, internalFilterByProp, getFilterForColumn, onChangeFilter } = context.props;
|
|
239
|
+
return renderFunction(h, {
|
|
240
|
+
column: customFilter,
|
|
241
|
+
filter: filter,
|
|
242
|
+
internalFilterByProp: internalFilterByProp,
|
|
243
|
+
getFilterForColumn: getFilterForColumn,
|
|
244
|
+
onChangeFilter: onChangeFilter
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
export default {
|
|
250
|
+
name: 'CrudFilters',
|
|
251
|
+
components: {
|
|
252
|
+
RenderCustomFilter
|
|
253
|
+
},
|
|
254
|
+
inject: [
|
|
255
|
+
'columns',
|
|
256
|
+
'customFilters',
|
|
257
|
+
'isColumnHasFilter',
|
|
258
|
+
'isCustomFilterEnabled',
|
|
259
|
+
'filter',
|
|
260
|
+
'internalFilterByProp',
|
|
261
|
+
'optionsLoaded',
|
|
262
|
+
'onChangeFilter',
|
|
263
|
+
'resetFilters',
|
|
264
|
+
'setupFilters',
|
|
265
|
+
'internalFilters'
|
|
266
|
+
],
|
|
267
|
+
methods: {
|
|
268
|
+
// Método helper para obtener el filtro de forma segura, creándolo si no existe
|
|
269
|
+
getFilterForColumn(column) {
|
|
270
|
+
let filter = this.internalFilterByProp(column.prop);
|
|
271
|
+
|
|
272
|
+
// Si el filtro no existe, intentar inicializar los filtros
|
|
273
|
+
if (!filter) {
|
|
274
|
+
// Verificar si hay filtros inicializados
|
|
275
|
+
if (this.internalFilters && this.internalFilters.length === 0) {
|
|
276
|
+
this.setupFilters();
|
|
277
|
+
// Intentar obtener el filtro nuevamente después de inicializar
|
|
278
|
+
filter = this.internalFilterByProp(column.prop);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Si aún no existe, crear un objeto temporal para evitar errores
|
|
283
|
+
if (!filter) {
|
|
284
|
+
return {
|
|
285
|
+
value: null
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return filter;
|
|
290
|
+
},
|
|
291
|
+
|
|
292
|
+
// Método helper específico para campos de fecha (from)
|
|
293
|
+
getFilterForDateFrom(column) {
|
|
294
|
+
const filter = this.internalFilterByProp(column.prop + '_from');
|
|
295
|
+
if (!filter) {
|
|
296
|
+
if (this.internalFilters && this.internalFilters.length === 0) {
|
|
297
|
+
this.setupFilters();
|
|
298
|
+
return this.internalFilterByProp(column.prop + '_from') || { value: null };
|
|
299
|
+
}
|
|
300
|
+
return { value: null };
|
|
301
|
+
}
|
|
302
|
+
return filter;
|
|
303
|
+
},
|
|
304
|
+
|
|
305
|
+
// Método helper específico para campos de fecha (to)
|
|
306
|
+
getFilterForDateTo(column) {
|
|
307
|
+
const filter = this.internalFilterByProp(column.prop + '_to');
|
|
308
|
+
if (!filter) {
|
|
309
|
+
if (this.internalFilters && this.internalFilters.length === 0) {
|
|
310
|
+
this.setupFilters();
|
|
311
|
+
return this.internalFilterByProp(column.prop + '_to') || { value: null };
|
|
312
|
+
}
|
|
313
|
+
return { value: null };
|
|
314
|
+
}
|
|
315
|
+
return filter;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
</script>
|