vue-laravel-crud 2.0.1 → 2.0.5
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/README.md +344 -148
- package/dist/vue-laravel-crud.esm.js +363 -124
- package/dist/vue-laravel-crud.min.js +3 -3
- package/dist/vue-laravel-crud.ssr.js +402 -143
- package/package.json +5 -2
- package/src/ItemCard.vue +23 -1
- package/src/components/CrudCards.vue +5 -1
- package/src/components/CrudFilters.vue +95 -32
- package/src/components/CrudPagination.vue +87 -20
- package/src/components/kanban/KanbanBoard.vue +4 -0
- package/src/components/kanban/KanbanCard.vue +23 -1
- package/src/components/kanban/KanbanColumn.vue +5 -1
- package/src/components/table/TableCell.vue +81 -6
- package/src/components/table/TableHeader.vue +54 -24
- package/src/vue-laravel-crud.vue +697 -688
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vue-laravel-crud",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "",
|
|
6
6
|
"homepage": "https://github.com/clonixdev/vue-laravel-crud",
|
|
@@ -21,7 +21,9 @@
|
|
|
21
21
|
"build": "cross-env NODE_ENV=production rollup --config build/rollup.config.js",
|
|
22
22
|
"build:ssr": "cross-env NODE_ENV=production rollup --config build/rollup.config.js --format cjs",
|
|
23
23
|
"build:es": "cross-env NODE_ENV=production rollup --config build/rollup.config.js --format es",
|
|
24
|
-
"build:unpkg": "cross-env NODE_ENV=production rollup --config build/rollup.config.js --format iife"
|
|
24
|
+
"build:unpkg": "cross-env NODE_ENV=production rollup --config build/rollup.config.js --format iife",
|
|
25
|
+
"build:demo": "cross-env NODE_ENV=production vue-cli-service build --mode production dev/demo/main.js",
|
|
26
|
+
"build:gh-pages": "npm run build:demo"
|
|
25
27
|
},
|
|
26
28
|
"dependencies": {
|
|
27
29
|
"axios": "^1.3.5",
|
|
@@ -51,6 +53,7 @@
|
|
|
51
53
|
"cors": "^2.8.5",
|
|
52
54
|
"cross-env": "^7.0.3",
|
|
53
55
|
"express": "^4.18.2",
|
|
56
|
+
"marked": "^4.3.0",
|
|
54
57
|
"minimist": "^1.2.5",
|
|
55
58
|
"node-sass": "^8.0.0",
|
|
56
59
|
"rollup": "^2.68.0",
|
package/src/ItemCard.vue
CHANGED
|
@@ -15,7 +15,19 @@
|
|
|
15
15
|
{{ itemValue(column, item) }}
|
|
16
16
|
</span>
|
|
17
17
|
<span v-else-if="column.type === 'state'">
|
|
18
|
-
|
|
18
|
+
<template v-if="getStateOptionsForColumn(column, item).length > 0">
|
|
19
|
+
<b-badge
|
|
20
|
+
v-for="(option, optIndex) in getStateOptionsForColumn(column, item)"
|
|
21
|
+
:key="optIndex"
|
|
22
|
+
:variant="getStateBadgeVariant(option)"
|
|
23
|
+
class="mr-1"
|
|
24
|
+
>
|
|
25
|
+
{{ option.text }}
|
|
26
|
+
</b-badge>
|
|
27
|
+
</template>
|
|
28
|
+
<span v-else>
|
|
29
|
+
{{ itemValue(column, item) }}
|
|
30
|
+
</span>
|
|
19
31
|
</span>
|
|
20
32
|
<span v-else-if="column.type === 'array'">
|
|
21
33
|
{{ getArrayValue(itemValue(column, item), column.displayProp, column.options) }}
|
|
@@ -55,11 +67,21 @@
|
|
|
55
67
|
cardHideFooter: Boolean,
|
|
56
68
|
itemValue: Function,
|
|
57
69
|
getStateValue: Function,
|
|
70
|
+
getStateOptions: Function,
|
|
71
|
+
getStateBadgeVariant: Function,
|
|
58
72
|
getArrayValue: Function,
|
|
59
73
|
showItem: Function,
|
|
60
74
|
updateItem: Function,
|
|
61
75
|
removeItem: Function,
|
|
62
76
|
},
|
|
77
|
+
methods: {
|
|
78
|
+
getStateOptionsForColumn(column, item) {
|
|
79
|
+
if (column.type === 'state' && column.options) {
|
|
80
|
+
return this.getStateOptions(this.itemValue(column, item), column.options);
|
|
81
|
+
}
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
63
85
|
};
|
|
64
86
|
</script>
|
|
65
87
|
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
:cardClass="cardClass"
|
|
25
25
|
:cardHideFooter="cardHideFooter"
|
|
26
26
|
:itemValue="itemValue"
|
|
27
|
-
:getStateValue="getStateValue"
|
|
27
|
+
:getStateValue="getStateValue"
|
|
28
|
+
:getStateOptions="getStateOptions"
|
|
29
|
+
:getStateBadgeVariant="getStateBadgeVariant"
|
|
28
30
|
:getArrayValue="getArrayValue"
|
|
29
31
|
:showItem="showItem"
|
|
30
32
|
:updateItem="updateItem"
|
|
@@ -74,6 +76,8 @@ export default {
|
|
|
74
76
|
'cardHideFooter',
|
|
75
77
|
'itemValue',
|
|
76
78
|
'getStateValue',
|
|
79
|
+
'getStateOptions',
|
|
80
|
+
'getStateBadgeVariant',
|
|
77
81
|
'getArrayValue',
|
|
78
82
|
'showItem',
|
|
79
83
|
'updateItem',
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
<div v-for="(column, indexc) in columns" :key="indexc">
|
|
4
4
|
<div v-if="isColumnHasFilter(column)">
|
|
5
5
|
<slot :name="'sidebar-filter-' + column.prop" v-bind:column="column" v-bind:filter="filter"
|
|
6
|
-
v-bind:internalFilterByProp="internalFilterByProp" v-
|
|
6
|
+
v-bind:internalFilterByProp="internalFilterByProp" v-bind:getFilterForColumn="getFilterForColumn">
|
|
7
7
|
<div class="form-group" v-if="column.type == 'boolean'">
|
|
8
8
|
<label>{{ column.label }}</label>
|
|
9
9
|
|
|
10
|
-
<select class="form-control" v-model="
|
|
10
|
+
<select class="form-control" v-model="getFilterForColumn(column).value"
|
|
11
11
|
@change="onChangeFilter($event)">
|
|
12
12
|
<option value=""></option>
|
|
13
13
|
<option value="1">Sí</option>
|
|
@@ -17,31 +17,49 @@
|
|
|
17
17
|
<div class="form-group" v-else-if="column.type == 'date'">
|
|
18
18
|
<div class="row">
|
|
19
19
|
<div class="col-6">
|
|
20
|
-
<b-form-datepicker v-model="
|
|
20
|
+
<b-form-datepicker v-model="getFilterForDateFrom(column).value
|
|
21
21
|
" today-button reset-button close-button locale="es"></b-form-datepicker>
|
|
22
22
|
</div>
|
|
23
23
|
<div class="col-6">
|
|
24
|
-
<b-form-datepicker v-model="
|
|
24
|
+
<b-form-datepicker v-model="getFilterForDateTo(column).value
|
|
25
25
|
" today-button reset-button close-button locale="es"></b-form-datepicker>
|
|
26
26
|
</div>
|
|
27
27
|
</div>
|
|
28
28
|
</div>
|
|
29
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
|
+
|
|
30
54
|
<div class="form-group" v-else-if="column.type == 'state'">
|
|
31
55
|
<label>{{ column.label }}</label>
|
|
32
56
|
|
|
33
|
-
<select class="form-control" v-model="
|
|
34
|
-
@change="onChangeFilter($event)" v-if="
|
|
57
|
+
<select class="form-control" v-model="getFilterForColumn(column).value"
|
|
58
|
+
@change="onChangeFilter($event)" v-if="column.options && Array.isArray(column.options)">
|
|
35
59
|
<option value=""></option>
|
|
36
|
-
<option :value="option.
|
|
37
|
-
:key="option.
|
|
38
|
-
{{
|
|
39
|
-
option.text
|
|
40
|
-
? option.text
|
|
41
|
-
: option.label
|
|
42
|
-
? option.label
|
|
43
|
-
: ""
|
|
44
|
-
}}
|
|
60
|
+
<option :value="option.value" v-for="option in column.options"
|
|
61
|
+
:key="option.value || option.id">
|
|
62
|
+
{{ option.text }}
|
|
45
63
|
</option>
|
|
46
64
|
</select>
|
|
47
65
|
</div>
|
|
@@ -49,28 +67,20 @@
|
|
|
49
67
|
<div class="form-group" v-else-if="column.type == 'array'">
|
|
50
68
|
<label>{{ column.label }}</label>
|
|
51
69
|
|
|
52
|
-
<select class="form-control" v-model="
|
|
53
|
-
@change="onChangeFilter($event)" v-if="
|
|
70
|
+
<select class="form-control" v-model="getFilterForColumn(column).value"
|
|
71
|
+
@change="onChangeFilter($event)" v-if="column.options && Array.isArray(column.options)">
|
|
54
72
|
<option value=""></option>
|
|
55
|
-
<
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
option.text
|
|
60
|
-
? option.text
|
|
61
|
-
: option.label
|
|
62
|
-
? option.label
|
|
63
|
-
: ""
|
|
64
|
-
}}
|
|
65
|
-
</option>
|
|
66
|
-
</template>
|
|
73
|
+
<option :value="option.value" v-for="option in column.options"
|
|
74
|
+
:key="option.value || option.id">
|
|
75
|
+
{{ option.text }}
|
|
76
|
+
</option>
|
|
67
77
|
</select>
|
|
68
78
|
</div>
|
|
69
79
|
|
|
70
80
|
<div class="form-group" v-else>
|
|
71
81
|
<label>{{ column.label }}</label>
|
|
72
82
|
|
|
73
|
-
<input class="form-control" v-model.lazy="
|
|
83
|
+
<input class="form-control" v-model.lazy="getFilterForColumn(column).value"
|
|
74
84
|
@change="onChangeFilter($event)" />
|
|
75
85
|
</div>
|
|
76
86
|
</slot>
|
|
@@ -98,7 +108,60 @@ export default {
|
|
|
98
108
|
'internalFilterByProp',
|
|
99
109
|
'optionsLoaded',
|
|
100
110
|
'onChangeFilter',
|
|
101
|
-
'resetFilters'
|
|
102
|
-
|
|
111
|
+
'resetFilters',
|
|
112
|
+
'setupFilters',
|
|
113
|
+
'internalFilters'
|
|
114
|
+
],
|
|
115
|
+
methods: {
|
|
116
|
+
// Método helper para obtener el filtro de forma segura, creándolo si no existe
|
|
117
|
+
getFilterForColumn(column) {
|
|
118
|
+
let filter = this.internalFilterByProp(column.prop);
|
|
119
|
+
|
|
120
|
+
// Si el filtro no existe, intentar inicializar los filtros
|
|
121
|
+
if (!filter) {
|
|
122
|
+
// Verificar si hay filtros inicializados
|
|
123
|
+
if (this.internalFilters && this.internalFilters.length === 0) {
|
|
124
|
+
this.setupFilters();
|
|
125
|
+
// Intentar obtener el filtro nuevamente después de inicializar
|
|
126
|
+
filter = this.internalFilterByProp(column.prop);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Si aún no existe, crear un objeto temporal para evitar errores
|
|
131
|
+
if (!filter) {
|
|
132
|
+
return {
|
|
133
|
+
value: null
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return filter;
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
// Método helper específico para campos de fecha (from)
|
|
141
|
+
getFilterForDateFrom(column) {
|
|
142
|
+
const filter = this.internalFilterByProp(column.prop + '_from');
|
|
143
|
+
if (!filter) {
|
|
144
|
+
if (this.internalFilters && this.internalFilters.length === 0) {
|
|
145
|
+
this.setupFilters();
|
|
146
|
+
return this.internalFilterByProp(column.prop + '_from') || { value: null };
|
|
147
|
+
}
|
|
148
|
+
return { value: null };
|
|
149
|
+
}
|
|
150
|
+
return filter;
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
// Método helper específico para campos de fecha (to)
|
|
154
|
+
getFilterForDateTo(column) {
|
|
155
|
+
const filter = this.internalFilterByProp(column.prop + '_to');
|
|
156
|
+
if (!filter) {
|
|
157
|
+
if (this.internalFilters && this.internalFilters.length === 0) {
|
|
158
|
+
this.setupFilters();
|
|
159
|
+
return this.internalFilterByProp(column.prop + '_to') || { value: null };
|
|
160
|
+
}
|
|
161
|
+
return { value: null };
|
|
162
|
+
}
|
|
163
|
+
return filter;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
103
166
|
};
|
|
104
167
|
</script>
|
|
@@ -26,18 +26,33 @@
|
|
|
26
26
|
<span class="paginator-label">Filas:</span>
|
|
27
27
|
<span class="paginator-value">{{ pagination.total }}</span>
|
|
28
28
|
</span>
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
29
|
+
<b-dropdown
|
|
30
|
+
variant="outline-secondary"
|
|
31
|
+
size="sm"
|
|
32
|
+
class="paginator-dropdown"
|
|
33
|
+
:text="`xPág: ${pagination.per_page}`"
|
|
34
|
+
>
|
|
35
|
+
<b-dropdown-item
|
|
36
|
+
v-for="option in perPageOptions"
|
|
37
|
+
:key="option"
|
|
38
|
+
@click="onPerPageChange(option)"
|
|
39
|
+
:active="pagination.per_page === option"
|
|
40
|
+
>
|
|
41
|
+
{{ option }}
|
|
42
|
+
</b-dropdown-item>
|
|
43
|
+
</b-dropdown>
|
|
44
|
+
<b-dropdown
|
|
45
|
+
v-if="selectedItemsCount > 0"
|
|
46
|
+
variant="outline-secondary"
|
|
47
|
+
size="sm"
|
|
48
|
+
class="paginator-dropdown paginator-badge-dropdown"
|
|
49
|
+
:text="`Seleccionados: ${selectedItemsCount}`"
|
|
50
|
+
>
|
|
51
|
+
<b-dropdown-item @click="clearSelection">
|
|
52
|
+
<b-icon-x-circle class="mr-1"></b-icon-x-circle>
|
|
53
|
+
Limpiar selección
|
|
54
|
+
</b-dropdown-item>
|
|
55
|
+
</b-dropdown>
|
|
41
56
|
</div>
|
|
42
57
|
|
|
43
58
|
<div class="crud-paginator">
|
|
@@ -73,28 +88,42 @@ export default {
|
|
|
73
88
|
'selectedItems',
|
|
74
89
|
'showPaginator',
|
|
75
90
|
'infiniteHandler',
|
|
76
|
-
'onPaginationChange'
|
|
77
|
-
|
|
91
|
+
'onPaginationChange',
|
|
92
|
+
'onPerPageChange',
|
|
93
|
+
'clearSelection'
|
|
94
|
+
],
|
|
95
|
+
data() {
|
|
96
|
+
return {
|
|
97
|
+
perPageOptions: [10, 20, 50, 100]
|
|
98
|
+
};
|
|
99
|
+
},
|
|
100
|
+
computed: {
|
|
101
|
+
selectedItemsCount() {
|
|
102
|
+
// Computed para forzar reactividad del contador
|
|
103
|
+
return this.selectedItems ? this.selectedItems.length : 0;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
78
106
|
};
|
|
79
107
|
</script>
|
|
80
108
|
|
|
81
109
|
<style scoped>
|
|
82
110
|
.paginator-container {
|
|
83
|
-
display:
|
|
84
|
-
|
|
111
|
+
display: grid;
|
|
112
|
+
grid-template-columns: 1fr auto 1fr;
|
|
85
113
|
align-items: center;
|
|
86
114
|
width: 100%;
|
|
87
115
|
margin-top: 1rem;
|
|
88
|
-
gap:
|
|
116
|
+
gap: 1rem;
|
|
89
117
|
}
|
|
90
118
|
|
|
91
119
|
.paginator-data {
|
|
92
120
|
display: flex;
|
|
93
|
-
flex-wrap:
|
|
94
|
-
justify-content:
|
|
121
|
+
flex-wrap: nowrap;
|
|
122
|
+
justify-content: flex-start;
|
|
95
123
|
align-items: center;
|
|
96
124
|
gap: 0.5rem;
|
|
97
125
|
font-size: 0.875rem;
|
|
126
|
+
grid-column: 1;
|
|
98
127
|
}
|
|
99
128
|
|
|
100
129
|
.paginator-badge {
|
|
@@ -124,10 +153,48 @@ export default {
|
|
|
124
153
|
color: #212529;
|
|
125
154
|
}
|
|
126
155
|
|
|
156
|
+
.paginator-dropdown {
|
|
157
|
+
font-size: 0.875rem;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.paginator-dropdown >>> .btn {
|
|
161
|
+
padding: 0.375rem 0.625rem;
|
|
162
|
+
font-size: 0.875rem;
|
|
163
|
+
background-color: #f8f9fa;
|
|
164
|
+
border: 1px solid #dee2e6;
|
|
165
|
+
color: #495057;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.paginator-dropdown >>> .btn:hover {
|
|
169
|
+
background-color: #e9ecef;
|
|
170
|
+
border-color: #ced4da;
|
|
171
|
+
}
|
|
172
|
+
|
|
127
173
|
.crud-paginator {
|
|
128
174
|
display: flex;
|
|
129
175
|
justify-content: center;
|
|
130
176
|
align-items: center;
|
|
131
|
-
|
|
177
|
+
grid-column: 2;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.paginator-badge-dropdown {
|
|
181
|
+
z-index: 1;
|
|
182
|
+
position: relative;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.paginator-badge-dropdown >>> .btn {
|
|
186
|
+
padding: 0.375rem 0.625rem;
|
|
187
|
+
font-size: 0.875rem;
|
|
188
|
+
background-color: #f8f9fa;
|
|
189
|
+
border: 1px solid #dee2e6;
|
|
190
|
+
color: #495057;
|
|
191
|
+
display: inline-flex;
|
|
192
|
+
align-items: center;
|
|
193
|
+
gap: 0.25rem;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.paginator-badge-dropdown >>> .btn:hover {
|
|
197
|
+
background-color: #e9ecef;
|
|
198
|
+
border-color: #ced4da;
|
|
132
199
|
}
|
|
133
200
|
</style>
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
:columns="columns"
|
|
9
9
|
:itemValue="itemValue"
|
|
10
10
|
:getStateValue="getStateValue"
|
|
11
|
+
:getStateOptions="getStateOptions"
|
|
12
|
+
:getStateBadgeVariant="getStateBadgeVariant"
|
|
11
13
|
:getArrayValue="getArrayValue"
|
|
12
14
|
:showItem="showItem"
|
|
13
15
|
:updateItem="updateItem"
|
|
@@ -34,6 +36,8 @@ export default {
|
|
|
34
36
|
'columns',
|
|
35
37
|
'itemValue',
|
|
36
38
|
'getStateValue',
|
|
39
|
+
'getStateOptions',
|
|
40
|
+
'getStateBadgeVariant',
|
|
37
41
|
'getArrayValue',
|
|
38
42
|
'showItem',
|
|
39
43
|
'updateItem',
|
|
@@ -22,7 +22,19 @@
|
|
|
22
22
|
{{ itemValue(column, item) }}
|
|
23
23
|
</span>
|
|
24
24
|
<span v-else-if="column.type === 'state'">
|
|
25
|
-
|
|
25
|
+
<template v-if="getStateOptionsForColumn(column, item).length > 0">
|
|
26
|
+
<b-badge
|
|
27
|
+
v-for="(option, optIndex) in getStateOptionsForColumn(column, item)"
|
|
28
|
+
:key="optIndex"
|
|
29
|
+
:variant="getStateBadgeVariant(option)"
|
|
30
|
+
class="mr-1"
|
|
31
|
+
>
|
|
32
|
+
{{ option.text }}
|
|
33
|
+
</b-badge>
|
|
34
|
+
</template>
|
|
35
|
+
<span v-else>
|
|
36
|
+
{{ itemValue(column, item) }}
|
|
37
|
+
</span>
|
|
26
38
|
</span>
|
|
27
39
|
<span v-else-if="column.type === 'array'">
|
|
28
40
|
{{ getArrayValue(itemValue(column, item), column.displayProp, column.options) }}
|
|
@@ -61,10 +73,20 @@ export default {
|
|
|
61
73
|
cardHideFooter: Boolean,
|
|
62
74
|
itemValue: Function,
|
|
63
75
|
getStateValue: Function,
|
|
76
|
+
getStateOptions: Function,
|
|
77
|
+
getStateBadgeVariant: Function,
|
|
64
78
|
getArrayValue: Function,
|
|
65
79
|
showItem: Function,
|
|
66
80
|
updateItem: Function,
|
|
67
81
|
removeItem: Function,
|
|
82
|
+
},
|
|
83
|
+
methods: {
|
|
84
|
+
getStateOptionsForColumn(column, item) {
|
|
85
|
+
if (column.type === 'state' && column.options) {
|
|
86
|
+
return this.getStateOptions(this.itemValue(column, item), column.options);
|
|
87
|
+
}
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
68
90
|
}
|
|
69
91
|
};
|
|
70
92
|
</script>
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
:cardClass="cardClass"
|
|
25
25
|
:cardHideFooter="cardHideFooter"
|
|
26
26
|
:itemValue="itemValue"
|
|
27
|
-
:getStateValue="getStateValue"
|
|
27
|
+
:getStateValue="getStateValue"
|
|
28
|
+
:getStateOptions="getStateOptions"
|
|
29
|
+
:getStateBadgeVariant="getStateBadgeVariant"
|
|
28
30
|
:getArrayValue="getArrayValue"
|
|
29
31
|
:showItem="showItem"
|
|
30
32
|
:updateItem="updateItem"
|
|
@@ -53,6 +55,8 @@ export default {
|
|
|
53
55
|
columns: Array,
|
|
54
56
|
itemValue: Function,
|
|
55
57
|
getStateValue: Function,
|
|
58
|
+
getStateOptions: Function,
|
|
59
|
+
getStateBadgeVariant: Function,
|
|
56
60
|
getArrayValue: Function,
|
|
57
61
|
showItem: Function,
|
|
58
62
|
updateItem: Function,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<td :scope="column.prop == 'id' ? 'row' : ''"
|
|
2
|
+
<td :scope="column.prop == 'id' ? 'row' : ''"
|
|
3
|
+
:class="{ 'actions-cell': column.type == 'actions' }">
|
|
3
4
|
<slot :name="'cell-' + column.prop" v-bind:item="item" v-bind:index="index" v-bind:itemindex="index"
|
|
4
5
|
v-bind:columnindex="columnIndex">
|
|
5
6
|
<span v-if="column.type == 'boolean'">
|
|
@@ -25,10 +26,24 @@
|
|
|
25
26
|
<b-form-checkbox v-model="item.selected" @change="onCheckSelect($event, item)">
|
|
26
27
|
</b-form-checkbox>
|
|
27
28
|
</span>
|
|
28
|
-
<span v-else-if="column.type == '
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
<span v-else-if="column.type == 'checkbox'">
|
|
30
|
+
<b-form-checkbox v-model="item.selected" @change="onCheckSelect($event, item)">
|
|
31
|
+
</b-form-checkbox>
|
|
32
|
+
</span>
|
|
33
|
+
<span v-else-if="column.type == 'state'">
|
|
34
|
+
<template v-if="stateOptions.length > 0">
|
|
35
|
+
<b-badge
|
|
36
|
+
v-for="(option, optIndex) in stateOptions"
|
|
37
|
+
:key="optIndex"
|
|
38
|
+
:variant="getStateBadgeVariant(option)"
|
|
39
|
+
class="mr-1"
|
|
40
|
+
>
|
|
41
|
+
{{ option.text }}
|
|
42
|
+
</b-badge>
|
|
43
|
+
</template>
|
|
44
|
+
<span v-else>
|
|
45
|
+
{{ itemValue(column, item) }}
|
|
46
|
+
</span>
|
|
32
47
|
</span>
|
|
33
48
|
<span v-else-if="column.type == 'array' && optionsLoaded">
|
|
34
49
|
{{
|
|
@@ -40,11 +55,35 @@
|
|
|
40
55
|
}}
|
|
41
56
|
</span>
|
|
42
57
|
<span v-else>
|
|
58
|
+
|
|
43
59
|
{{ itemValue(column, item) }}
|
|
44
60
|
</span>
|
|
45
61
|
</slot>
|
|
46
62
|
|
|
47
|
-
|
|
63
|
+
<!-- Modo dropdown cuando useDropdown está activo -->
|
|
64
|
+
<b-dropdown v-if="column.type == 'actions' && column.useDropdown"
|
|
65
|
+
variant="secondary"
|
|
66
|
+
size="sm"
|
|
67
|
+
class="actions-dropdown">
|
|
68
|
+
<template #button-content>
|
|
69
|
+
<b-icon-list></b-icon-list>
|
|
70
|
+
</template>
|
|
71
|
+
<slot name="rowAction" v-bind:item="item" v-bind:index="index" v-bind:showItem="showItem"
|
|
72
|
+
v-bind:updateItem="updateItem" v-bind:removeItem="removeItem">
|
|
73
|
+
<b-dropdown-item @click="showItem(item.id, index)">
|
|
74
|
+
<b-icon-eye></b-icon-eye> Ver
|
|
75
|
+
</b-dropdown-item>
|
|
76
|
+
<b-dropdown-item @click="updateItem(item.id, index)">
|
|
77
|
+
<b-icon-pencil></b-icon-pencil> Editar
|
|
78
|
+
</b-dropdown-item>
|
|
79
|
+
<b-dropdown-item @click="removeItem(item.id, index)" class="text-danger">
|
|
80
|
+
<b-icon-trash></b-icon-trash> Eliminar
|
|
81
|
+
</b-dropdown-item>
|
|
82
|
+
</slot>
|
|
83
|
+
</b-dropdown>
|
|
84
|
+
|
|
85
|
+
<!-- Modo botones normal (comportamiento original) -->
|
|
86
|
+
<b-button-group v-else-if="column.type == 'actions'" class="actions-button-group">
|
|
48
87
|
<slot name="rowAction" v-bind:item="item" v-bind:index="index" v-bind:showItem="showItem"
|
|
49
88
|
v-bind:updateItem="updateItem" v-bind:removeItem="removeItem">
|
|
50
89
|
<b-button variant="primary" @click="showItem(item.id, index)">
|
|
@@ -75,6 +114,8 @@ export default {
|
|
|
75
114
|
inject: [
|
|
76
115
|
'itemValue',
|
|
77
116
|
'getStateValue',
|
|
117
|
+
'getStateOptions',
|
|
118
|
+
'getStateBadgeVariant',
|
|
78
119
|
'getArrayValue',
|
|
79
120
|
'onCheckSelect',
|
|
80
121
|
'showItem',
|
|
@@ -86,6 +127,40 @@ export default {
|
|
|
86
127
|
return {
|
|
87
128
|
moment: moment
|
|
88
129
|
};
|
|
130
|
+
},
|
|
131
|
+
computed: {
|
|
132
|
+
stateOptions() {
|
|
133
|
+
// Permitir usar opciones incluso si optionsLoaded es false, ya que getStateOptions normaliza internamente
|
|
134
|
+
if (this.column.type === 'state' && this.column.options && Array.isArray(this.column.options)) {
|
|
135
|
+
const itemVal = this.itemValue(this.column, this.item);
|
|
136
|
+
const options = this.column.options;
|
|
137
|
+
const result = this.getStateOptions(itemVal, options);
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
89
142
|
}
|
|
90
143
|
};
|
|
91
144
|
</script>
|
|
145
|
+
|
|
146
|
+
<style scoped>
|
|
147
|
+
/* Fijar ancho de la columna de acciones */
|
|
148
|
+
.actions-cell {
|
|
149
|
+
width: 1%;
|
|
150
|
+
white-space: nowrap;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.actions-button-group {
|
|
154
|
+
display: inline-flex;
|
|
155
|
+
flex-wrap: nowrap;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.actions-dropdown {
|
|
159
|
+
display: inline-block;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* Asegurar que los botones no se expandan */
|
|
163
|
+
.actions-button-group .btn {
|
|
164
|
+
flex-shrink: 0;
|
|
165
|
+
}
|
|
166
|
+
</style>
|