|
| 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