refs #6062 feat(arrayData): support exprBuilder #112
|
@ -25,27 +25,17 @@ const pinnedModulesRef = ref();
|
|||
|
||||
|
||||
<template>
|
||||
<QHeader class="bg-dark" color="white" elevated>
|
||||
<QToolbar class="q-py-sm q-px-md">
|
||||
<QBtn
|
||||
@click="stateStore.toggleLeftDrawer()"
|
||||
icon="menu"
|
||||
class="q-mr-sm"
|
||||
round
|
||||
dense
|
||||
flat
|
||||
>
|
||||
<QToolbar
|
||||
class="q-py-sm q-px-md"
|
||||
:class="{ 'q-gutter-x-sm': !quasar.platform.is.mobile }"
|
||||
>
|
||||
<QBtn @click="stateStore.toggleLeftDrawer()" icon="menu" round dense flat>
|
||||
<QTooltip bottom anchor="bottom right">
|
||||
{{ t('globals.collapseMenu') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
<RouterLink to="/">
|
||||
<QBtn
|
||||
class="q-ml-xs"
|
||||
color="primary"
|
||||
flat
|
||||
round
|
||||
v-if="!quasar.platform.is.mobile"
|
||||
>
|
||||
<QBtn color="primary" flat round v-if="!quasar.platform.is.mobile">
|
||||
<QAvatar square size="md">
|
||||
<QImg
|
||||
src="~/assets/salix_icon.svg"
|
||||
|
|
|
@ -15,6 +15,10 @@ const $props = defineProps({
|
|||
type: String,
|
||||
default: '',
|
||||
},
|
||||
isClearable: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
});
|
||||
const { optionLabel, options } = toRefs($props);
|
||||
const myOptions = ref([]);
|
||||
|
@ -84,7 +88,7 @@ const value = computed({
|
|||
fill-input
|
||||
ref="vnSelectRef"
|
||||
>
|
||||
<template #append>
|
||||
<template v-if="isClearable" #append>
|
||||
<QIcon name="close" @click.stop="value = null" class="cursor-pointer" />
|
||||
</template>
|
||||
<template v-for="(_, slotName) in $slots" #[slotName]="slotData">
|
||||
|
|
|
@ -41,15 +41,11 @@ onMounted(() => {
|
|||
|
||||
const isLoading = ref(false);
|
||||
async function search() {
|
||||
for (const param in userParams.value) {
|
||||
if (userParams.value[param] === '' || userParams.value[param] === null) {
|
||||
delete userParams.value[param];
|
||||
delete store.userParams[param];
|
||||
}
|
||||
}
|
||||
const params = { ...userParams.value };
|
||||
isLoading.value = true;
|
||||
await arrayData.addFilter({ params });
|
||||
const params = { ...userParams.value };
|
||||
const { params: newParams } = await arrayData.addFilter({ params });
|
||||
userParams.value = newParams;
|
||||
|
||||
if (!props.showAll && !Object.values(params).length) store.data = [];
|
||||
|
||||
isLoading.value = false;
|
||||
|
@ -78,10 +74,11 @@ async function clearFilters() {
|
|||
const tags = computed(() => {
|
||||
const params = [];
|
||||
|
||||
for (const param in store.userParams) {
|
||||
for (const param in userParams.value) {
|
||||
jsegarra
commented
Se puede reemplazar el for por esto
Se puede reemplazar el for por esto
`
Object.entries(userParams.value).filter(([k,v]) => v).reduce((acc,[label, value])=>(
{...acc, [label]: value}
),{})
`
|
||||
if (!userParams.value[param]) continue;
|
||||
params.push({
|
||||
label: param,
|
||||
value: store.userParams[param],
|
||||
value: userParams.value[param],
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -89,8 +86,7 @@ const tags = computed(() => {
|
|||
});
|
||||
|
||||
async function remove(key) {
|
||||
delete userParams.value[key];
|
||||
delete store.userParams[key];
|
||||
userParams.value[key] = null;
|
||||
await search();
|
||||
}
|
||||
|
||||
|
@ -200,7 +196,7 @@ function formatValue(value) {
|
|||
</template>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
es:
|
||||
No filters applied: No se han aplicado filtros
|
||||
Applied filters: Filtros aplicados
|
||||
Remove filters: Eliminar filtros
|
||||
|
|
|
@ -50,6 +50,10 @@ const props = defineProps({
|
|||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
exprBuilder: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['onFetch', 'onPaginate']);
|
||||
|
@ -68,6 +72,7 @@ const arrayData = useArrayData(props.dataKey, {
|
|||
limit: props.limit,
|
||||
order: props.order,
|
||||
userParams: props.userParams,
|
||||
exprBuilder: props.exprBuilder,
|
||||
alexm marked this conversation as resolved
jsegarra
commented
si coinciden todas las claves con el valor de props, quizas se puede hacer
si coinciden todas las claves con el valor de props, quizas se puede hacer
`const arrayData = useArrayData(props.dataKey, {...props}
});`
alexm
commented
De hecho no es un allowProperties De hecho no es un allowProperties
|
||||
});
|
||||
const store = arrayData.store;
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import { onMounted, ref, computed } from 'vue';
|
|||
import { useRouter, useRoute } from 'vue-router';
|
||||
import axios from 'axios';
|
||||
import { useArrayDataStore } from 'stores/useArrayDataStore';
|
||||
import { buildFilter } from 'filters/filterPanel';
|
||||
|
||||
const arrayDataStore = useArrayDataStore();
|
||||
|
||||
|
@ -43,6 +44,7 @@ export function useArrayData(key, userOptions) {
|
|||
'skip',
|
||||
'userParams',
|
||||
'userFilter',
|
||||
'exprBuilder',
|
||||
];
|
||||
if (typeof userOptions === 'object') {
|
||||
for (const option in userOptions) {
|
||||
|
@ -68,16 +70,27 @@ export function useArrayData(key, userOptions) {
|
|||
skip: store.skip,
|
||||
};
|
||||
|
||||
Object.assign(filter, store.userFilter);
|
||||
Object.assign(store.filter, filter);
|
||||
let exprFilter;
|
||||
let userParams = { ...store.userParams };
|
||||
if (store?.exprBuilder) {
|
||||
const where = buildFilter(userParams, (param, value) => {
|
||||
const res = store.exprBuilder(param, value);
|
||||
if (res) delete userParams[param];
|
||||
return res;
|
||||
});
|
||||
exprFilter = where ? { where } : null;
|
||||
}
|
||||
|
||||
Object.assign(filter, store.userFilter, exprFilter);
|
||||
Object.assign(store.filter, filter);
|
||||
const params = {
|
||||
filter: JSON.stringify(store.filter),
|
||||
};
|
||||
|
||||
Object.assign(params, store.userParams);
|
||||
Object.assign(params, userParams);
|
||||
|
||||
store.isLoading = true;
|
||||
|
||||
const response = await axios.get(store.url, {
|
||||
signal: canceller.signal,
|
||||
params,
|
||||
|
@ -126,9 +139,30 @@ export function useArrayData(key, userOptions) {
|
|||
|
||||
async function addFilter({ filter, params }) {
|
||||
if (filter) store.userFilter = Object.assign(store.userFilter, filter);
|
||||
if (params) store.userParams = Object.assign(store.userParams, params);
|
||||
|
||||
let userParams = Object.assign({}, store.userParams, params);
|
||||
userParams = sanitizerParams(userParams, store?.exprBuilder);
|
||||
|
||||
store.userParams = userParams;
|
||||
|
||||
await fetch({ append: false });
|
||||
return { filter, params };
|
||||
}
|
||||
|
||||
function sanitizerParams(params) {
|
||||
for (const param in params) {
|
||||
if (params[param] === '' || params[param] === null) {
|
||||
jsegarra marked this conversation as resolved
jsegarra
commented
Duda, esto es para eliminar los parámetros de búsqueda que tengan valor vacío o null Duda, esto es para eliminar los parámetros de búsqueda que tengan valor vacío o null
alexm
commented
exacto exacto
|
||||
delete store.userParams[param];
|
||||
delete params[param];
|
||||
if (store.filter?.where) {
|
||||
delete store.filter.where[Object.keys(store?.exprBuilder(param))[0]];
|
||||
if (Object.keys(store.filter.where).length === 0) {
|
||||
delete store.filter.where;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
async function loadMore() {
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/**
|
||||
* Passes a loopback fields filter to an object.
|
||||
*
|
||||
* @param {Object} fields The fields object or array
|
||||
* @return {Object} The fields as object
|
||||
*/
|
||||
function fieldsToObject(fields) {
|
||||
alexm marked this conversation as resolved
jsegarra
commented
Lo miramos, porque este método se puede simplificar Lo miramos, porque este método se puede simplificar
alexm
commented
Este archivo es copy paste del de salix (lo hizo Juan) Este archivo es copy paste del de salix (lo hizo Juan)
jsegarra
commented
Ah vale, me salía en verde. Ah vale, me salía en verde.
Entonces, no lo tocamos?
alexm
commented
Yo no lo tocaria Yo no lo tocaria
|
||||
let fieldsObj = {};
|
||||
|
||||
if (Array.isArray(fields)) {
|
||||
for (let field of fields) fieldsObj[field] = true;
|
||||
} else if (typeof fields == 'object') {
|
||||
for (let field in fields) {
|
||||
if (fields[field]) fieldsObj[field] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return fieldsObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges two loopback fields filters.
|
||||
*
|
||||
* @param {Object|Array} src The source fields
|
||||
* @param {Object|Array} dst The destination fields
|
||||
* @return {Array} The merged fields as an array
|
||||
*/
|
||||
function mergeFields(src, dst) {
|
||||
let fields = {};
|
||||
Object.assign(fields, fieldsToObject(src), fieldsToObject(dst));
|
||||
return Object.keys(fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges two loopback where filters.
|
||||
*
|
||||
* @param {Object|Array} src The source where
|
||||
* @param {Object|Array} dst The destination where
|
||||
* @return {Array} The merged wheres
|
||||
*/
|
||||
function mergeWhere(src, dst) {
|
||||
let and = [];
|
||||
if (src) and.push(src);
|
||||
if (dst) and.push(dst);
|
||||
return simplifyOperation(and, 'and');
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges two loopback filters returning the merged filter.
|
||||
*
|
||||
* @param {Object} src The source filter
|
||||
* @param {Object} dst The destination filter
|
||||
* @return {Object} The result filter
|
||||
*/
|
||||
function mergeFilters(src, dst) {
|
||||
let res = Object.assign({}, dst);
|
||||
|
||||
if (!src) return res;
|
||||
|
||||
if (src.fields) res.fields = mergeFields(src.fields, res.fields);
|
||||
if (src.where) res.where = mergeWhere(res.where, src.where);
|
||||
if (src.include) res.include = src.include;
|
||||
if (src.order) res.order = src.order;
|
||||
if (src.limit) res.limit = src.limit;
|
||||
if (src.offset) res.offset = src.offset;
|
||||
if (src.skip) res.skip = src.skip;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function simplifyOperation(operation, operator) {
|
||||
switch (operation.length) {
|
||||
case 0:
|
||||
return undefined;
|
||||
case 1:
|
||||
return operation[0];
|
||||
default:
|
||||
return { [operator]: operation };
|
||||
}
|
||||
}
|
||||
|
||||
function buildFilter(params, builderFunc) {
|
||||
let and = [];
|
||||
|
||||
for (let param in params) {
|
||||
let value = params[param];
|
||||
if (value == null) continue;
|
||||
let expr = builderFunc(param, value);
|
||||
if (expr) and.push(expr);
|
||||
}
|
||||
return simplifyOperation(and, 'and');
|
||||
}
|
||||
|
||||
export { fieldsToObject, mergeFields, mergeWhere, mergeFilters, buildFilter };
|
|
@ -3,6 +3,7 @@ import { ref } from 'vue';
|
|||
import { useI18n } from 'vue-i18n';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
||||
import VnSelectFilter from 'components/common/VnSelectFilter.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps({
|
||||
|
@ -60,7 +61,7 @@ const states = ref();
|
|||
<QSkeleton type="QInput" class="full-width" />
|
||||
</QItemSection>
|
||||
<QItemSection v-if="workers">
|
||||
<QSelect
|
||||
<VnSelectFilter
|
||||
:label="t('Salesperson')"
|
||||
v-model="params.salesPersonFk"
|
||||
@update:model-value="searchFn()"
|
||||
|
@ -79,7 +80,7 @@ const states = ref();
|
|||
<QSkeleton type="QInput" class="full-width" />
|
||||
</QItemSection>
|
||||
<QItemSection v-if="workers">
|
||||
<QSelect
|
||||
<VnSelectFilter
|
||||
:label="t('Attender')"
|
||||
v-model="params.attenderFk"
|
||||
@update:model-value="searchFn()"
|
||||
|
@ -98,7 +99,7 @@ const states = ref();
|
|||
<QSkeleton type="QInput" class="full-width" />
|
||||
</QItemSection>
|
||||
<QItemSection v-if="workers">
|
||||
<QSelect
|
||||
<VnSelectFilter
|
||||
:label="t('Responsible')"
|
||||
v-model="params.claimResponsibleFk"
|
||||
@update:model-value="searchFn()"
|
||||
|
@ -117,7 +118,7 @@ const states = ref();
|
|||
<QSkeleton type="QInput" class="full-width" />
|
||||
</QItemSection>
|
||||
<QItemSection v-if="states">
|
||||
<QSelect
|
||||
<VnSelectFilter
|
||||
:label="t('State')"
|
||||
v-model="params.claimStateFk"
|
||||
@update:model-value="searchFn()"
|
||||
|
|
|
@ -3,6 +3,7 @@ import { ref } from 'vue';
|
|||
import { useI18n } from 'vue-i18n';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
||||
import VnSelectFilter from 'components/common/VnSelectFilter.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps({
|
||||
|
@ -63,7 +64,7 @@ const zones = ref();
|
|||
<QSkeleton type="QInput" class="full-width" />
|
||||
</QItemSection>
|
||||
<QItemSection v-if="workers">
|
||||
<QSelect
|
||||
<VnSelectFilter
|
||||
:label="t('Salesperson')"
|
||||
v-model="params.salesPersonFk"
|
||||
@update:model-value="searchFn()"
|
||||
|
@ -82,7 +83,7 @@ const zones = ref();
|
|||
<QSkeleton type="QInput" class="full-width" />
|
||||
</QItemSection>
|
||||
<QItemSection v-if="provinces">
|
||||
<QSelect
|
||||
<VnSelectFilter
|
||||
:label="t('Province')"
|
||||
v-model="params.provinceFk"
|
||||
@update:model-value="searchFn()"
|
||||
|
@ -91,6 +92,7 @@ const zones = ref();
|
|||
option-label="name"
|
||||
emit-value
|
||||
map-options
|
||||
:input-debounce="0"
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
|
@ -124,7 +126,7 @@ const zones = ref();
|
|||
<QSkeleton type="QInput" class="full-width" />
|
||||
</QItemSection>
|
||||
<QItemSection v-if="zones">
|
||||
<QSelect
|
||||
<VnSelectFilter
|
||||
:label="t('Zone')"
|
||||
v-model="params.zoneFk"
|
||||
@update:model-value="searchFn()"
|
||||
|
|
|
@ -19,6 +19,7 @@ export const useArrayDataStore = defineStore('arrayDataStore', () => {
|
|||
order: '',
|
||||
data: ref(),
|
||||
isLoading: false,
|
||||
exprBuilder: null,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Esto es pq me daba toc, estaba mal alineado