@bildvitta/quasar-ui-asteroid 3.9.0 → 3.10.0-beta.0
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/package.json +1 -1
- package/src/components/date/QasDate.vue +412 -0
- package/src/components/date/QasDate.yml +69 -0
- package/src/components/date-time-input/QasDateTimeInput.vue +1 -1
- package/src/components/filters/QasFilters.vue +12 -76
- package/src/components/form-view/QasFormView.vue +2 -2
- package/src/components/label/QasLabel.vue +1 -1
- package/src/components/search-box/QasSearchBox.vue +27 -21
- package/src/components/search-input/QasSearchInput.vue +122 -0
- package/src/components/search-input/QasSearchInput.yml +43 -0
- package/src/components/select/QasSelect.vue +20 -20
- package/src/components/select/QasSelect.yml +5 -0
- package/src/components/select-list/QasSelectList.vue +48 -18
- package/src/components/select-list/QasSelectList.yml +20 -10
- package/src/mixins/search-filter.js +64 -28
- package/src/vue-plugin.js +6 -0
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<qas-input v-bind="attributes"
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
</qas-input>
|
|
8
|
-
|
|
9
|
-
<div ref="scrollContainer" class="overflow-auto q-mt-xs relative-position" :style="containerStyle">
|
|
10
|
-
<component :is="component.is" v-bind="component.props">
|
|
2
|
+
<div>
|
|
3
|
+
<qas-search-input v-bind="attributes" v-model="mx_search" />
|
|
4
|
+
|
|
5
|
+
<div ref="scrollContainer" class="overflow-auto q-mt-md relative-position" :style="containerStyle">
|
|
6
|
+
<component :is="component.is" v-bind="component.props" class="q-mr-sm">
|
|
11
7
|
<slot v-if="mx_hasFilteredOptions" />
|
|
12
8
|
</component>
|
|
13
9
|
|
|
@@ -28,7 +24,7 @@
|
|
|
28
24
|
<q-spinner color="grey" size="3em" />
|
|
29
25
|
</q-inner-loading>
|
|
30
26
|
</div>
|
|
31
|
-
</
|
|
27
|
+
</div>
|
|
32
28
|
</template>
|
|
33
29
|
|
|
34
30
|
<script>
|
|
@@ -110,12 +106,10 @@ export default {
|
|
|
110
106
|
computed: {
|
|
111
107
|
attributes () {
|
|
112
108
|
return {
|
|
113
|
-
|
|
109
|
+
ref: 'search',
|
|
114
110
|
disable: this.isDisabled,
|
|
115
|
-
|
|
116
|
-
outlined: true,
|
|
111
|
+
useDebounce: this.useLazyLoading,
|
|
117
112
|
placeholder: this.placeholder,
|
|
118
|
-
hideBottomSpace: true,
|
|
119
113
|
error: this.mx_hasFetchError,
|
|
120
114
|
loading: this.mx_isFetching
|
|
121
115
|
}
|
|
@@ -195,7 +189,7 @@ export default {
|
|
|
195
189
|
await this.mx_filterOptionsByStore(value)
|
|
196
190
|
|
|
197
191
|
this.$refs.infiniteScrollRef.resume()
|
|
198
|
-
this.$refs.search.focus()
|
|
192
|
+
this.$refs.search.input.focus()
|
|
199
193
|
|
|
200
194
|
return
|
|
201
195
|
}
|
|
@@ -222,12 +216,7 @@ export default {
|
|
|
222
216
|
},
|
|
223
217
|
|
|
224
218
|
created () {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
this.mx_filteredOptions = this.list
|
|
228
|
-
this.fuse = new Fuse(this.list, this.defaultFuseOptions)
|
|
229
|
-
|
|
230
|
-
this.setListWatcher()
|
|
219
|
+
this.setSearchMethod()
|
|
231
220
|
},
|
|
232
221
|
|
|
233
222
|
methods: {
|
|
@@ -258,6 +247,23 @@ export default {
|
|
|
258
247
|
|
|
259
248
|
this.filterOptionsByFuse(this.mx_search)
|
|
260
249
|
}, { deep: true })
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
setSearchMethod () {
|
|
253
|
+
this.useLazyLoading ? this.setLazyLoading() : this.setFuse()
|
|
254
|
+
},
|
|
255
|
+
|
|
256
|
+
setFuse () {
|
|
257
|
+
const list = [...this.list]
|
|
258
|
+
|
|
259
|
+
this.mx_filteredOptions = list
|
|
260
|
+
this.fuse = new Fuse(list, this.defaultFuseOptions)
|
|
261
|
+
|
|
262
|
+
this.setListWatcher()
|
|
263
|
+
},
|
|
264
|
+
|
|
265
|
+
setLazyLoading () {
|
|
266
|
+
this.mx_setCachedOptions('list')
|
|
261
267
|
}
|
|
262
268
|
}
|
|
263
269
|
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="qas-filter-input">
|
|
3
|
+
<qas-input ref="input" v-model="model" class="bg-white q-px-sm rounded-borders-sm shadow-2" v-bind="$attrs" data-cy="search-input" :debounce="debounce" dense hide-bottom-space input-class="ellipsis text-grey-8" :outlined="false" type="search">
|
|
4
|
+
<template #prepend>
|
|
5
|
+
<q-icon v-if="useSearchOnType" color="grey-8" name="sym_r_search" />
|
|
6
|
+
<qas-btn v-else color="grey-9" icon="sym_r_search" variant="tertiary" @click="$emit('filter')" />
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<template #append>
|
|
10
|
+
<qas-btn v-if="hasSearch" color="grey-9" icon="sym_r_clear" variant="tertiary" @click="clear" />
|
|
11
|
+
|
|
12
|
+
<slot name="after-clear" />
|
|
13
|
+
</template>
|
|
14
|
+
</qas-input>
|
|
15
|
+
</div>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script>
|
|
19
|
+
export default {
|
|
20
|
+
name: 'QasSearchInput',
|
|
21
|
+
|
|
22
|
+
inheritAttrs: false,
|
|
23
|
+
|
|
24
|
+
props: {
|
|
25
|
+
modelValue: {
|
|
26
|
+
default: '',
|
|
27
|
+
type: String
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
useDebounce: {
|
|
31
|
+
default: true,
|
|
32
|
+
type: Boolean
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
useSearchOnType: {
|
|
36
|
+
default: true,
|
|
37
|
+
type: Boolean
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
emits: [
|
|
42
|
+
'clear',
|
|
43
|
+
'filter',
|
|
44
|
+
'update:modelValue'
|
|
45
|
+
],
|
|
46
|
+
|
|
47
|
+
computed: {
|
|
48
|
+
debounce () {
|
|
49
|
+
return this.useDebounce ? '1200' : ''
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
hasSearch () {
|
|
53
|
+
return !!this.model.length
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
input () {
|
|
57
|
+
return this.$refs.input
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
model: {
|
|
61
|
+
get () {
|
|
62
|
+
return this.modelValue
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
set (value) {
|
|
66
|
+
this.$emit('update:modelValue', value)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
methods: {
|
|
72
|
+
clear () {
|
|
73
|
+
this.$emit('clear', this.modelValue)
|
|
74
|
+
this.$emit('update:modelValue', '')
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
</script>
|
|
79
|
+
|
|
80
|
+
<style lang="scss">
|
|
81
|
+
.qas-filter-input {
|
|
82
|
+
position: relative;
|
|
83
|
+
|
|
84
|
+
.q-field {
|
|
85
|
+
&::before {
|
|
86
|
+
border: 2px solid transparent;
|
|
87
|
+
border-radius: var(--qas-generic-border-radius);
|
|
88
|
+
bottom: 0;
|
|
89
|
+
content: '';
|
|
90
|
+
left: 0;
|
|
91
|
+
pointer-events: none;
|
|
92
|
+
position: absolute;
|
|
93
|
+
right: 0;
|
|
94
|
+
top: 0;
|
|
95
|
+
transition: border-color var(--qas-generic-transition);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
&--dense .q-field__prepend {
|
|
99
|
+
padding-right: var(--qas-spacing-xs);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
&--dense .q-field__append {
|
|
103
|
+
padding-left: var(--qas-spacing-sm);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
&--focused::before {
|
|
107
|
+
border-color: var(--q-primary);
|
|
108
|
+
color: var(--q-primary);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
&__control::after,
|
|
112
|
+
&__control::before {
|
|
113
|
+
display: none !important;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
&__native {
|
|
117
|
+
padding-bottom: var(--qas-spacing-sm);
|
|
118
|
+
padding-top: var(--qas-spacing-sm);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
</style>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
type: component
|
|
2
|
+
|
|
3
|
+
meta:
|
|
4
|
+
desc: Componente de input para pesquisa / filtros.
|
|
5
|
+
|
|
6
|
+
props:
|
|
7
|
+
model-value:
|
|
8
|
+
desc: Model do componente, utilizado para v-model.
|
|
9
|
+
default: ''
|
|
10
|
+
type: String
|
|
11
|
+
model: true
|
|
12
|
+
|
|
13
|
+
use-debounce:
|
|
14
|
+
desc: Controla debounce.
|
|
15
|
+
default: true
|
|
16
|
+
type: Boolean
|
|
17
|
+
|
|
18
|
+
use-search-on-type:
|
|
19
|
+
desc: Controla se vai habilitar o botão de pesquisa ao clicar.
|
|
20
|
+
default: true
|
|
21
|
+
type: Boolean
|
|
22
|
+
|
|
23
|
+
slots:
|
|
24
|
+
after-clear:
|
|
25
|
+
desc: Slot para acessar área após o botão de limpar pesquisa.
|
|
26
|
+
|
|
27
|
+
events:
|
|
28
|
+
'@update:clear -> function(oldValue)':
|
|
29
|
+
desc: Dispara quando é clicado no botão de limpar pesquisa.
|
|
30
|
+
params:
|
|
31
|
+
oldValue:
|
|
32
|
+
desc: Valor do model antes de ser limpo.
|
|
33
|
+
type: String
|
|
34
|
+
|
|
35
|
+
'@update:filter -> function()':
|
|
36
|
+
desc: Dispara quando a prop "useSearchOnType" for "false" e é clicado no botão de pesquisar.
|
|
37
|
+
|
|
38
|
+
'@update:model-value -> function(value)':
|
|
39
|
+
desc: Dispara quando o model-value altera, também usado para v-model.
|
|
40
|
+
params:
|
|
41
|
+
value:
|
|
42
|
+
desc: Novo valor do model.
|
|
43
|
+
type: String
|
|
@@ -43,11 +43,6 @@ export default {
|
|
|
43
43
|
type: Object
|
|
44
44
|
},
|
|
45
45
|
|
|
46
|
-
labelKey: {
|
|
47
|
-
default: '',
|
|
48
|
-
type: String
|
|
49
|
-
},
|
|
50
|
-
|
|
51
46
|
modelValue: {
|
|
52
47
|
default: () => [],
|
|
53
48
|
type: [Array, Object, String, Number, Boolean]
|
|
@@ -63,9 +58,9 @@ export default {
|
|
|
63
58
|
type: Array
|
|
64
59
|
},
|
|
65
60
|
|
|
66
|
-
|
|
67
|
-
default:
|
|
68
|
-
type:
|
|
61
|
+
useFetchOptionsOnCreate: {
|
|
62
|
+
default: true,
|
|
63
|
+
type: Boolean
|
|
69
64
|
},
|
|
70
65
|
|
|
71
66
|
useSearch: {
|
|
@@ -114,10 +109,6 @@ export default {
|
|
|
114
109
|
return this.hasFuse || this.useLazyLoading
|
|
115
110
|
},
|
|
116
111
|
|
|
117
|
-
defaultOptions () {
|
|
118
|
-
return this.mx_handleOptions(this.options)
|
|
119
|
-
},
|
|
120
|
-
|
|
121
112
|
hasError () {
|
|
122
113
|
return this.mx_hasFetchError || this.$attrs.error
|
|
123
114
|
},
|
|
@@ -153,7 +144,7 @@ export default {
|
|
|
153
144
|
|
|
154
145
|
watch: {
|
|
155
146
|
defaultFuseOptions () {
|
|
156
|
-
this.setFuse()
|
|
147
|
+
if (this.hasFuse) this.setFuse()
|
|
157
148
|
},
|
|
158
149
|
|
|
159
150
|
options: {
|
|
@@ -162,7 +153,7 @@ export default {
|
|
|
162
153
|
|
|
163
154
|
if (this.fuse || this.hasFuse) this.setFuse()
|
|
164
155
|
|
|
165
|
-
this.mx_filteredOptions = this.
|
|
156
|
+
this.mx_filteredOptions = this.options
|
|
166
157
|
},
|
|
167
158
|
|
|
168
159
|
immediate: true
|
|
@@ -170,15 +161,12 @@ export default {
|
|
|
170
161
|
},
|
|
171
162
|
|
|
172
163
|
created () {
|
|
173
|
-
this.
|
|
174
|
-
this.useLazyLoading && this.mx_setFetchOptions('')
|
|
164
|
+
this.setSearchMethod()
|
|
175
165
|
},
|
|
176
166
|
|
|
177
167
|
methods: {
|
|
178
168
|
setFuse () {
|
|
179
|
-
|
|
180
|
-
this.fuse = new Fuse(this.defaultOptions, this.defaultFuseOptions)
|
|
181
|
-
}
|
|
169
|
+
this.fuse = new Fuse(this.options, this.defaultFuseOptions)
|
|
182
170
|
},
|
|
183
171
|
|
|
184
172
|
async onFilter (value, update) {
|
|
@@ -195,13 +183,25 @@ export default {
|
|
|
195
183
|
|
|
196
184
|
filterOptionsByFuse (value) {
|
|
197
185
|
if (value === '') {
|
|
198
|
-
this.mx_filteredOptions = this.
|
|
186
|
+
this.mx_filteredOptions = this.options
|
|
199
187
|
return
|
|
200
188
|
}
|
|
201
189
|
|
|
202
190
|
const results = this.fuse.search(value)
|
|
203
191
|
|
|
204
192
|
this.mx_filteredOptions = this.mx_getNormalizedFuseResults(results)
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
setLazyLoading () {
|
|
196
|
+
this.mx_setCachedOptions('options')
|
|
197
|
+
|
|
198
|
+
if (this.useFetchOptionsOnCreate) this.mx_setFetchOptions('')
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
setSearchMethod () {
|
|
202
|
+
if (this.useLazyLoading) return this.setLazyLoading()
|
|
203
|
+
|
|
204
|
+
if (this.hasFuse) this.setFuse()
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
207
|
}
|
|
@@ -71,6 +71,11 @@ props:
|
|
|
71
71
|
type: String
|
|
72
72
|
examples: [value-key="uuid"]
|
|
73
73
|
|
|
74
|
+
use-fetch-options-on-create:
|
|
75
|
+
desc: Controla se o componente vai fazer um fetch das opções assim que o mesmo é criado (caso tenha lazy loading ativado).
|
|
76
|
+
default: true
|
|
77
|
+
type: Boolean
|
|
78
|
+
|
|
74
79
|
use-search:
|
|
75
80
|
desc: Controla se vai ou não ter campo de busca no select.
|
|
76
81
|
default: undefined
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<qas-search-box v-model:results="results"
|
|
2
|
+
<qas-search-box v-model:results="results" v-bind="defaultSearchBoxProps" :list="sortedList">
|
|
3
3
|
<template #default>
|
|
4
4
|
<q-list separator>
|
|
5
|
-
<q-item v-for="result in results" :key="result.value">
|
|
5
|
+
<q-item v-for="result in results" :key="result.value" class="q-px-none">
|
|
6
6
|
<slot v-bind="slotData" :item="result" name="item">
|
|
7
7
|
<slot name="item-section" :result="result">
|
|
8
|
-
<q-item-section
|
|
9
|
-
<div :class="labelClass" @click="onClickLabel({ item: result, index })">
|
|
8
|
+
<q-item-section>
|
|
9
|
+
<div :class="labelClass" @click="onClickLabel({ item: result, index })">
|
|
10
|
+
{{ result.label }}
|
|
11
|
+
</div>
|
|
10
12
|
</q-item-section>
|
|
11
13
|
</slot>
|
|
12
14
|
|
|
13
15
|
<q-item-section avatar>
|
|
14
16
|
<slot :item="result" name="item-action" v-bind="slotData">
|
|
15
|
-
<qas-btn v-bind="getButtonProps(result)" @click="handleClick(result)" />
|
|
17
|
+
<qas-btn :disable="readonly" :use-label-on-small-screen="false" v-bind="getButtonProps(result)" @click="handleClick(result)" />
|
|
16
18
|
</slot>
|
|
17
19
|
</q-item-section>
|
|
18
20
|
</slot>
|
|
@@ -36,19 +38,21 @@ export default {
|
|
|
36
38
|
QasSearchBox
|
|
37
39
|
},
|
|
38
40
|
|
|
41
|
+
inheritAttrs: false,
|
|
42
|
+
|
|
39
43
|
props: {
|
|
40
|
-
|
|
41
|
-
type:
|
|
44
|
+
addLabel: {
|
|
45
|
+
type: String,
|
|
46
|
+
default: 'Adicionar'
|
|
42
47
|
},
|
|
43
48
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
deleteLabel: {
|
|
50
|
+
type: String,
|
|
51
|
+
default: 'Excluir'
|
|
47
52
|
},
|
|
48
53
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
type: Array
|
|
54
|
+
deleteOnly: {
|
|
55
|
+
type: Boolean
|
|
52
56
|
},
|
|
53
57
|
|
|
54
58
|
modelValue: {
|
|
@@ -56,6 +60,15 @@ export default {
|
|
|
56
60
|
default: () => []
|
|
57
61
|
},
|
|
58
62
|
|
|
63
|
+
readonly: {
|
|
64
|
+
type: Boolean
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
searchBoxProps: {
|
|
68
|
+
type: Object,
|
|
69
|
+
default: () => ({})
|
|
70
|
+
},
|
|
71
|
+
|
|
59
72
|
useClickableLabel: {
|
|
60
73
|
type: Boolean
|
|
61
74
|
}
|
|
@@ -77,10 +90,26 @@ export default {
|
|
|
77
90
|
},
|
|
78
91
|
|
|
79
92
|
computed: {
|
|
93
|
+
defaultSearchBoxProps () {
|
|
94
|
+
return {
|
|
95
|
+
fuseOptions: { keys: ['label'] },
|
|
96
|
+
|
|
97
|
+
...this.searchBoxProps
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
hasLazyLoading () {
|
|
102
|
+
return this.defaultSearchBoxProps.useLazyLoading
|
|
103
|
+
},
|
|
104
|
+
|
|
80
105
|
labelClass () {
|
|
81
106
|
return this.useClickableLabel && 'cursor-pointer'
|
|
82
107
|
},
|
|
83
108
|
|
|
109
|
+
list () {
|
|
110
|
+
return this.defaultSearchBoxProps.list || []
|
|
111
|
+
},
|
|
112
|
+
|
|
84
113
|
slotData () {
|
|
85
114
|
return {
|
|
86
115
|
add: this.add,
|
|
@@ -94,9 +123,9 @@ export default {
|
|
|
94
123
|
watch: {
|
|
95
124
|
list: {
|
|
96
125
|
handler (value) {
|
|
97
|
-
if (!this.
|
|
98
|
-
|
|
99
|
-
|
|
126
|
+
if (!this.hasLazyLoading) return this.sortList()
|
|
127
|
+
|
|
128
|
+
this.sortedList = [...value]
|
|
100
129
|
},
|
|
101
130
|
|
|
102
131
|
immediate: true
|
|
@@ -113,7 +142,7 @@ export default {
|
|
|
113
142
|
},
|
|
114
143
|
|
|
115
144
|
created () {
|
|
116
|
-
this.handleList()
|
|
145
|
+
if (!this.hasLazyLoading) this.handleList()
|
|
117
146
|
},
|
|
118
147
|
|
|
119
148
|
methods: {
|
|
@@ -128,9 +157,10 @@ export default {
|
|
|
128
157
|
const isSelected = this.values.includes(value)
|
|
129
158
|
|
|
130
159
|
return {
|
|
160
|
+
label: isSelected ? this.deleteLabel : this.addLabel,
|
|
131
161
|
variant: 'tertiary',
|
|
132
162
|
color: isSelected ? 'grey-9' : 'primary',
|
|
133
|
-
icon: isSelected ? '
|
|
163
|
+
icon: isSelected ? 'sym_r_delete' : 'sym_r_add'
|
|
134
164
|
}
|
|
135
165
|
},
|
|
136
166
|
|
|
@@ -7,20 +7,20 @@ meta:
|
|
|
7
7
|
desc: Componente para selecionar dentro de uma lista com pesquisa utilizando o `QasSearchBox`.
|
|
8
8
|
|
|
9
9
|
props:
|
|
10
|
+
add-label:
|
|
11
|
+
desc: Label do botão de adicionar.
|
|
12
|
+
default: Adicionar
|
|
13
|
+
type: String
|
|
14
|
+
|
|
15
|
+
delete-label:
|
|
16
|
+
desc: Label do botão de deletar.
|
|
17
|
+
default: Excluir
|
|
18
|
+
type: String
|
|
19
|
+
|
|
10
20
|
delete-only:
|
|
11
21
|
desc: Caso o "modelValue" tenha valor, ele remove tudo na lista que não esteja dentro do modelValue.
|
|
12
22
|
type: Boolean
|
|
13
23
|
|
|
14
|
-
fuse-options:
|
|
15
|
-
desc: Propriedade que será repassada para o "QasSearchBox".
|
|
16
|
-
default: "{ keys: ['label'] }"
|
|
17
|
-
type: Object
|
|
18
|
-
|
|
19
|
-
list:
|
|
20
|
-
desc: Lista que será feita a seleção e pesquisa.
|
|
21
|
-
default: []
|
|
22
|
-
type: Array
|
|
23
|
-
|
|
24
24
|
model-value:
|
|
25
25
|
desc: Model do componente, que será controlado tudo que foi selecionado.
|
|
26
26
|
default: []
|
|
@@ -28,6 +28,16 @@ props:
|
|
|
28
28
|
examples: [v-model="value"]
|
|
29
29
|
model: true
|
|
30
30
|
|
|
31
|
+
readonly:
|
|
32
|
+
desc: Habilita modo visualização.
|
|
33
|
+
default: false
|
|
34
|
+
type: Boolean
|
|
35
|
+
|
|
36
|
+
search-box-props:
|
|
37
|
+
desc: Repassa props para o componente "QasSearchBox"
|
|
38
|
+
default: {}
|
|
39
|
+
type: Object
|
|
40
|
+
|
|
31
41
|
use-clickable-label:
|
|
32
42
|
desc: Habilita "cursor-pointer" no label e evento "click-label".
|
|
33
43
|
type: Boolean
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { decamelize } from 'humps'
|
|
2
2
|
import { isEqual } from 'lodash'
|
|
3
|
-
import { getNormalizedOptions } from '../helpers'
|
|
4
3
|
import { getAction } from '@bildvitta/store-adapter'
|
|
5
4
|
|
|
6
5
|
export default {
|
|
@@ -20,11 +19,11 @@ export default {
|
|
|
20
19
|
type: String
|
|
21
20
|
},
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
fetching: {
|
|
24
23
|
type: Boolean
|
|
25
24
|
},
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
useLazyLoading: {
|
|
28
27
|
type: Boolean
|
|
29
28
|
}
|
|
30
29
|
},
|
|
@@ -38,12 +37,15 @@ export default {
|
|
|
38
37
|
|
|
39
38
|
data () {
|
|
40
39
|
return {
|
|
40
|
+
mx_cachedOptions: [],
|
|
41
|
+
mx_fetchCount: 0,
|
|
41
42
|
mx_filteredOptions: [],
|
|
43
|
+
mx_foundDuplicatedOptions: [],
|
|
44
|
+
mx_fromSearch: false,
|
|
42
45
|
mx_hasFetchError: false,
|
|
43
46
|
mx_isFetching: false,
|
|
44
47
|
mx_isScrolling: false,
|
|
45
48
|
mx_search: '',
|
|
46
|
-
mx_fetchCount: 0,
|
|
47
49
|
mx_pagination: {
|
|
48
50
|
page: 1,
|
|
49
51
|
lastPage: null,
|
|
@@ -77,10 +79,6 @@ export default {
|
|
|
77
79
|
return !!this.mx_filteredOptions.length
|
|
78
80
|
},
|
|
79
81
|
|
|
80
|
-
mx_isFilterByFuse () {
|
|
81
|
-
return !this.useLazyLoading
|
|
82
|
-
},
|
|
83
|
-
|
|
84
82
|
mx_isMultiple () {
|
|
85
83
|
return this.$attrs.multiple || this.$attrs.multiple === ''
|
|
86
84
|
}
|
|
@@ -101,11 +99,17 @@ export default {
|
|
|
101
99
|
methods: {
|
|
102
100
|
async mx_filterOptionsByStore (search) {
|
|
103
101
|
this.mx_resetFilter(search)
|
|
102
|
+
|
|
103
|
+
this.mx_fromSearch = !!search
|
|
104
|
+
|
|
104
105
|
await this.mx_setFetchOptions()
|
|
106
|
+
|
|
107
|
+
if (this.mx_cachedOptions.length && !search) this.mx_setInitialCachedOptions()
|
|
105
108
|
},
|
|
106
109
|
|
|
107
110
|
mx_resetFilter (search) {
|
|
108
111
|
this.mx_filteredOptions = []
|
|
112
|
+
this.mx_foundDuplicatedOptions = []
|
|
109
113
|
this.mx_search = search
|
|
110
114
|
this.mx_pagination = {
|
|
111
115
|
page: 1,
|
|
@@ -180,14 +184,8 @@ export default {
|
|
|
180
184
|
|
|
181
185
|
this.$emit('fetch-options-success', data)
|
|
182
186
|
|
|
183
|
-
return this.
|
|
187
|
+
return this.mx_getNonDuplicatedOptions(results)
|
|
184
188
|
} catch (error) {
|
|
185
|
-
this.$qas.logger.group(
|
|
186
|
-
`Mixin: searchFilterMixin - mx_fetchOptions -> exceção da action ${this.entity}/fetchFieldOptions`,
|
|
187
|
-
[error],
|
|
188
|
-
{ error: true }
|
|
189
|
-
)
|
|
190
|
-
|
|
191
189
|
this.mx_hasFetchError = true
|
|
192
190
|
this.$emit('fetch-options-error', error)
|
|
193
191
|
|
|
@@ -199,7 +197,48 @@ export default {
|
|
|
199
197
|
},
|
|
200
198
|
|
|
201
199
|
async mx_setFetchOptions () {
|
|
202
|
-
|
|
200
|
+
const options = await this.mx_fetchOptions()
|
|
201
|
+
|
|
202
|
+
this.mx_filteredOptions.push(...options)
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
mx_setInitialCachedOptions () {
|
|
206
|
+
this.mx_cachedOptions.forEach(cachedOption => {
|
|
207
|
+
const hasOption = this.mx_filteredOptions.find(filteredOption => {
|
|
208
|
+
return filteredOption.value === cachedOption.value
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
if (!hasOption && this.mx_filteredOptions.length) {
|
|
212
|
+
this.mx_filteredOptions.unshift(cachedOption)
|
|
213
|
+
}
|
|
214
|
+
})
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
mx_getNonDuplicatedOptions (options = []) {
|
|
218
|
+
if (this.mx_fromSearch) {
|
|
219
|
+
this.mx_fromSearch = false
|
|
220
|
+
|
|
221
|
+
return options
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (!options.length) return []
|
|
225
|
+
|
|
226
|
+
const nonDuplicatedOptions = [...options]
|
|
227
|
+
|
|
228
|
+
this.mx_cachedOptions.forEach(cachedOption => {
|
|
229
|
+
if (this.mx_foundDuplicatedOptions.includes(cachedOption.value)) return
|
|
230
|
+
|
|
231
|
+
const duplicatedOptionIndex = nonDuplicatedOptions.findIndex(option => {
|
|
232
|
+
return option.value === cachedOption.value
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
if (~duplicatedOptionIndex) {
|
|
236
|
+
this.mx_foundDuplicatedOptions.push(cachedOption.value)
|
|
237
|
+
nonDuplicatedOptions.splice(duplicatedOptionIndex, 1)
|
|
238
|
+
}
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
return nonDuplicatedOptions
|
|
203
242
|
},
|
|
204
243
|
|
|
205
244
|
mx_canFetchOptions () {
|
|
@@ -210,18 +249,6 @@ export default {
|
|
|
210
249
|
return hasMorePages && !this.mx_isFetching && !this.mx_isScrolling && this.useLazyLoading
|
|
211
250
|
},
|
|
212
251
|
|
|
213
|
-
mx_handleOptions (options) {
|
|
214
|
-
if (this.labelKey && this.valueKey) {
|
|
215
|
-
return getNormalizedOptions({
|
|
216
|
-
options,
|
|
217
|
-
label: this.labelKey,
|
|
218
|
-
value: this.valueKey
|
|
219
|
-
})
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
return options
|
|
223
|
-
},
|
|
224
|
-
|
|
225
252
|
mx_getMissingPropsMessage (prop) {
|
|
226
253
|
return `A propriedade "${prop}" é obrigatória quando a propriedade "useLazyLoading" está ativa.`
|
|
227
254
|
},
|
|
@@ -232,6 +259,15 @@ export default {
|
|
|
232
259
|
|
|
233
260
|
mx_getNormalizedFuseResults (results = []) {
|
|
234
261
|
return results.map(({ item }) => item)
|
|
262
|
+
},
|
|
263
|
+
|
|
264
|
+
mx_setCachedOptions (model) {
|
|
265
|
+
this.$watch(model, options => {
|
|
266
|
+
if (!options?.length) return
|
|
267
|
+
|
|
268
|
+
this.mx_filteredOptions = [...options]
|
|
269
|
+
this.mx_cachedOptions = [...options]
|
|
270
|
+
}, { immediate: true })
|
|
235
271
|
}
|
|
236
272
|
}
|
|
237
273
|
}
|