Skip to content

Commit bb3dc54

Browse files
searchFilter
1 parent 692b22b commit bb3dc54

File tree

7 files changed

+643
-249
lines changed

7 files changed

+643
-249
lines changed

app/src/components/appbar/RightButtons.vue

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
<template lang='pug'>
22
div
3-
q-btn(v-for="button in buttons" :key="button.icon" round flat :icon="button.icon" size="lg")
4-
q-tooltip.text-body2(transition-show="scale" transition-hide="scale") {{ button.name }}
5-
q-btn-dropdown(icon="mdi-account-circle-outline" round flat size="lg")
6-
q-list
7-
q-item.q-pa-none(v-for="button in buttons" :key="button.name")
8-
q-btn.full-width.items-baseline.q-pa-sm(
9-
:icon="button.icon"
10-
:label="button.name"
11-
:color="button?.color || 'primary'"
12-
@click="button?.action"
13-
:to='button?.to'
14-
flat
15-
dense
16-
)
3+
q-btn(v-for="button in buttons" :key="button.icon" round flat :icon="button.icon" size="md").q-mx-sm
4+
q-tooltip.text-body2(transition-show="scale" transition-hide="scale") {{ button.name }}
5+
q-btn-dropdown(icon="mdi-account-circle-outline" round flat size="md")
6+
q-list
7+
q-item.q-pa-none(v-for="button in buttons" :key="button.name")
8+
q-btn.full-width.items-baseline.q-pa-sm(
9+
:icon="button.icon"
10+
:label="button.name"
11+
:color="button?.color || 'primary'"
12+
@click="button?.action"
13+
:to='button?.to'
14+
flat
15+
dense
16+
)
1717
</template>
1818

