@bildvitta/quasar-ui-asteroid 3.17.0-beta.23 → 3.17.0-beta.25
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/app-user/QasAppUser.vue +49 -40
- package/src/components/chart-view/QasChartView.vue +55 -2
- package/src/components/chart-view/QasChartView.yml +6 -0
- package/src/components/expansion-item/QasExpansionItem.vue +6 -49
- package/src/components/expansion-item/QasExpansionItem.yml +0 -5
- package/src/components/list-view/QasListView.vue +3 -1
- package/src/components/select-filter/QasSelectFilter.vue +65 -0
- package/src/components/select-filter/QasSelectFilter.yml +36 -0
- package/src/composables/index.js +3 -1
- package/src/composables/use-default-filters.js +106 -0
- package/src/composables/use-query-cache.js +1 -1
- package/src/vue-plugin.js +3 -0
package/package.json
CHANGED
|
@@ -108,23 +108,29 @@ const props = defineProps({
|
|
|
108
108
|
}
|
|
109
109
|
})
|
|
110
110
|
|
|
111
|
+
// emits
|
|
111
112
|
const emit = defineEmits(['sign-out', 'toggle-notifications'])
|
|
112
113
|
|
|
113
|
-
//
|
|
114
|
+
// globals
|
|
114
115
|
const axios = inject('axios')
|
|
115
116
|
|
|
117
|
+
// composables
|
|
116
118
|
const router = useRouter()
|
|
117
119
|
|
|
118
120
|
const { isNotificationsEnabled, unreadNotificationsCount } = useNotifications()
|
|
119
121
|
|
|
120
122
|
const { reset } = useQueryCache()
|
|
121
123
|
|
|
124
|
+
const { avatarNotificationCountProps } = useAvatarNotifications()
|
|
125
|
+
|
|
126
|
+
// refs
|
|
122
127
|
const companiesModel = ref('')
|
|
123
128
|
const loading = ref(false)
|
|
124
129
|
|
|
125
|
-
|
|
130
|
+
// consts
|
|
131
|
+
const IS_ME_VERSION_2 = process.env.ME_VERSION === 2
|
|
126
132
|
|
|
127
|
-
//
|
|
133
|
+
// computeds
|
|
128
134
|
const defaultCompanyProps = computed(() => {
|
|
129
135
|
return {
|
|
130
136
|
loading: loading.value,
|
|
@@ -148,42 +154,7 @@ watch(() => props.companyProps.modelValue, value => {
|
|
|
148
154
|
companiesModel.value = value
|
|
149
155
|
}, { immediate: true })
|
|
150
156
|
|
|
151
|
-
//
|
|
152
|
-
function useAvatarNotifications () {
|
|
153
|
-
const hasAnimated = ref(false)
|
|
154
|
-
|
|
155
|
-
watch(() => unreadNotificationsCount.value, () => {
|
|
156
|
-
hasAnimated.value = true
|
|
157
|
-
|
|
158
|
-
setTimeout(() => {
|
|
159
|
-
hasAnimated.value = false
|
|
160
|
-
}, 1000)
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
const avatarNotificationCountProps = computed(() => {
|
|
164
|
-
const classes = [
|
|
165
|
-
'qas-app-user__notification-avatar',
|
|
166
|
-
'animated',
|
|
167
|
-
{
|
|
168
|
-
rubberBand: hasAnimated.value
|
|
169
|
-
}
|
|
170
|
-
]
|
|
171
|
-
|
|
172
|
-
return {
|
|
173
|
-
class: classes,
|
|
174
|
-
color: 'red-14',
|
|
175
|
-
size: 'xs',
|
|
176
|
-
title: unreadNotificationsToString.value,
|
|
177
|
-
useCropTitle: false
|
|
178
|
-
}
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
return {
|
|
182
|
-
avatarNotificationCountProps
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// métodos
|
|
157
|
+
// functions
|
|
187
158
|
function signOut () {
|
|
188
159
|
emit('sign-out')
|
|
189
160
|
}
|
|
@@ -194,7 +165,10 @@ async function setCompanies (value) {
|
|
|
194
165
|
loading.value = true
|
|
195
166
|
|
|
196
167
|
try {
|
|
197
|
-
await axios.patch('users/me', {
|
|
168
|
+
await axios.patch('users/me', {
|
|
169
|
+
[IS_ME_VERSION_2 ? 'currentMainCompany' : 'companies']: value
|
|
170
|
+
})
|
|
171
|
+
|
|
198
172
|
setTimeout(() => location.reload(), 1500)
|
|
199
173
|
|
|
200
174
|
NotifySuccess('Vínculo alterado com sucesso.')
|
|
@@ -224,6 +198,41 @@ function onMenuHide () {
|
|
|
224
198
|
function toggleNotificationsDrawer () {
|
|
225
199
|
emit('toggle-notifications')
|
|
226
200
|
}
|
|
201
|
+
|
|
202
|
+
// composables definitions
|
|
203
|
+
function useAvatarNotifications () {
|
|
204
|
+
const hasAnimated = ref(false)
|
|
205
|
+
|
|
206
|
+
watch(() => unreadNotificationsCount.value, () => {
|
|
207
|
+
hasAnimated.value = true
|
|
208
|
+
|
|
209
|
+
setTimeout(() => {
|
|
210
|
+
hasAnimated.value = false
|
|
211
|
+
}, 1000)
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
const avatarNotificationCountProps = computed(() => {
|
|
215
|
+
const classes = [
|
|
216
|
+
'qas-app-user__notification-avatar',
|
|
217
|
+
'animated',
|
|
218
|
+
{
|
|
219
|
+
rubberBand: hasAnimated.value
|
|
220
|
+
}
|
|
221
|
+
]
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
class: classes,
|
|
225
|
+
color: 'red-14',
|
|
226
|
+
size: 'xs',
|
|
227
|
+
title: unreadNotificationsToString.value,
|
|
228
|
+
useCropTitle: false
|
|
229
|
+
}
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
return {
|
|
233
|
+
avatarNotificationCountProps
|
|
234
|
+
}
|
|
235
|
+
}
|
|
227
236
|
</script>
|
|
228
237
|
|
|
229
238
|
<style lang="scss">
|
|
@@ -46,8 +46,9 @@ import zoomPlugin from 'chartjs-plugin-zoom'
|
|
|
46
46
|
import chartDataLabels from 'chartjs-plugin-datalabels'
|
|
47
47
|
|
|
48
48
|
// Outras importações
|
|
49
|
-
import { extend } from 'quasar'
|
|
50
49
|
import { filterListByHandle } from '../../helpers'
|
|
50
|
+
|
|
51
|
+
import { extend, is } from 'quasar'
|
|
51
52
|
import { getAction } from '@bildvitta/store-adapter'
|
|
52
53
|
|
|
53
54
|
const ChartTypes = {
|
|
@@ -131,6 +132,11 @@ export default {
|
|
|
131
132
|
type: String
|
|
132
133
|
},
|
|
133
134
|
|
|
135
|
+
urlQueryList: {
|
|
136
|
+
default: () => (['company']),
|
|
137
|
+
type: Array
|
|
138
|
+
},
|
|
139
|
+
|
|
134
140
|
useBox: {
|
|
135
141
|
type: Boolean,
|
|
136
142
|
default: true
|
|
@@ -332,6 +338,10 @@ export default {
|
|
|
332
338
|
...(this.useBox && { ...this.boxProps })
|
|
333
339
|
}
|
|
334
340
|
}
|
|
341
|
+
},
|
|
342
|
+
|
|
343
|
+
queryFromURL () {
|
|
344
|
+
return this.getQueryFromURL(this.$route.query)
|
|
335
345
|
}
|
|
336
346
|
},
|
|
337
347
|
|
|
@@ -342,6 +352,10 @@ export default {
|
|
|
342
352
|
|
|
343
353
|
isFetching (value) {
|
|
344
354
|
this.$emit('update:fetching', value)
|
|
355
|
+
},
|
|
356
|
+
|
|
357
|
+
$route (to, from) {
|
|
358
|
+
this.onRouteChange(to, from)
|
|
345
359
|
}
|
|
346
360
|
},
|
|
347
361
|
|
|
@@ -357,9 +371,10 @@ export default {
|
|
|
357
371
|
methods: {
|
|
358
372
|
handleFetchData () {
|
|
359
373
|
const hasBeforeFetch = typeof this.beforeFetch === 'function'
|
|
374
|
+
|
|
360
375
|
const payload = {
|
|
361
376
|
url: this.url,
|
|
362
|
-
filters: this.filters
|
|
377
|
+
filters: { ...this.filters, ...this.queryFromURL }
|
|
363
378
|
}
|
|
364
379
|
|
|
365
380
|
if (hasBeforeFetch && !this.cancelBeforeFetch) {
|
|
@@ -435,6 +450,44 @@ export default {
|
|
|
435
450
|
...this.defaultChartItems,
|
|
436
451
|
...this.elementsChartItems[this.type]
|
|
437
452
|
)
|
|
453
|
+
},
|
|
454
|
+
|
|
455
|
+
onRouteChange (to, from) {
|
|
456
|
+
const { query } = to
|
|
457
|
+
|
|
458
|
+
const isSameRoute = to.name === from.name
|
|
459
|
+
const hasQueryInURLQueryList = this.urlQueryList.some(urlQuery => query[urlQuery])
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* feito com função para evitar um deepEqual desnecessário, uma vez que
|
|
463
|
+
* caso "isSameRoute" seja falso, ou "hasQueryInURLQueryList" seja falso,
|
|
464
|
+
* não é necessário fazer a comparação.
|
|
465
|
+
*/
|
|
466
|
+
const hasQueryChanged = () => !is.deepEqual(this.queryFromURL, this.getQueryFromURL(from.query))
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Verifica se a rota atual é a mesma, se há uma query na URL que corresponde à queryList,
|
|
470
|
+
* e se a query correspondente à queryList foi alterada. Se todas essas condições forem
|
|
471
|
+
* verdadeiras, faz a requisição de dados.
|
|
472
|
+
*/
|
|
473
|
+
if (isSameRoute && hasQueryInURLQueryList && hasQueryChanged()) this.handleFetchData()
|
|
474
|
+
},
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* "urlQueryList" é uma lista de query que o componente deve pegar da URL.
|
|
478
|
+
*/
|
|
479
|
+
getQueryFromURL (query = {}) {
|
|
480
|
+
const newQuery = {}
|
|
481
|
+
|
|
482
|
+
this.urlQueryList.forEach(urlQuery => {
|
|
483
|
+
const queryValue = query[urlQuery]
|
|
484
|
+
|
|
485
|
+
if (queryValue) {
|
|
486
|
+
newQuery[urlQuery] = queryValue
|
|
487
|
+
}
|
|
488
|
+
})
|
|
489
|
+
|
|
490
|
+
return newQuery
|
|
438
491
|
}
|
|
439
492
|
}
|
|
440
493
|
}
|
|
@@ -70,6 +70,12 @@ props:
|
|
|
70
70
|
desc: Envia como parâmetro para a action "fetchList" do modulo correspondente a "entity".
|
|
71
71
|
type: String
|
|
72
72
|
|
|
73
|
+
url-query-list:
|
|
74
|
+
desc: Lista de query que serão recuperadas da URL e enviadas como parâmetro para a action "fetchList" do modulo correspondente a "entity".
|
|
75
|
+
type: Array
|
|
76
|
+
default:
|
|
77
|
+
- company
|
|
78
|
+
|
|
73
79
|
use-box:
|
|
74
80
|
desc: Controla se o componente vai ter o QasBox englobando ou não.
|
|
75
81
|
default: true
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div ref="expansionItem" class="full-width qas-expansion-item" :class="classes" v-bind="expansionProps.parent">
|
|
3
|
-
<
|
|
3
|
+
<qas-box class="qas-expansion-item__box" v-bind="boxProps">
|
|
4
4
|
<q-expansion-item v-model="modelValue" v-bind="expansionProps.item" header-class="text-bold q-mt-sm q-pa-none qas-expansion-item__header" @show="setShowContent">
|
|
5
5
|
<template #header>
|
|
6
6
|
<div class="full-width justify-between no-wrap row">
|
|
@@ -28,17 +28,13 @@
|
|
|
28
28
|
</div>
|
|
29
29
|
</template>
|
|
30
30
|
|
|
31
|
-
<q-separator v-if="hasHeaderSeparator" class="q-my-md" />
|
|
32
|
-
|
|
33
31
|
<div :class="contentClasses">
|
|
34
32
|
<slot v-if="showContent" name="content">
|
|
35
33
|
<qas-grid-generator v-if="hasGridGenerator" use-inline v-bind="gridGeneratorProps" />
|
|
36
34
|
</slot>
|
|
37
35
|
</div>
|
|
38
|
-
|
|
39
|
-
<q-separator v-if="hasBottomSeparator" class="q-mt-md" />
|
|
40
36
|
</q-expansion-item>
|
|
41
|
-
</
|
|
37
|
+
</qas-box>
|
|
42
38
|
|
|
43
39
|
<div v-if="hasError" class="q-pt-sm qas-expansion-item__error-message text-caption text-negative">
|
|
44
40
|
{{ props.errorMessage }}
|
|
@@ -49,7 +45,7 @@
|
|
|
49
45
|
<script setup>
|
|
50
46
|
import QasBox from '../box/QasBox.vue'
|
|
51
47
|
|
|
52
|
-
import { computed, provide, inject,
|
|
48
|
+
import { computed, provide, inject, ref, useAttrs } from 'vue'
|
|
53
49
|
|
|
54
50
|
defineOptions({
|
|
55
51
|
name: 'QasExpansionItem',
|
|
@@ -97,11 +93,6 @@ const props = defineProps({
|
|
|
97
93
|
maxContentHeight: {
|
|
98
94
|
type: String,
|
|
99
95
|
default: ''
|
|
100
|
-
},
|
|
101
|
-
|
|
102
|
-
useHeaderSeparator: {
|
|
103
|
-
type: Boolean,
|
|
104
|
-
default: undefined
|
|
105
96
|
}
|
|
106
97
|
})
|
|
107
98
|
|
|
@@ -116,37 +107,18 @@ const slots = defineSlots()
|
|
|
116
107
|
|
|
117
108
|
// refs
|
|
118
109
|
const expansionItem = ref(null)
|
|
119
|
-
const hasNextSibling = ref(false)
|
|
120
110
|
const showContent = ref(false)
|
|
121
111
|
|
|
122
|
-
onMounted(setHasNextSibling)
|
|
123
|
-
|
|
124
112
|
// constants
|
|
125
113
|
const isNestedExpansionItem = inject('isExpansionItem', false)
|
|
126
114
|
const isNestedBox = inject('isBox', false)
|
|
127
115
|
|
|
128
|
-
const component = {
|
|
129
|
-
is: isNestedExpansionItem ? 'div' : QasBox
|
|
130
|
-
}
|
|
131
|
-
|
|
132
116
|
// computed
|
|
133
117
|
const hasBadges = computed(() => !!props.badges.length)
|
|
134
118
|
const hasError = computed(() => props.error || !!props.errorMessage)
|
|
135
119
|
const hasGridGenerator = computed(() => !!Object.keys(props.gridGeneratorProps).length)
|
|
136
|
-
const hasBottomSeparator = computed(() => isNestedExpansionItem && hasNextSibling.value)
|
|
137
120
|
const hasHeaderBottom = computed(() => !!slots['header-bottom'])
|
|
138
121
|
|
|
139
|
-
/**
|
|
140
|
-
* Verifica se o componente deve adicionar um separador no header.
|
|
141
|
-
*
|
|
142
|
-
* - Se a propriedade useHeaderSeparator for true, retorna separador.
|
|
143
|
-
* - Se a propriedade useHeaderSeparator for undefined, retorna separador apenas se não for um componente aninhado.
|
|
144
|
-
* - Se a propriedade useHeaderSeparator for false, não retorna separador.
|
|
145
|
-
*/
|
|
146
|
-
const hasHeaderSeparator = computed(() => {
|
|
147
|
-
return typeof props.useHeaderSeparator === 'undefined' ? !isNestedExpansionItem : props.useHeaderSeparator
|
|
148
|
-
})
|
|
149
|
-
|
|
150
122
|
const classes = computed(() => {
|
|
151
123
|
return {
|
|
152
124
|
'qas-expansion-item--error': hasError.value,
|
|
@@ -157,8 +129,7 @@ const classes = computed(() => {
|
|
|
157
129
|
|
|
158
130
|
const contentClasses = computed(() => {
|
|
159
131
|
return {
|
|
160
|
-
'q-mt-
|
|
161
|
-
'q-mt-md': !isNestedExpansionItem && !props.useHeaderSeparator,
|
|
132
|
+
'q-mt-md': true,
|
|
162
133
|
'qas-expansion-item__content overflow-auto': !!props.maxContentHeight
|
|
163
134
|
}
|
|
164
135
|
})
|
|
@@ -196,10 +167,10 @@ const expansionProps = computed(() => {
|
|
|
196
167
|
|
|
197
168
|
const boxProps = computed(() => {
|
|
198
169
|
/**
|
|
199
|
-
* Caso o QasExpansionItem estiver dentro de um QasBox
|
|
170
|
+
* Caso o QasExpansionItem estiver dentro de um QasBox ou for um QasExpansionItem
|
|
200
171
|
* dentro de outro QasExpansionItem, o componente terá uma borda.
|
|
201
172
|
*/
|
|
202
|
-
const isBoxed = isNestedBox
|
|
173
|
+
const isBoxed = isNestedBox || isNestedExpansionItem
|
|
203
174
|
|
|
204
175
|
if (!isBoxed) return {}
|
|
205
176
|
|
|
@@ -212,20 +183,6 @@ const boxProps = computed(() => {
|
|
|
212
183
|
const isDisabled = computed(() => props.disable || props.disableButton)
|
|
213
184
|
|
|
214
185
|
// functions
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Caso o componente esteja dentro de um QasExpansionItem, verifica se existe um próximo irmão
|
|
218
|
-
* para adicionar um separador.
|
|
219
|
-
*/
|
|
220
|
-
function setHasNextSibling () {
|
|
221
|
-
if (!isNestedExpansionItem) return
|
|
222
|
-
|
|
223
|
-
const hasTextContentSibling = !!expansionItem.value.nextSibling?.textContent?.trim?.()
|
|
224
|
-
const hasElementSibling = !!expansionItem.value.nextElementSibling
|
|
225
|
-
|
|
226
|
-
hasNextSibling.value = hasElementSibling || hasTextContentSibling
|
|
227
|
-
}
|
|
228
|
-
|
|
229
186
|
function setShowContent () {
|
|
230
187
|
showContent.value = true
|
|
231
188
|
}
|
|
@@ -49,11 +49,6 @@ props:
|
|
|
49
49
|
desc: Propriedades que serão repassadas para o QasGridGenerator.
|
|
50
50
|
type: Object
|
|
51
51
|
|
|
52
|
-
use-header-separator:
|
|
53
|
-
desc: Propriedade para forçar o QSeparator no header.
|
|
54
|
-
type: Boolean
|
|
55
|
-
default: undefined
|
|
56
|
-
|
|
57
52
|
slots:
|
|
58
53
|
header:
|
|
59
54
|
desc: Slot para substituir o conteúdo do header (não inclui o botão dropdown).
|
|
@@ -43,10 +43,12 @@
|
|
|
43
43
|
<script>
|
|
44
44
|
import QasFilters from '../filters/QasFilters.vue'
|
|
45
45
|
import QasPagination from '../pagination/QasPagination.vue'
|
|
46
|
+
|
|
47
|
+
import { viewMixin, contextMixin } from '../../mixins'
|
|
48
|
+
|
|
46
49
|
import debug from 'debug'
|
|
47
50
|
import { extend } from 'quasar'
|
|
48
51
|
import { getState, getAction } from '@bildvitta/store-adapter'
|
|
49
|
-
import { viewMixin, contextMixin } from '../../mixins'
|
|
50
52
|
import { computed } from 'vue'
|
|
51
53
|
|
|
52
54
|
const log = debug('asteroid-ui:qas-list-view')
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<qas-select v-model="internalModel" :label="props.label" :options="props.options" use-filter-mode @update:model-value="onUpdateModel" />
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script setup>
|
|
6
|
+
import useDefaultFilters from '../../composables/use-default-filters'
|
|
7
|
+
|
|
8
|
+
import { extend } from 'quasar'
|
|
9
|
+
import { watch, ref, nextTick } from 'vue'
|
|
10
|
+
import { useRouter, useRoute } from 'vue-router'
|
|
11
|
+
|
|
12
|
+
defineOptions({ name: 'QasSelectFilter' })
|
|
13
|
+
|
|
14
|
+
const props = defineProps({
|
|
15
|
+
label: {
|
|
16
|
+
type: String,
|
|
17
|
+
default: 'Selecione uma empresa vinculada'
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
name: {
|
|
21
|
+
type: String,
|
|
22
|
+
default: 'company'
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
options: {
|
|
26
|
+
type: Array,
|
|
27
|
+
default: () => []
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
// composables
|
|
32
|
+
const router = useRouter()
|
|
33
|
+
const route = useRoute()
|
|
34
|
+
const { setFilterQuery, triggerDefaultFiltersChange, filterQuery } = useDefaultFilters()
|
|
35
|
+
|
|
36
|
+
// models
|
|
37
|
+
const model = defineModel({ type: String, default: '' })
|
|
38
|
+
|
|
39
|
+
// refs
|
|
40
|
+
const internalModel = ref(route.query[props.name] || model.value)
|
|
41
|
+
|
|
42
|
+
// watch
|
|
43
|
+
watch(() => route.query[props.name], setModels)
|
|
44
|
+
|
|
45
|
+
// functions
|
|
46
|
+
/**
|
|
47
|
+
* Adiciona o valor na URL, atualizando a rota, isto vai fazer com que o componente
|
|
48
|
+
* seja atualizado com o novo valor, pois cai no watch que atualiza o model interno e externo.
|
|
49
|
+
*/
|
|
50
|
+
function onUpdateModel (value) {
|
|
51
|
+
const { ...query } = route.query
|
|
52
|
+
|
|
53
|
+
router.push({ query: { ...query, [props.name]: value } })
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function setModels (value) {
|
|
57
|
+
model.value = value
|
|
58
|
+
internalModel.value = value
|
|
59
|
+
|
|
60
|
+
const oldFilters = extend(true, {}, filterQuery.value)
|
|
61
|
+
|
|
62
|
+
setFilterQuery(value, props.name)
|
|
63
|
+
nextTick(() => triggerDefaultFiltersChange(filterQuery.value, oldFilters))
|
|
64
|
+
}
|
|
65
|
+
</script>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
type: component
|
|
2
|
+
|
|
3
|
+
meta:
|
|
4
|
+
desc: Componente para gerar dinamicamente checkbox agrupados.
|
|
5
|
+
|
|
6
|
+
props:
|
|
7
|
+
inline:
|
|
8
|
+
desc: Controla se o componente vai aparece em linha ou em bloco.
|
|
9
|
+
default: true
|
|
10
|
+
type: Boolean
|
|
11
|
+
|
|
12
|
+
label:
|
|
13
|
+
desc: Label utilizada em casos de ser checkbox-group.
|
|
14
|
+
default: ''
|
|
15
|
+
type: String
|
|
16
|
+
|
|
17
|
+
model-value:
|
|
18
|
+
desc: Model do componente, usado para v-model.
|
|
19
|
+
default: []
|
|
20
|
+
type: Array
|
|
21
|
+
examples: [v-model"value"]
|
|
22
|
+
model: true
|
|
23
|
+
|
|
24
|
+
options:
|
|
25
|
+
desc: Opções para gerar os checkbox.
|
|
26
|
+
default: []
|
|
27
|
+
type: Array
|
|
28
|
+
|
|
29
|
+
events:
|
|
30
|
+
'@update:model-value -> function(value)':
|
|
31
|
+
desc: Dispara quando o model-value altera, também usado para v-model.
|
|
32
|
+
params:
|
|
33
|
+
value:
|
|
34
|
+
desc: Novo valor do model.
|
|
35
|
+
default: []
|
|
36
|
+
type: Array
|
package/src/composables/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export { default as useContext } from './use-context.js'
|
|
2
|
+
export { default as useDefaultFilters } from './use-default-filters.js'
|
|
2
3
|
export { default as useForm } from './use-form.js'
|
|
3
4
|
export { default as useHistory } from './use-history.js'
|
|
5
|
+
export { default as useNotifications } from './use-notifications.js'
|
|
4
6
|
export { default as useQueryCache } from './use-query-cache.js'
|
|
5
7
|
export { default as useScreen } from './use-screen.js'
|
|
6
|
-
export { default as useNotifications } from './use-notifications.js'
|
|
7
8
|
|
|
8
9
|
export * from './use-notifications.js'
|
|
10
|
+
export * from './use-default-filters.js'
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { computed, ref } from 'vue'
|
|
2
|
+
import { LocalStorage, is } from 'quasar'
|
|
3
|
+
|
|
4
|
+
const filterQuery = ref({})
|
|
5
|
+
|
|
6
|
+
const defaultFiltersHooks = {
|
|
7
|
+
defaultFiltersChange: []
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Define os filtros padrão antes de entrar na rota.
|
|
12
|
+
*
|
|
13
|
+
* Prioridade de aplicação dos filtros:
|
|
14
|
+
* 1 - Se o filtro estiver salvo no estado global, então utiliza ele.
|
|
15
|
+
* 2 - Se o filtro já estiver na query, então utiliza ele.
|
|
16
|
+
* 3 - Se o filtro já estiver salvo no LocalStorage, então utiliza ele.
|
|
17
|
+
*
|
|
18
|
+
* @param {Object} to - Rota de destino.
|
|
19
|
+
* @param {Object} _from - Rota de origem.
|
|
20
|
+
* @param {Function} next - Função de redirecionamento.
|
|
21
|
+
* @param {Array} queryList='company' - Lista de filtros a serem aplicados.
|
|
22
|
+
*/
|
|
23
|
+
export function setDefaultFiltersBeforeEnter (to, _from, next, queryList = ['company']) {
|
|
24
|
+
const { getDefaultFiltersFromStorage, setFilterQuery } = useDefaultFilters()
|
|
25
|
+
|
|
26
|
+
const { query } = to
|
|
27
|
+
const newQuery = { ...query }
|
|
28
|
+
|
|
29
|
+
// recupera os filtros padrão do LocalStorage
|
|
30
|
+
const defaultFiltersFromStorage = getDefaultFiltersFromStorage()
|
|
31
|
+
|
|
32
|
+
queryList.forEach(name => {
|
|
33
|
+
// 1. se o filtro já estiver salvo no estado, então utiliza ele
|
|
34
|
+
if (filterQuery.value[name]) {
|
|
35
|
+
newQuery[name] = filterQuery.value[name]
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 2. se o filtro já estiver na query, então utiliza ele
|
|
40
|
+
if (query[name]) {
|
|
41
|
+
setFilterQuery(query[name], name)
|
|
42
|
+
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const storedFilter = defaultFiltersFromStorage[name]
|
|
47
|
+
|
|
48
|
+
// 3. se o filtro já estiver salvo no LocalStorage, então utiliza ele
|
|
49
|
+
if (storedFilter) {
|
|
50
|
+
setFilterQuery(storedFilter, name)
|
|
51
|
+
newQuery[name] = storedFilter
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Verifica se houve mudanças na query antes de redirecionar, sem essa validação
|
|
57
|
+
* o redirecionamento ocorre mesmo que a query seja a mesma, gerando loop infinito.
|
|
58
|
+
*/
|
|
59
|
+
if (!is.deepEqual(newQuery, query)) return next({ ...to, query: newQuery, replace: true })
|
|
60
|
+
|
|
61
|
+
next()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Este composable recupera os filtros default salvos no LocalStorage na chave 'defaultFilters'.
|
|
66
|
+
*/
|
|
67
|
+
export default function useDefaultFilters () {
|
|
68
|
+
const hasFilterQuery = computed(() => !!Object.keys(filterQuery.value).length)
|
|
69
|
+
|
|
70
|
+
function setFilterQuery (query, name = 'company') {
|
|
71
|
+
filterQuery.value[name] = query
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function getDefaultFiltersFromStorage () {
|
|
75
|
+
const defaultFiltersFromStorage = LocalStorage.getItem('defaultFilters') || {}
|
|
76
|
+
|
|
77
|
+
return defaultFiltersFromStorage
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function triggerDefaultFiltersChange (newFilters, oldFilters) {
|
|
81
|
+
// necessário verificar se houve mudanças antes de disparar o evento para não duplicar.
|
|
82
|
+
if (is.deepEqual(newFilters, oldFilters)) return
|
|
83
|
+
|
|
84
|
+
defaultFiltersHooks.defaultFiltersChange.forEach(hook => hook(newFilters, oldFilters))
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function onDefaultFiltersChange (callback) {
|
|
88
|
+
defaultFiltersHooks.defaultFiltersChange.push(callback)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function removeOnDefaultFiltersChange (callback) {
|
|
92
|
+
const index = defaultFiltersHooks.defaultFiltersChange.indexOf(callback)
|
|
93
|
+
|
|
94
|
+
if (~index) defaultFiltersHooks.defaultFiltersChange.splice(index, 1)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
filterQuery,
|
|
99
|
+
hasFilterQuery,
|
|
100
|
+
getDefaultFiltersFromStorage,
|
|
101
|
+
onDefaultFiltersChange,
|
|
102
|
+
removeOnDefaultFiltersChange,
|
|
103
|
+
setFilterQuery,
|
|
104
|
+
triggerDefaultFiltersChange
|
|
105
|
+
}
|
|
106
|
+
}
|
package/src/vue-plugin.js
CHANGED
|
@@ -14,6 +14,7 @@ import QasBtnDropdown from './components/btn-dropdown/QasBtnDropdown.vue'
|
|
|
14
14
|
import QasCard from './components/card/QasCard.vue'
|
|
15
15
|
import QasCardImage from './components/card-image/QasCardImage.vue'
|
|
16
16
|
import QasCheckbox from './components/checkbox/QasCheckbox.vue'
|
|
17
|
+
import QasSelectFilter from './components/select-filter/QasSelectFilter.vue'
|
|
17
18
|
import QasCopy from './components/copy/QasCopy.vue'
|
|
18
19
|
import QasDate from './components/date/QasDate.vue'
|
|
19
20
|
import QasDateTimeInput from './components/date-time-input/QasDateTimeInput.vue'
|
|
@@ -112,6 +113,7 @@ async function install (app) {
|
|
|
112
113
|
app.component('QasCard', QasCard)
|
|
113
114
|
app.component('QasCardImage', QasCardImage)
|
|
114
115
|
app.component('QasCheckbox', QasCheckbox)
|
|
116
|
+
app.component('QasSelectFilter', QasSelectFilter)
|
|
115
117
|
app.component('QasCopy', QasCopy)
|
|
116
118
|
app.component('QasDate', QasDate)
|
|
117
119
|
app.component('QasDateTimeInput', QasDateTimeInput)
|
|
@@ -213,6 +215,7 @@ export {
|
|
|
213
215
|
QasCard,
|
|
214
216
|
QasCheckbox,
|
|
215
217
|
QasCopy,
|
|
218
|
+
QasSelectFilter,
|
|
216
219
|
QasDate,
|
|
217
220
|
QasDateTimeInput,
|
|
218
221
|
QasDebugger,
|