quasar-ui-sellmate-ui-kit 3.14.0 → 3.14.2
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/index.common.js +2 -2
- package/dist/index.css +1 -1
- package/dist/index.esm.js +2 -2
- package/dist/index.min.css +1 -1
- package/dist/index.rtl.css +1 -1
- package/dist/index.rtl.min.css +1 -1
- package/dist/index.umd.js +193 -226
- package/dist/index.umd.min.js +2 -2
- package/package.json +1 -1
- package/src/components/SSelectSearchCheckbox.vue +188 -204
- package/src/components/STable.vue +7 -3
- package/src/css/extends.scss +176 -176
package/package.json
CHANGED
|
@@ -9,18 +9,13 @@
|
|
|
9
9
|
multiple
|
|
10
10
|
emit-value
|
|
11
11
|
map-options
|
|
12
|
+
autocomplete="country"
|
|
12
13
|
color="positive"
|
|
13
|
-
:popup-content-class="
|
|
14
|
-
[
|
|
15
|
-
's-select-checkbox-opts',
|
|
16
|
-
idClass,
|
|
17
|
-
isScrolled && 's-select-opts--scroll',
|
|
18
|
-
popupContentClass,
|
|
19
|
-
].join(' ')
|
|
20
|
-
"
|
|
14
|
+
:popup-content-class="['s-select-checkbox-opts', popupContentClass].join(' ')"
|
|
21
15
|
class="s-select-checkbox"
|
|
22
16
|
:option-label="optionLabel"
|
|
23
17
|
:option-value="optionValue"
|
|
18
|
+
:option-group="optionGroup"
|
|
24
19
|
@add="onAddChecked"
|
|
25
20
|
@remove="onRemoveChecked"
|
|
26
21
|
:menu-offset="[0, 4]"
|
|
@@ -29,22 +24,24 @@
|
|
|
29
24
|
no-error-icon
|
|
30
25
|
hide-bottom-space
|
|
31
26
|
ref="sSelectRef"
|
|
32
|
-
@popup-show="handleScroll"
|
|
33
|
-
@popup-hide="removeScroll"
|
|
34
27
|
>
|
|
28
|
+
<!-- TODO: 아무것도 선택되지 않았을 때 props 값으로 표기 해줘야함 기본 값은 "전체" -->
|
|
35
29
|
<template #before-options>
|
|
36
30
|
<div class="search-input-form-container">
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
31
|
+
<form class="select-search-input-form">
|
|
32
|
+
<q-icon :name="searchIcon" size="20px" />
|
|
33
|
+
<input
|
|
34
|
+
v-model="search"
|
|
35
|
+
autofocus
|
|
36
|
+
class="select-search-input"
|
|
37
|
+
:placeholder="searchPlaceholder"
|
|
38
|
+
@input="
|
|
39
|
+
data => {
|
|
40
|
+
onSearch(data.target.value);
|
|
41
|
+
}
|
|
42
|
+
"
|
|
43
|
+
/>
|
|
44
|
+
</form>
|
|
48
45
|
</div>
|
|
49
46
|
</template>
|
|
50
47
|
<template #option="{ itemProps, opt, selected, toggleOption }">
|
|
@@ -52,59 +49,70 @@
|
|
|
52
49
|
<q-item-section side v-if="!opt.disable">
|
|
53
50
|
<s-checkbox :modelValue="selected" @update:modelValue="toggleOption(opt)" />
|
|
54
51
|
</q-item-section>
|
|
52
|
+
<q-item-section v-if="opt[optionGroup]" class="text-Grey_Darken-4">
|
|
53
|
+
{{ opt[optionGroup] }}
|
|
54
|
+
</q-item-section>
|
|
55
55
|
<q-item-section avatar v-if="opt.logo">
|
|
56
|
-
<q-img class="q-pa-none bg-
|
|
56
|
+
<q-img class="q-pa-none bg-Grey_Lighten-5" :src="opt.logo" width="60px" height="22px" />
|
|
57
57
|
</q-item-section>
|
|
58
58
|
<q-item-section>
|
|
59
59
|
{{ opt[optionLabel] }}
|
|
60
60
|
</q-item-section>
|
|
61
61
|
</q-item>
|
|
62
62
|
</template>
|
|
63
|
-
<template
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
<template
|
|
64
|
+
v-if="
|
|
65
|
+
(options.length && useAll && (model[0] === '' || model.includes(''))) ||
|
|
66
|
+
(noSelected && !options.length)
|
|
67
|
+
"
|
|
68
|
+
#selected
|
|
69
|
+
>
|
|
70
|
+
<div v-if="noSelected && !options.length">{{ noSelected }}</div>
|
|
71
|
+
<div v-else-if="options.length && useAll && (model[0] === '' || model.includes(''))">
|
|
72
|
+
{{ placeholder }}
|
|
66
73
|
</div>
|
|
67
74
|
</template>
|
|
68
|
-
|
|
69
75
|
<template #no-option>
|
|
70
76
|
<div class="search-input-form-container">
|
|
71
|
-
<
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
<form class="select-search-input-form">
|
|
78
|
+
<q-icon :name="searchIcon" size="20px" />
|
|
79
|
+
<input
|
|
80
|
+
v-model="search"
|
|
81
|
+
autofocus
|
|
82
|
+
class="select-search-input"
|
|
83
|
+
:placeholder="searchPlaceholder"
|
|
84
|
+
@input="
|
|
85
|
+
data => {
|
|
86
|
+
onSearch(data.target.value);
|
|
87
|
+
}
|
|
88
|
+
"
|
|
89
|
+
/>
|
|
90
|
+
</form>
|
|
82
91
|
</div>
|
|
83
92
|
<q-item class="s-select-no-option">
|
|
84
|
-
<q-item-section class="text-grey">{{
|
|
93
|
+
<q-item-section class="text-grey">{{ noData }}</q-item-section>
|
|
85
94
|
</q-item>
|
|
86
95
|
</template>
|
|
87
96
|
</q-select>
|
|
88
97
|
</template>
|
|
89
98
|
|
|
90
99
|
<script>
|
|
91
|
-
import {
|
|
92
|
-
import {
|
|
93
|
-
import { selectDownArrowIcon } from '../assets/icons';
|
|
94
|
-
import InputWithSearchIcon from './InputWithSearchIcon.vue';
|
|
100
|
+
import { QIcon, QImg, QItem, QItemSection, QSelect, debounce } from 'quasar';
|
|
101
|
+
import { defineComponent, nextTick, onBeforeMount, ref, watch } from 'vue';
|
|
102
|
+
import { searchIcon, selectDownArrowIcon } from '../assets/icons';
|
|
95
103
|
|
|
96
104
|
export default defineComponent({
|
|
97
|
-
name: '
|
|
98
|
-
emits: ['update:modelValue'
|
|
105
|
+
name: 'SSelectSearchCheckbox',
|
|
106
|
+
emits: ['update:modelValue'],
|
|
99
107
|
components: {
|
|
100
108
|
QSelect,
|
|
101
109
|
QItem,
|
|
102
110
|
QItemSection,
|
|
103
111
|
QImg,
|
|
104
|
-
|
|
112
|
+
QIcon,
|
|
105
113
|
},
|
|
106
114
|
props: {
|
|
107
|
-
searchPlaceholder: { type: String, default: '
|
|
115
|
+
searchPlaceholder: { type: String, default: '검색' },
|
|
108
116
|
options: {
|
|
109
117
|
type: Array,
|
|
110
118
|
required: true,
|
|
@@ -121,209 +129,144 @@
|
|
|
121
129
|
type: String,
|
|
122
130
|
default: 'value',
|
|
123
131
|
},
|
|
132
|
+
optionGroup: {
|
|
133
|
+
type: String,
|
|
134
|
+
default: 'group',
|
|
135
|
+
},
|
|
124
136
|
useAll: {
|
|
125
137
|
type: Boolean,
|
|
126
138
|
default: false,
|
|
127
139
|
},
|
|
128
|
-
|
|
140
|
+
placeholder: {
|
|
129
141
|
type: String,
|
|
130
142
|
default: '전체',
|
|
131
143
|
},
|
|
144
|
+
checkboxSearch: {
|
|
145
|
+
type: String,
|
|
146
|
+
default: '',
|
|
147
|
+
},
|
|
148
|
+
noData: {
|
|
149
|
+
type: String,
|
|
150
|
+
default: '데이터 없음',
|
|
151
|
+
},
|
|
132
152
|
popupContentClass: {
|
|
133
|
-
default: () => '',
|
|
134
153
|
type: String,
|
|
135
154
|
},
|
|
136
|
-
|
|
155
|
+
noSelected: {
|
|
137
156
|
type: String,
|
|
138
|
-
default: '
|
|
157
|
+
default: '선택',
|
|
139
158
|
},
|
|
140
159
|
},
|
|
141
160
|
setup(props, { emit }) {
|
|
142
|
-
const NO_VALUE = ['', null];
|
|
143
|
-
const filteredOptions = ref(props.options);
|
|
144
|
-
const checkNoValue = value => NO_VALUE.includes(value);
|
|
145
161
|
const model = ref(props.modelValue);
|
|
162
|
+
const filteredOptions = ref(props.options);
|
|
163
|
+
const searchInput = ref(null);
|
|
164
|
+
const search = ref('');
|
|
165
|
+
const isDisable = props.options.find(v => Boolean(v.disable));
|
|
146
166
|
|
|
167
|
+
/**
|
|
168
|
+
* @param {{ index: number; value: string | number }} detail
|
|
169
|
+
*/
|
|
147
170
|
function onRemoveChecked(detail) {
|
|
148
|
-
|
|
171
|
+
const idx = model.value.findIndex(v => v === '');
|
|
172
|
+
if (detail.value === '') {
|
|
149
173
|
nextTick(() => {
|
|
150
174
|
model.value = [];
|
|
151
175
|
});
|
|
152
|
-
} else if (
|
|
176
|
+
} else if (idx >= 0) {
|
|
153
177
|
nextTick(() => {
|
|
154
|
-
model.value
|
|
178
|
+
model.value.splice(idx, 1);
|
|
155
179
|
});
|
|
156
180
|
}
|
|
157
181
|
}
|
|
158
182
|
|
|
159
|
-
|
|
183
|
+
/**
|
|
184
|
+
* @param {{ index: number; value: string | number }} detail
|
|
185
|
+
*/
|
|
160
186
|
function onAddChecked(detail) {
|
|
161
|
-
if (
|
|
187
|
+
if (detail.value === '') {
|
|
162
188
|
nextTick(() => {
|
|
163
|
-
model.value =
|
|
189
|
+
model.value = props.options
|
|
190
|
+
.filter(v => !v.category)
|
|
191
|
+
.map(option => option[props.optionValue]);
|
|
164
192
|
});
|
|
165
193
|
} else {
|
|
166
194
|
nextTick(() => {
|
|
167
|
-
if (
|
|
168
|
-
model.value =
|
|
195
|
+
if (model.value.length === props.options.length - 1) {
|
|
196
|
+
model.value = props.options
|
|
197
|
+
.filter(v => !v.category)
|
|
198
|
+
.map(option => option[props.optionValue]);
|
|
169
199
|
}
|
|
170
200
|
});
|
|
171
201
|
}
|
|
172
202
|
}
|
|
173
203
|
|
|
174
|
-
|
|
175
|
-
if (
|
|
176
|
-
|
|
204
|
+
const onSearch = debounce(val => {
|
|
205
|
+
if (val === '') {
|
|
206
|
+
filteredOptions.value = props.options;
|
|
207
|
+
} else {
|
|
208
|
+
filteredOptions.value = props.options.filter(
|
|
209
|
+
v => (v[props.optionLabel] || v).toLowerCase().indexOf(val.toLowerCase()) > -1,
|
|
210
|
+
);
|
|
177
211
|
}
|
|
178
|
-
|
|
179
|
-
return opt !== 0 && !opt;
|
|
180
|
-
}
|
|
212
|
+
}, 200);
|
|
181
213
|
|
|
182
214
|
watch(
|
|
183
215
|
() => props.modelValue,
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
model.value = getOnlyValueArray();
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
model.value = newModelValue;
|
|
190
|
-
},
|
|
191
|
-
);
|
|
216
|
+
val => {
|
|
217
|
+
model.value = val;
|
|
192
218
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
model.value =
|
|
219
|
+
if (
|
|
220
|
+
props.options.filter(opt => opt[props.optionValue] && !opt.category).length ===
|
|
221
|
+
model.value.length &&
|
|
222
|
+
model.value.length
|
|
223
|
+
) {
|
|
224
|
+
model.value = props.options
|
|
225
|
+
.filter(v => !v.category)
|
|
226
|
+
.map(option => option[props.optionValue]);
|
|
199
227
|
}
|
|
200
228
|
},
|
|
201
229
|
);
|
|
202
230
|
|
|
203
|
-
watch(model,
|
|
204
|
-
emit('update:modelValue',
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
onBeforeMount(() => {
|
|
208
|
-
if (props.useAll && checkEmptyValue(props.modelValue[0])) {
|
|
209
|
-
model.value = getOnlyValueArray();
|
|
210
|
-
}
|
|
231
|
+
watch(model, val => {
|
|
232
|
+
emit('update:modelValue', val);
|
|
211
233
|
});
|
|
212
234
|
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
sSelectRef.value.moveOptionSelection(e.key === 'ArrowDown' ? 1 : -1, true);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
function handleInput(val) {
|
|
223
|
-
search.value = val;
|
|
224
|
-
sSelectRef.value.setOptionIndex(-1);
|
|
225
|
-
|
|
226
|
-
if (!val) {
|
|
227
|
-
filteredOptions.value = props.options;
|
|
228
|
-
sSelectRef.value.setOptionIndex(-1);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
function handleDelete() {
|
|
233
|
-
sSelectRef.value.setOptionIndex(-1);
|
|
234
|
-
search.value = '';
|
|
235
|
-
emit('onSearch', '');
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const onSearch = debounce(val => {
|
|
239
|
-
if (!val) {
|
|
240
|
-
filteredOptions.value = props.options;
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// 옵션을 선택 했을 때
|
|
245
|
-
if (sSelectRef.value.getOptionIndex() !== -1) {
|
|
246
|
-
const selectedValue =
|
|
247
|
-
filteredOptions.value[sSelectRef.value.getOptionIndex()][props.optionValue];
|
|
248
|
-
if (model.value.includes(selectedValue)) {
|
|
249
|
-
model.value = model.value.filter(v => !checkNoValue(v) && v !== selectedValue);
|
|
250
|
-
} else {
|
|
251
|
-
console.log('sdfsdf')
|
|
252
|
-
model.value.push(selectedValue);
|
|
253
|
-
}
|
|
254
|
-
handleDelete();
|
|
255
|
-
sSelectRef.value.setOptionIndex(-1);
|
|
256
|
-
sSelectRef.value.hidePopup();
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const filtered = props.options.filter(
|
|
261
|
-
v => (v[props.optionLabel] || v).toLowerCase().indexOf(val.toLowerCase()) > -1,
|
|
262
|
-
);
|
|
263
|
-
|
|
264
|
-
if (!filtered.length) {
|
|
265
|
-
emit('onSearch', val);
|
|
266
|
-
sSelectRef.value.setOptionIndex(-1);
|
|
267
|
-
return;
|
|
235
|
+
const allSelectedModel = () => {
|
|
236
|
+
if (props.useAll && model.value.filter(v => v).length < 1) {
|
|
237
|
+
model.value = props.options
|
|
238
|
+
.filter(v => !v[props.optionGroup])
|
|
239
|
+
.map(option => option[props.optionValue]);
|
|
268
240
|
}
|
|
269
|
-
|
|
270
|
-
filteredOptions.value = filtered;
|
|
271
|
-
}, 200);
|
|
272
|
-
|
|
273
|
-
const isScrolled = ref(false);
|
|
274
|
-
const id = useId();
|
|
275
|
-
const idClass = `s-select-checkbox-opt-${id.value}`;
|
|
276
|
-
let scrollTimeout = null;
|
|
277
|
-
const handleScroll = () => {
|
|
278
|
-
const selectOptsEl = document.getElementsByClassName(idClass);
|
|
279
|
-
nextTick(() => {
|
|
280
|
-
if (selectOptsEl[0]) {
|
|
281
|
-
selectOptsEl[0].addEventListener('scroll', () => {
|
|
282
|
-
isScrolled.value = true;
|
|
283
|
-
|
|
284
|
-
if (scrollTimeout) {
|
|
285
|
-
clearTimeout(scrollTimeout);
|
|
286
|
-
}
|
|
287
|
-
scrollTimeout = setTimeout(() => {
|
|
288
|
-
isScrolled.value = false;
|
|
289
|
-
}, 100); // 100ms 후 스크롤 멈춤으로 간주
|
|
290
|
-
});
|
|
291
|
-
}
|
|
292
|
-
});
|
|
293
241
|
};
|
|
294
242
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
243
|
+
watch(
|
|
244
|
+
() => props.options,
|
|
245
|
+
val => {
|
|
246
|
+
model.value = [];
|
|
247
|
+
filteredOptions.value = val;
|
|
248
|
+
nextTick(() => {
|
|
249
|
+
allSelectedModel();
|
|
250
|
+
});
|
|
251
|
+
},
|
|
252
|
+
);
|
|
303
253
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
});
|
|
308
|
-
};
|
|
254
|
+
onBeforeMount(() => {
|
|
255
|
+
allSelectedModel();
|
|
256
|
+
});
|
|
309
257
|
|
|
310
258
|
return {
|
|
311
259
|
model,
|
|
312
260
|
selectDownArrowIcon,
|
|
261
|
+
onRemoveChecked,
|
|
262
|
+
onAddChecked,
|
|
313
263
|
onSearch,
|
|
264
|
+
isDisable,
|
|
314
265
|
filteredOptions,
|
|
315
266
|
search,
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
idClass,
|
|
320
|
-
onRemoveChecked,
|
|
321
|
-
onAddChecked,
|
|
322
|
-
handleKey,
|
|
323
|
-
handleInput,
|
|
324
|
-
handleDelete,
|
|
325
|
-
handleScroll,
|
|
326
|
-
removeScroll,
|
|
267
|
+
searchInput,
|
|
268
|
+
searchIcon,
|
|
269
|
+
sSelectRef: ref(null),
|
|
327
270
|
};
|
|
328
271
|
},
|
|
329
272
|
});
|
|
@@ -335,6 +278,7 @@
|
|
|
335
278
|
|
|
336
279
|
.s-select-checkbox {
|
|
337
280
|
@extend %select;
|
|
281
|
+
|
|
338
282
|
.q-field__native {
|
|
339
283
|
display: block;
|
|
340
284
|
min-height: 0;
|
|
@@ -345,9 +289,11 @@
|
|
|
345
289
|
white-space: nowrap;
|
|
346
290
|
overflow: hidden;
|
|
347
291
|
text-overflow: ellipsis;
|
|
292
|
+
|
|
348
293
|
> span {
|
|
349
294
|
max-height: $default-height;
|
|
350
295
|
}
|
|
296
|
+
|
|
351
297
|
> .s-checkbox {
|
|
352
298
|
margin-right: $default-icon-margin;
|
|
353
299
|
}
|
|
@@ -356,21 +302,59 @@
|
|
|
356
302
|
|
|
357
303
|
.s-select-checkbox-opts {
|
|
358
304
|
@extend %select-menu-list;
|
|
359
|
-
> .q-virtual-scroll__content {
|
|
360
|
-
> .q-item.disabled {
|
|
361
|
-
border: none;
|
|
362
|
-
color: $Grey_Darken-4 !important;
|
|
363
|
-
opacity: 1 !important;
|
|
364
|
-
background: $Grey_Lighten-5 !important;
|
|
365
|
-
border-top: 1px solid $Grey_Lighten-3 !important;
|
|
366
|
-
&:not(.q-manual-focusable):first-of-type {
|
|
367
|
-
border-top: none !important;
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
305
|
}
|
|
372
306
|
|
|
373
307
|
.custom-select-options {
|
|
374
308
|
height: $default-height;
|
|
375
309
|
}
|
|
310
|
+
|
|
311
|
+
.disabled.s-select-checkbox-option {
|
|
312
|
+
border: none;
|
|
313
|
+
background: none !important;
|
|
314
|
+
color: $Grey_Default !important;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.select-search-input-form {
|
|
318
|
+
height: 28px;
|
|
319
|
+
display: flex;
|
|
320
|
+
align-items: center;
|
|
321
|
+
padding-left: 8px;
|
|
322
|
+
position: relative;
|
|
323
|
+
border-radius: 2px;
|
|
324
|
+
border: 1px solid $Grey_Lighten-1;
|
|
325
|
+
background-color: white;
|
|
326
|
+
position: sticky;
|
|
327
|
+
top: 0;
|
|
328
|
+
z-index: 1;
|
|
329
|
+
margin: 4px;
|
|
330
|
+
|
|
331
|
+
&::after {
|
|
332
|
+
content: '';
|
|
333
|
+
position: absolute;
|
|
334
|
+
top: 0;
|
|
335
|
+
right: 0;
|
|
336
|
+
bottom: 0;
|
|
337
|
+
left: 0;
|
|
338
|
+
pointer-events: none;
|
|
339
|
+
border: 1px solid transparent;
|
|
340
|
+
border-radius: inherit;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
&:hover,
|
|
344
|
+
&:focus-within {
|
|
345
|
+
&::after {
|
|
346
|
+
border-color: #0075ff;
|
|
347
|
+
box-shadow: 0 0 4px #0075ff;
|
|
348
|
+
transition: border-color 0.36s cubic-bezier(0.4, 0, 0.2, 1);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.select-search-input {
|
|
353
|
+
font-size: 12px;
|
|
354
|
+
margin-left: 8px;
|
|
355
|
+
flex-grow: 1;
|
|
356
|
+
border: none;
|
|
357
|
+
outline: none;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
376
360
|
</style>
|
|
@@ -29,14 +29,17 @@
|
|
|
29
29
|
"
|
|
30
30
|
>
|
|
31
31
|
<template #no-data="props">
|
|
32
|
-
<slot name="
|
|
32
|
+
<slot name="no-data" v-bind="props">
|
|
33
33
|
<div class="full-width text-center">
|
|
34
34
|
{{ noDataLabel }}
|
|
35
35
|
</div>
|
|
36
36
|
</slot>
|
|
37
37
|
</template>
|
|
38
|
+
|
|
38
39
|
<template #loading>
|
|
39
|
-
<
|
|
40
|
+
<slot name="loading">
|
|
41
|
+
<q-inner-loading showing color="positive" size="72px" />
|
|
42
|
+
</slot>
|
|
40
43
|
</template>
|
|
41
44
|
|
|
42
45
|
<template v-for="(column, index) in columns" :key="index" #[`body-cell-${column.name}`]="props">
|
|
@@ -100,8 +103,9 @@
|
|
|
100
103
|
</slot>
|
|
101
104
|
</q-td>
|
|
102
105
|
</template>
|
|
106
|
+
|
|
103
107
|
<template v-for="(_, slotName, index) in $slots" :key="index" #[slotName]="data">
|
|
104
|
-
<slot :name="slotName" v-bind="data"> </slot>
|
|
108
|
+
<slot :name="slotName" :key="`slot-${index}`" v-bind="data"> </slot>
|
|
105
109
|
</template>
|
|
106
110
|
</q-table>
|
|
107
111
|
<s-pagination
|