1919
<script lang='ts' setup>
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
<template lang="pug">
2+
.row.q-gutter-sm.items-center.q-mt-sm
3+
//- .col.col-md-2
4+
//- q-select(:options="fieldTypes" label="Type de champ" v-model="fieldType" clearable @update:model-value="clearFields(['field', 'comparator'])")
5+
.col.col-md-2
6+
q-select(:options="fields" label="Champs" v-model="field" clearable @update:model-value="onFieldChange($event)")
7+
.col.col-md-2
8+
q-select(:options="comparatorFilteredByType" label="Comparateurs" v-model="comparator" clearable @update:model-value="clearFields([])" :disable="isFieldDisabled.comparator")
9+
template(v-slot:selected-item="scope")
10+
q-icon(:name="scope.opt.icon" size="xs")
11+
template(v-slot:option="scope")
12+
q-item(v-bind="scope.itemProps")
13+
q-item-section(avatar)
14+
q-icon(:name="scope.opt.icon")
15+
q-item-section
16+
q-item-label
17+
span {{ scope.opt.label }}
18+
19+
.col-12.col-md-2(v-show="!comparator?.multiplefields")
20+
q-input(v-model="search" label="Rechercher" clearable :type="searchInputType" :disable="isFieldDisabled.search" :prefix="comparator?.prefix" :suffix="comparator?.suffix")
21+
.col-6.col-md-2(v-show="comparator?.multiplefields")
22+
q-input(v-model="searchMin" label="Min" clearable :type="searchInputType" :disable="isFieldDisabled.search" )
23+
.col-6.col-md-2(v-show="comparator?.multiplefields")
24+
q-input(v-model="searchMax" label="Max" clearable :type="searchInputType" :disable="isFieldDisabled.search" )
25+
.col-12.col-md-1
26+
q-btn(color="primary" @click="addFilter" :disable="isFieldDisabled.addButton") Ajouter
27+
q-space
28+
.col-12.col-md-2
29+
tk-SearchfiltersRightSelect(ref="rightSelect")
30+
</template>
31+
32+
<script lang="ts" setup>
33+
import { ref, computed, inject } from 'vue'
34+
import { useRouter, useRoute } from 'nuxt/app'
35+
import { useDayjs } from '#imports';
36+
import type { Filter, Field, Comparator, SearchFilter } from '~/types'
37+
const dayjs = useDayjs()
38+
39+
const fields = inject('fieldsList', ref<Field[]>([]))
40+
41+
const router = useRouter()
42+
const route = useRoute()
43+
const rightSelect = ref(null)
44+
const inclus = ref(true)
45+
const fieldType = ref<string>()
46+
47+
let field = ref<Field>()
48+
let comparator = ref<Comparator>()
49+
const search = ref('')
50+
const searchMin = ref('')
51+
const searchMax = ref('')
52+
53+
54+
const filters = ref<Filter[]>([])
55+
56+
const fieldTypes = ref<{
57+
label: string
58+
value: string
59+
}[]>([
60+
{ label: 'Texte', value: 'text' },
61+
{ label: 'Nombre', value: 'number' },
62+
{ label: 'Date', value: 'date' },
63+
])
64+
65+
const comparatorTypes = ref<Comparator[]>([
66+
{ label: 'Egal à', querySign: '=', value: '=', icon: 'mdi-equal', type: ['number'], multiplefields: false, prefix: '', suffix: '' },
67+
{ label: 'Différent', querySign: '!=', value: '!=', icon: 'mdi-exclamation', type: ['number'], multiplefields: false, prefix: '', suffix: '' },
68+
{ label: 'Supérieur à', querySign: '>', value: '>', icon: 'mdi-greater-than', type: ['number', 'date'], multiplefields: false, prefix: '', suffix: '' },
69+
{ label: 'Supérieur ou égal à', querySign: '>=', value: '>=', icon: 'mdi-greater-than-or-equal', type: ['number', 'date'], multiplefields: false, prefix: '', suffix: '' },
70+
{ label: 'Inférieur à', querySign: '<', value: '<', icon: 'mdi-less-than', type: ['number', 'date'], multiplefields: false, prefix: '', suffix: '' },
71+
{ label: 'Inférieur ou égal à', querySign: '<=', value: '<=', icon: 'mdi-less-than-or-equal', type: ['number', 'date'], multiplefields: false, prefix: '', suffix: '' },
72+
{ label: 'entre', querySign: '<<', value: 'between', icon: 'mdi-arrow-expand-horizontal', type: ['number', 'date'], multiplefields: true, prefix: '', suffix: '' },
73+
{ label: 'Contiens', querySign: '^', value: '^', icon: 'mdi-apple-keyboard-control', type: ['text'], multiplefields: false, prefix: '/', suffix: '/' },
74+
{ label: 'Commence par', querySign: '^', value: '/^', icon: 'mdi-apple-keyboard-control', type: ['text'], multiplefields: false, prefix: '/^', suffix: '/' },
75+
{ label: 'Fini par', querySign: '^', value: '$/', icon: 'mdi-apple-keyboard-control', type: ['text'], multiplefields: false, prefix: '/', suffix: '$/' },
76+
{ label: 'Egal à', querySign: '@', value: '@', icon: 'mdi-apple-keyboard-control', type: [], multiplefields: true, prefix: '', suffix: '' },
77+
78+
])
79+
80+
const onFieldChange = (value: Field) => {
81+
value === null ? fieldType.value = '' : fieldType.value = value.type
82+
clearFields(['comparator'])
83+
}
84+
85+
const clearFields = (fields: string[]) => {
86+
if (fields.includes('field')) field = ref()
87+
if (fields.includes('comparator')) comparator = ref()
88+
search.value = ''
89+
searchMin.value = ''
90+
searchMax.value = ''
91+
}
92+
93+
const addFilter = async () => {
94+
const searchFilter = getSearchFilter.value
95+
if (!searchFilter) return
96+
if (searchFilter.comparator.multiplefields) {
97+
for (const { key, value } of parseMultipleFilter(searchFilter)) {
98+
await pushQuery(key, value)
99+
}
100+
} else {
101+
const { key, value } = parseSimpleFilter(searchFilter)
102+
await pushQuery(key, value)
103+
}
104+
}
105+
106+
const parseSimpleFilter = (searchFilter: SearchFilter) => {
107+
if (searchFilter.field.type === 'date') {
108+
if (searchFilter.comparator.querySign === '<' || searchFilter.comparator.querySign === '>=') searchFilter.search = dayjs(searchFilter.search).startOf('day').toISOString()
109+
if (searchFilter.comparator.querySign === '>' || searchFilter.comparator.querySign === '<=') searchFilter.search = dayjs(searchFilter.search).endOf('day').toISOString()
110+
}
111+
return {
112+
key: `filters[${searchFilter.comparator.querySign}${searchFilter.field.name}]`,
113+
value: `${searchFilter.comparator.prefix}${searchFilter.search}${searchFilter.comparator.suffix}`
114+
}
115+
}
116+
117+
const parseMultipleFilter = (searchFilter: SearchFilter) => {
118+
if (searchFilter.field.type === 'date') {
119+
searchFilter.searchMin = dayjs(searchFilter.searchMin).startOf('day').toISOString()
120+
searchFilter.searchMax = dayjs(searchFilter.searchMax).endOf('day').toISOString()
121+
}
122+
const min = {
123+
key: `filters[>=${searchFilter.field.name}]`,
124+
value: `${searchFilter.comparator.prefix}${searchFilter.searchMin}${searchFilter.comparator.suffix}`
125+
}
126+
const max = {
127+
key: `filters[<=${searchFilter.field.name}]`,
128+
value: `${searchFilter.comparator.prefix}${searchFilter.searchMax}${searchFilter.comparator.suffix}`
129+
}
130+
return [min, max]
131+
}
132+
133+
const pushQuery = async (key: string, value: string) => {
134+
const query = {
135+
...route.query,
136+
}
137+
query[key] = value
138+
await router.push({
139+
query
140+
})
141+
}
142+
143+
const getSearchFilter = computed(() => {
144+
if (field.value === undefined || field.value === null) return null
145+
if (comparator.value === undefined || comparator.value === null) return null
146+
return {
147+
field: field!.value,
148+
comparator: comparator!.value,
149+
search: search.value,
150+
searchMin: searchMin.value,
151+
searchMax: searchMax.value
152+
}
153+
})
154+
155+
const searchInputType = computed(() => {
156+
if (fieldType.value === undefined || fieldType.value === null) return 'text'
157+
return fieldType.value
158+
})
159+
160+
const fieldsFilteredByType = computed(() => {
161+
if (fieldType.value === undefined || fieldType.value === null) return []
162+
return fields.value.filter((field) => {
163+
return field.type === fieldType.value
164+
})
165+
})
166+
167+
const comparatorFilteredByType = computed(() => {
168+
if (fieldType.value === undefined || fieldType.value === null) return []
169+
return comparatorTypes.value.filter((comparator) => {
170+
return comparator.type.includes(fieldType.value!)
171+
})
172+
})
173+
174+
const isFieldDisabled = computed(() => {
175+
return {
176+
field: false,
177+
comparator: !field.value,
178+
search: !field.value || !comparator.value,
179+
addButton: !field.value || !comparator.value || !search.value,
180+
}
181+
})
182+
183+
defineExpose({
184+
comparatorTypes,
185+
rightSelect,
186+
})
187+
</script>

0 commit comments

Comments
 (0)