1- <template lang="pug">
2- .q-pa -sm ( @keydown.enter = "addFilter" )
1+ <template lang="pug" @ keypress = " addFilter " >
2+ .q-ma -sm
33 .row.q-gutter-sm.items-center
4- .col-1
5- q-toggle( v-model ="inclus" : label= "inclus ? 'Inclus' : 'Exclus'" )
6- .col-1
7- q-select( :options ="fieldTypes" label ="Type de champ" v-model ="fieldType" )
8- .col-2
9- q-select( :options ="fields" label ="Champs" v-model ="field" )
10- .col-1
11- q-select( :options ="comparatorTypes" label ="Comparateurs" v-model ="comparator" )
4+ .col.col-md-2
5+ q-select( :options ="fieldTypes" label ="Type de champ" v-model ="fieldType" clearable @update:model-value ="clearFields(['field', 'comparator'])" )
6+ .col.col-md-2
7+ q-select( :options ="fieldsFilteredByType" label ="Champs" v-model ="field" clearable @update:model-value ="clearFields(['comparator'])" )
8+ .col.col-md-2
9+ q-select( :options ="comparatorFilteredByType" label ="Comparateurs" v-model ="comparator" clearable @update:model-value ="clearFields([])" )
1210 template( v-slot:selected-item ="scope" )
1311 q-icon( :name ="scope.opt.icon" size ="xs" )
14-
1512 template( v-slot:option ="scope" )
1613 q-item( v-bind ="scope.itemProps" )
1714 q-item-section( avatar )
2017 q-item-label
2118 span {{ scope.opt.label }}
2219
23- .col-2
24- q-input( v-model ="search" label ="Rechercher" )
25- .col-2
26- q-btn( flat icon ="mdi-plus" color ="primary" @click ="addFilter" )
27- q-tooltip.text-body2 ( transition-show ="scale" transition-hide ="scale" ) Ajouter
20+ .col-12.col-md-2 ( v-show ="!comparator?.multiplefields" )
21+ q-input( v-model ="search" label ="Rechercher" clearable :type ="searchInputType" : prefix= "comparator?.prefix" : suffix= "comparator?.suffix" )
22+ template( v-slot:append )
23+
2824
25+ .col-6.col-md-2 ( v-show ="comparator?.multiplefields" )
26+ q-input( v-model ="searchMin" label ="Min" clearable :type ="searchInputType" )
27+ .col-6.col-md-2 ( v-show ="comparator?.multiplefields" )
28+ q-input( v-model ="searchMax" label ="Max" clearable :type ="searchInputType" )
29+ .col-12.col-md-1
30+ q-btn( color ="primary" @click ="addFilter" ) Ajouter
2931 //Filters chips
3032 .row.q-gutter-sm.items-center.q-mt-sm
3133 q-chip(
3537</template >
3638
3739<script lang="ts" setup>
38- import { ref } from ' vue'
40+ import { ref , computed } from ' vue'
3941import type { PropType } from ' vue'
4042import { useRouter , useRoute } from ' nuxt/app'
43+ import { useDayjs } from ' #imports' ;
44+
45+ const dayjs = useDayjs ()
4146
4247type Filter = {
4348 field: string
@@ -48,12 +53,26 @@ type Filter = {
4853type Field = {
4954 name: string
5055 label: string
56+ type: string
5157}
5258
5359type Comparator = {
5460 label: string
61+ querySign: string
5562 value: string
5663 icon: string
64+ type: string []
65+ multiplefields: boolean
66+ prefix: string
67+ suffix: string
68+ }
69+
70+ type SearchFilter = {
71+ field: Field
72+ comparator: Comparator
73+ search: string
74+ searchMin: string
75+ searchMax: string
5776}
5877
5978const props = defineProps ({
@@ -67,59 +86,102 @@ const router = useRouter()
6786const route = useRoute ()
6887
6988const inclus = ref (true )
70- const fieldType = ref (' ' )
89+ const fieldType = ref <{
90+ label: string
91+ value: string
92+ }>()
93+
7194let field = ref <Field >()
7295let comparator = ref <Comparator >()
7396const search = ref (' ' )
97+ const searchMin = ref (' ' )
98+ const searchMax = ref (' ' )
99+
74100
75101const filters = ref <Filter []>([])
76102
77- const fieldTypes = ref ([
103+ const fieldTypes = ref <{
104+ label: string
105+ value: string
106+ }[]>([
78107 { label: ' Texte' , value: ' text' },
79108 { label: ' Nombre' , value: ' number' },
80109 { label: ' Date' , value: ' date' },
81- { label: ' Heure' , value: ' time' },
82- { label: ' Date et heure' , value: ' datetime' },
83- { label: ' Liste' , value: ' list' },
84- { label: ' Liste de valeurs' , value: ' listOfValues' },
85- { label: ' Liste de valeurs multiples' , value: ' listOfValuesMultiple' },
86110])
87111
88112const comparatorTypes = ref <Comparator []>([
89- { label: ' Egal' , value: ' =' , icon: ' mdi-equal' },
90- { label: ' Différent' , value: ' !=' , icon: ' mdi-exclamation' },
91- { label: ' Est supérieur à' , value: ' >' , icon: ' mdi-greater-than' },
92- { label: ' Est supérieur ou égal à' , value: ' >=' , icon: ' mdi-greater-than-or-equal' },
93- { label: ' Est inférieur à' , value: ' <' , icon: ' mdi-less-than' },
94- { label: ' Est inférieur ou égal à' , value: ' <=' , icon: ' mdi-less-than-or-equal' },
95- { label: ' Est entre' , value: ' between' , icon: ' mdi-arrow-expand-horizontal' },
113+ { label: ' Egal' , querySign: ' =' , value: ' =' , icon: ' mdi-equal' , type: [' number' ], multiplefields: false , prefix: ' ' , suffix: ' ' },
114+ { label: ' Différent' , querySign: ' !=' , value: ' !=' , icon: ' mdi-exclamation' , type: [' number' ], multiplefields: false , prefix: ' ' , suffix: ' ' },
115+ { label: ' Est supérieur à' , querySign: ' >' , value: ' >' , icon: ' mdi-greater-than' , type: [' number' , ' date' ], multiplefields: false , prefix: ' ' , suffix: ' ' },
116+ { label: ' Est supérieur ou égal à' , querySign: ' >=' , value: ' >=' , icon: ' mdi-greater-than-or-equal' , type: [' number' , ' date' ], multiplefields: false , prefix: ' ' , suffix: ' ' },
117+ { label: ' Est inférieur à' , querySign: ' <' , value: ' <' , icon: ' mdi-less-than' , type: [' number' , ' date' ], multiplefields: false , prefix: ' ' , suffix: ' ' },
118+ { label: ' Est inférieur ou égal à' , querySign: ' <=' , value: ' <=' , icon: ' mdi-less-than-or-equal' , type: [' number' , ' date' ], multiplefields: false , prefix: ' ' , suffix: ' ' },
119+ { label: ' Est entre' , querySign: ' <<' , value: ' between' , icon: ' mdi-arrow-expand-horizontal' , type: [' number' , ' date' ], multiplefields: true , prefix: ' ' , suffix: ' ' },
120+ { label: ' Contiens' , querySign: ' ^' , value: ' ^' , icon: ' mdi-apple-keyboard-control' , type: [' text' ], multiplefields: false , prefix: ' /' , suffix: ' /' },
121+ { label: ' Commence par' , querySign: ' ^' , value: ' /^' , icon: ' mdi-apple-keyboard-control' , type: [' text' ], multiplefields: false , prefix: ' /^' , suffix: ' /' },
122+ { label: ' Fini par' , querySign: ' ^' , value: ' $/' , icon: ' mdi-apple-keyboard-control' , type: [' text' ], multiplefields: false , prefix: ' /' , suffix: ' $/' },
96123])
97124
98- const addFilter = () => {
99- if (
100- ! field .value ||
101- ! comparator .value ||
102- ! search .value
103- ) return
104-
105- const object = {
106- field: field .value .name ,
107- comparator: comparator .value .value ,
108- search: search .value
125+ const clearFields = (fields : string []) => {
126+ if (fields .includes (' field' )) field = ref ()
127+ if (fields .includes (' comparator' )) comparator = ref ()
128+ search .value = ' '
129+ searchMin .value = ' '
130+ searchMax .value = ' '
131+ }
132+
133+ const addFilter = async () => {
134+ const searchFilter = getSearchFilter .value
135+ if (! searchFilter ) return
136+ if (searchFilter .comparator .multiplefields ) {
137+ for (const { key, value } of parseMultipleFilter (searchFilter )) {
138+ await pushQuery (key , value )
139+ }
140+ } else {
141+ const { key, value } = parseSimpleFilter (searchFilter )
142+ await pushQuery (key , value )
143+ }
144+ }
145+
146+ const parseSimpleFilter = (searchFilter : SearchFilter ) => {
147+ if (searchFilter .field .type === ' date' ) {
148+ if (searchFilter .comparator .querySign === ' <' || searchFilter .comparator .querySign === ' >=' ) searchFilter .search = dayjs (searchFilter .search ).startOf (' day' ).toISOString ()
149+ if (searchFilter .comparator .querySign === ' >' || searchFilter .comparator .querySign === ' <=' ) searchFilter .search = dayjs (searchFilter .search ).endOf (' day' ).toISOString ()
150+ }
151+ return {
152+ key: ` filters[${searchFilter .comparator .querySign }${searchFilter .field .name }] ` ,
153+ value: ` ${searchFilter .comparator .prefix }${searchFilter .search }${searchFilter .comparator .suffix } `
154+ }
155+ }
156+
157+ const parseMultipleFilter = (searchFilter : SearchFilter ) => {
158+ if (searchFilter .field .type === ' date' ) {
159+ searchFilter .searchMin = dayjs (searchFilter .searchMin ).startOf (' day' ).toISOString ()
160+ searchFilter .searchMax = dayjs (searchFilter .searchMax ).endOf (' day' ).toISOString ()
161+ }
162+ const min = {
163+ key: ` filters[>=${searchFilter .field .name }] ` ,
164+ value: ` ${searchFilter .comparator .prefix }${searchFilter .searchMin }${searchFilter .comparator .suffix } `
165+ }
166+ const max = {
167+ key: ` filters[<=${searchFilter .field .name }] ` ,
168+ value: ` ${searchFilter .comparator .prefix }${searchFilter .searchMax }${searchFilter .comparator .suffix } `
109169 }
110- const key = ` filter[${object .comparator }${object .field }] `
111- const value = object .search
170+ return [min , max ]
171+ }
172+
173+ const pushQuery = async (key : string , value : string ) => {
112174 const query = {
113175 ... route .query ,
114176 }
115177 query [key ] = value
116- router .push ({
178+ await router .push ({
117179 query
118180 })
119181}
120182
121183const removeFilter = (filter : Filter ) => {
122- const key = ` filter [${filter .comparator }${filter .field }]`
184+ const key = ` filters [${filter .comparator }${filter .field }]`
123185 const query = {
124186 ... route .query ,
125187 }
@@ -131,7 +193,7 @@ const removeFilter = (filter: Filter) => {
131193
132194const getLabelByName = (name : string ) => {
133195 const field = props .fields .find (field => field .name === name )
134- if (! field ) return
196+ if (! field ) return ' '
135197 return field .label
136198}
137199
@@ -141,7 +203,7 @@ const exctractComparator = (key: string): {
141203 field: string
142204} | null => {
143205 const match = key .match (/ ^ (\= | \? | \# | \! | \> | \< | \^ | \@ )+ / )
144- if (! match ) return
206+ if (! match ) return null
145207 const comparator = match [0 ]
146208 const field = key .replace (comparator , ' ' )
147209 return {
@@ -150,28 +212,59 @@ const exctractComparator = (key: string): {
150212 }
151213}
152214
215+ const getSearchFilter = computed (() => {
216+ if (field .value === undefined || field .value === null ) return null
217+ if (comparator .value === undefined || comparator .value === null ) return null
218+ return {
219+ field: field ! .value ,
220+ comparator: comparator ! .value ,
221+ search: search .value ,
222+ searchMin: searchMin .value ,
223+ searchMax: searchMax .value
224+ }
225+ })
226+
153227const filterArray = computed (() => {
154228 const queries = { ... route .query }
155- const filters: Record <string , string > = {};
229+ const filters: Record <string , { label : string , field : string , comparator : string , search : string } > = {};
156230
157231 // Iterate through the keys and values in the input object
158232 for (const key in queries ) {
159233 if (queries .hasOwnProperty (key ) && key .includes (" filter" )) {
160234
161235 // Extract the key without the "filter[" and "]" parts
162- const filteredKey = key .replace (" filter [" , " " ).replace (" ]" , " " );
236+ const filteredKey = key .replace (" filters [" , " " ).replace (" ]" , " " );
163237 const exctract = exctractComparator (filteredKey )
164238 if (! exctract ) continue
165239 const { comparator, field } = exctract
166240 // Assign the value to the extracted key in the filter array
167- filters [field ] = {
241+ filters [key ] = {
168242 label: getLabelByName (field ),
169243 field ,
170244 comparator ,
171- search: queries [key ]
245+ search: queries [key ]?. toString () ?? ' '
172246 };
173247 }
174248 }
175249 return filters
176250})
251+
252+ const searchInputType = computed (() => {
253+ if (fieldType .value === undefined || fieldType .value === null ) return ' text'
254+ return fieldType .value ! .value
255+ })
256+
257+ const fieldsFilteredByType = computed (() => {
258+ if (fieldType .value === undefined || fieldType .value === null ) return []
259+ return props .fields .filter ((field ) => {
260+ return field .type === fieldType .value ! .value
261+ })
262+ })
263+
264+ const comparatorFilteredByType = computed (() => {
265+ if (fieldType .value === undefined || fieldType .value === null ) return []
266+ return comparatorTypes .value .filter ((comparator ) => {
267+ return comparator .type .includes (fieldType .value ! .value )
268+ })
269+ })
177270 </script >
0 commit comments