#7356 - Ticket filter #1530
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed, toRef } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useArrayData } from 'composables/useArrayData';
|
import { useArrayData } from 'composables/useArrayData';
|
||||||
import toDate from 'filters/toDate';
|
import toDate from 'filters/toDate';
|
||||||
|
@ -61,6 +61,14 @@ const $props = defineProps({
|
||||||
type: Object,
|
type: Object,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
|
validations: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
excludeParams: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits([
|
const emit = defineEmits([
|
||||||
|
@ -84,18 +92,40 @@ const arrayData =
|
||||||
const store = arrayData.store;
|
const store = arrayData.store;
|
||||||
const userParams = ref(useFilterParams($props.dataKey).params);
|
const userParams = ref(useFilterParams($props.dataKey).params);
|
||||||
const userOrders = ref(useFilterParams($props.dataKey).orders);
|
const userOrders = ref(useFilterParams($props.dataKey).orders);
|
||||||
|
const isLoading = ref(false);
|
||||||
|
const excludeParams = toRef($props.excludeParams);
|
||||||
|
|||||||
|
|
||||||
defineExpose({ search, params: userParams, remove });
|
defineExpose({ search, params: userParams, remove });
|
||||||
|
|
||||||
const isLoading = ref(false);
|
|
||||||
async function search(evt) {
|
async function search(evt) {
|
||||||
try {
|
try {
|
||||||
|
const validations = $props.validations.every((validation) => {
|
||||||
|
return validation(userParams.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!validations) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(userParams.value).length) {
|
||||||
|
excludeParams.value = null;
|
||||||
|
evt = { ...evt?.params };
|
||||||
|
} else if ($props.excludeParams) {
|
||||||
|
excludeParams.value = $props.excludeParams;
|
||||||
|
}
|
||||||
|
|
||||||
if (evt && $props.disableSubmitEvent) return;
|
if (evt && $props.disableSubmitEvent) return;
|
||||||
|
|
||||||
jorgep marked this conversation as resolved
Outdated
jorgep
commented
No veo donde usas el evt. No veo donde usas el **evt**.
|
|||||||
store.filter.where = {};
|
store.filter.where = {};
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
const filter = { ...userParams.value, ...$props.modelValue };
|
let filter = { ...userParams.value, ...$props.modelValue, ...evt };
|
||||||
store.userParamsChanged = true;
|
store.userParamsChanged = true;
|
||||||
|
if (excludeParams.value) {
|
||||||
|
filter = {
|
||||||
|
...filter.params,
|
||||||
|
exclude: excludeParams.value,
|
||||||
|
};
|
||||||
|
}
|
||||||
await arrayData.addFilter({
|
await arrayData.addFilter({
|
||||||
params: filter,
|
params: filter,
|
||||||
});
|
});
|
||||||
|
@ -201,6 +231,7 @@ const getLocale = (label) => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
{{ excludeParams }}
|
||||||
<QBtn
|
<QBtn
|
||||||
class="q-mt-lg q-mr-xs q-mb-lg"
|
class="q-mt-lg q-mr-xs q-mb-lg"
|
||||||
round
|
round
|
||||||
|
@ -222,6 +253,7 @@ const getLocale = (label) => {
|
||||||
</QItemLabel>
|
</QItemLabel>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
<QItemSection top side>
|
<QItemSection top side>
|
||||||
|
{{ excludeParams }}
|
||||||
<QBtn
|
<QBtn
|
||||||
@click="clearFilters"
|
@click="clearFilters"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
|
|
@ -69,6 +69,10 @@ const props = defineProps({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
filterPanel: {
|
||||||
|
type: Object,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const searchText = ref();
|
const searchText = ref();
|
||||||
|
@ -85,6 +89,7 @@ if (props.redirect)
|
||||||
};
|
};
|
||||||
let arrayData = useArrayData(props.dataKey, arrayDataProps);
|
let arrayData = useArrayData(props.dataKey, arrayDataProps);
|
||||||
let store = arrayData.store;
|
let store = arrayData.store;
|
||||||
|
const filterPanel = ref(props.filterPanel);
|
||||||
const to = computed(() => {
|
const to = computed(() => {
|
||||||
const url = { path: route.path, query: { ...(route.query ?? {}) } };
|
const url = { path: route.path, query: { ...(route.query ?? {}) } };
|
||||||
const searchUrl = arrayData.store.searchUrl;
|
const searchUrl = arrayData.store.searchUrl;
|
||||||
|
@ -104,6 +109,12 @@ watch(
|
||||||
store = arrayData.store;
|
store = arrayData.store;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
watch(
|
||||||
|
() => props.filterPanel,
|
||||||
|
(val) => {
|
||||||
|
filterPanel.value = val;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const params = store.userParams;
|
const params = store.userParams;
|
||||||
|
@ -116,7 +127,10 @@ async function search() {
|
||||||
arrayData.resetPagination();
|
arrayData.resetPagination();
|
||||||
|
|
||||||
let filter = { params: { search: searchText.value } };
|
let filter = { params: { search: searchText.value } };
|
||||||
|
if (filterPanel?.value?.filterPanelRef) {
|
||||||
jorgep
commented
No sería más fácil que crearas un composable useFilterPanelSearch ? De todas maneras, creo que lo ideal sería que el searchbar y el filterPanel usen la misma lógica(respecto a arrayData) ya que ambos llaman al mismo back. Incluso crearía un solo composable para ambos. @alexm ¿cómo lo ves? No sería más fácil que crearas un composable **useFilterPanelSearch** ? De todas maneras, creo que lo ideal sería que el searchbar y el filterPanel usen la misma lógica(respecto a arrayData) ya que ambos llaman al mismo back. Incluso crearía un solo composable para ambos. @alexm ¿cómo lo ves?
jsegarra
commented
no lo veo no lo veo
un ejemplo?
jsegarra
commented
1. VnSarchbar y VnFilterPanel, son componentes independientes que sus funciones de search no se parecen entre si, por lo que tener un composable que tenga la función search valida para ambos lo veo, complicado, peligroso e innecesario.
2. Si lo que se quiere hacer es un refactor, esta tarea no tiene ese objetivo
3. "creo que lo ideal sería que el searchbar y el filterPanel usen la misma lógica(respecto a arrayData) ya que ambos llaman al mismo back"...nos sentamos a revisarlo juntos porque searchbar está llamando a su lógica y solo cuando se le indica, casos específicos, que use filterpanel lo hace, que es el caso de TicketFilter.
4. *Por otra parte*, searchbar no se le está modificando el comportamiento con respecto a arrayData
jorgep
commented
No veo lo de pasar el componente como propiedad, que te diga @alexm su opinión. No veo lo de pasar el componente como propiedad, que te diga @alexm su opinión.
jsegarra
commented
Ni yo, pero por el ciclo de vida de VnSection, provide/inject no se puede hacer Ni yo, pero por el ciclo de vida de VnSection, provide/inject no se puede hacer
Vamos a hacer de meter el TicketFilter dentro de VnSection
|
|||||||
|
filterPanel.value.filterPanelRef.search(filter);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!props.searchRemoveParams || !searchText.value) {
|
if (!props.searchRemoveParams || !searchText.value) {
|
||||||
filter = {
|
filter = {
|
||||||
params: {
|
params: {
|
||||||
|
|
|
@ -75,12 +75,13 @@ export function useArrayData(key, userOptions) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetch({ append = false, updateRouter = true }) {
|
async function fetch(fetchOptions) {
|
||||||
|
let { append = false, updateRouter = true } = fetchOptions ?? {};
|
||||||
if (!store.url) return;
|
if (!store.url) return;
|
||||||
|
|
||||||
cancelRequest();
|
cancelRequest();
|
||||||
canceller = new AbortController();
|
canceller = new AbortController();
|
||||||
const { params, limit } = setCurrentFilter();
|
let { params, limit } = setCurrentFilter();
|
||||||
|
|
||||||
let exprFilter;
|
let exprFilter;
|
||||||
if (store?.exprBuilder) {
|
if (store?.exprBuilder) {
|
||||||
|
@ -98,7 +99,11 @@ export function useArrayData(key, userOptions) {
|
||||||
if (!params?.filter?.order?.length) delete params?.filter?.order;
|
if (!params?.filter?.order?.length) delete params?.filter?.order;
|
||||||
|
|
||||||
params.filter = JSON.stringify(params.filter);
|
params.filter = JSON.stringify(params.filter);
|
||||||
|
if (fetchOptions?.exclude) {
|
||||||
|
delete params?.exclude;
|
||||||
|
delete params?.params?.exclude;
|
||||||
|
params = { ...params, ...fetchOptions.exclude };
|
||||||
|
}
|
||||||
store.isLoading = true;
|
store.isLoading = true;
|
||||||
const response = await axios.get(store.url, {
|
const response = await axios.get(store.url, {
|
||||||
signal: canceller.signal,
|
signal: canceller.signal,
|
||||||
|
@ -150,6 +155,10 @@ export function useArrayData(key, userOptions) {
|
||||||
async function applyFilter({ filter, params }, fetchOptions = {}) {
|
async function applyFilter({ filter, params }, fetchOptions = {}) {
|
||||||
if (filter) store.userFilter = filter;
|
if (filter) store.userFilter = filter;
|
||||||
store.filter = {};
|
store.filter = {};
|
||||||
|
if (params?.exclude) {
|
||||||
|
fetchOptions = { ...fetchOptions, exclude: params.exclude };
|
||||||
|
delete params.exclude;
|
||||||
|
}
|
||||||
if (params) store.userParams = { ...params };
|
if (params) store.userParams = { ...params };
|
||||||
|
|
||||||
const response = await fetch(fetchOptions);
|
const response = await fetch(fetchOptions);
|
||||||
|
@ -158,14 +167,19 @@ export function useArrayData(key, userOptions) {
|
||||||
|
|
||||||
async function addFilter({ filter, params }) {
|
async function addFilter({ filter, params }) {
|
||||||
if (filter) store.filter = filter;
|
if (filter) store.filter = filter;
|
||||||
|
let exclude = {};
|
||||||
|
if (params?.exclude) {
|
||||||
jorgep
commented
Por qué params.params? Por qué params.params?
jsegarra
commented
SOLVED en b5549dae8813235e9be27aebcddafdb07d05ad88 SOLVED en b5549dae8813235e9be27aebcddafdb07d05ad88
|
|||||||
|
exclude = params.exclude;
|
||||||
|
|
||||||
|
delete params.exclude;
|
||||||
|
}
|
||||||
let userParams = { ...store.userParams, ...params };
|
let userParams = { ...store.userParams, ...params };
|
||||||
userParams = sanitizerParams(userParams, store?.exprBuilder);
|
userParams = sanitizerParams(userParams, store?.exprBuilder);
|
||||||
|
|
||||||
store.userParams = userParams;
|
store.userParams = userParams;
|
||||||
resetPagination();
|
resetPagination();
|
||||||
|
|
||||||
await fetch({});
|
await fetch({ exclude });
|
||||||
return { filter, params };
|
return { filter, params };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
||||||
|
@ -8,6 +9,7 @@ import VnInput from 'src/components/common/VnInput.vue';
|
||||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
||||||
|
import useNotify from 'src/composables/useNotify';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
@ -16,13 +18,34 @@ const props = defineProps({
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const route = useRoute();
|
||||||
|
const userParams = {
|
||||||
|
from: null,
|
||||||
|
to: null,
|
||||||
|
};
|
||||||
|
const filterPanelRef = ref(null);
|
||||||
|
|
||||||
|
defineExpose({ filterPanelRef });
|
||||||
const provinces = ref([]);
|
const provinces = ref([]);
|
||||||
const states = ref([]);
|
const states = ref([]);
|
||||||
const agencies = ref([]);
|
const agencies = ref([]);
|
||||||
const warehouses = ref([]);
|
const warehouses = ref([]);
|
||||||
const groupedStates = ref([]);
|
const groupedStates = ref([]);
|
||||||
|
const { notify } = useNotify();
|
||||||
|
const from = ref(Date.vnNew());
|
||||||
|
const to = ref(Date.vnNew());
|
||||||
|
const initializeFromQuery = computed(() => {
|
||||||
jorgep
commented
from y to no son ref from y to no son **ref**
jsegarra
commented
Copy paste, pero lo modifico Copy paste, pero lo modifico
jsegarra
commented
b5549dae8813235e9be27aebcddafdb07d05ad88 b5549dae8813235e9be27aebcddafdb07d05ad88
|
|||||||
|
from.value.setHours(0, 0, 0, 0);
|
||||||
|
from.value.setDate(from.value.getDate() - 7);
|
||||||
|
to.value.setHours(23, 59, 0, 0);
|
||||||
|
to.value.setDate(to.value.getDate() + 1);
|
||||||
|
const query = route.query.table ? JSON.parse(route.query.table) : {};
|
||||||
|
Object.assign(userParams, {
|
||||||
|
from: query.from || from.value.toISOString(),
|
||||||
|
to: query.to || to.value.toISOString(),
|
||||||
|
});
|
||||||
|
return userParams;
|
||||||
|
});
|
||||||
const getGroupedStates = (data) => {
|
const getGroupedStates = (data) => {
|
||||||
for (const state of data) {
|
for (const state of data) {
|
||||||
groupedStates.value.push({
|
groupedStates.value.push({
|
||||||
|
@ -32,6 +55,17 @@ const getGroupedStates = (data) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function validateDateRange(params) {
|
||||||
|
const hasFrom = 'from' in params;
|
||||||
|
const hasTo = 'to' in params;
|
||||||
jorgep marked this conversation as resolved
jorgep
commented
Comentario, no sería mejor lanzar error? y así en caso de ser erróneo el usuario puede abrir un cau? Comentario, no sería mejor lanzar error? y así en caso de ser erróneo el usuario puede abrir un cau?
jsegarra
commented
Pero no es un error para abrir un cau sino es una validación previa a llamar a search Pero no es un error para abrir un cau sino es una validación previa a llamar a search
La función se llama validate
|
|||||||
|
|
||||||
|
if (hasFrom !== hasTo) {
|
||||||
|
notify(t(`dateRangeMustHaveBothFrom`), 'negative');
|
||||||
|
}
|
||||||
jorgep
commented
return hasFrom === hasTo , yo lo guardaría en una variable y así lo puedes usar en el if también. **return hasFrom === hasTo** , yo lo guardaría en una variable y así lo puedes usar en el if también.
jsegarra
commented
Son 3 validaciones distintas
Son 3 validaciones distintas
1. Cuando son diferentes
2. Cuando son iguales
3. Cuando son null las 2
jorgep
commented
(hasFrom && hasTo) || (!hasFrom && !hasTo) es lo mismo que hasFrom === hasTo y hasFrom !== hasTo también es lo mismo que !(hasFrom === hasTo). **(hasFrom && hasTo) || (!hasFrom && !hasTo)** es lo mismo que **hasFrom === hasTo** y **hasFrom !== hasTo** también es lo mismo que **!(hasFrom === hasTo)**.
jsegarra
commented
has es booleano has es booleano
comparamos booleanos? o se entiende mejor de esta manera?
En un if no haces hasFrom === true, no?
|
|||||||
|
|
||||||
jorgep
commented
(hasFrom && hasTo) || (!hasFrom && !hasTo) es lo mismo que esto: hasFrom === hasTo? GitHub Copilot Ambas expresiones verifican si hasFrom y hasTo son ambos verdaderos o ambos falsos. Aquí está la explicación: (hasFrom && hasTo): Esto es verdadero si ambos hasFrom y hasTo son verdaderos. Por lo tanto, puedes simplificar (hasFrom && hasTo) || (!hasFrom && !hasTo) a hasFrom === hasTo. (hasFrom && hasTo) || (!hasFrom && !hasTo) es lo mismo que esto: hasFrom === hasTo?
GitHub Copilot
Sí, la expresión (hasFrom && hasTo) || (!hasFrom && !hasTo) es lógicamente equivalente a hasFrom === hasTo.
Ambas expresiones verifican si hasFrom y hasTo son ambos verdaderos o ambos falsos. Aquí está la explicación:
(hasFrom && hasTo): Esto es verdadero si ambos hasFrom y hasTo son verdaderos.
(!hasFrom && !hasTo): Esto es verdadero si ambos hasFrom y hasTo son falsos.
La expresión completa (hasFrom && hasTo) || (!hasFrom && !hasTo) es verdadera si ambos son verdaderos o ambos son falsos.
La expresión hasFrom === hasTo también es verdadera si ambos son verdaderos o ambos son falsos, ya que compara directamente los valores de hasFrom y hasTo.
Por lo tanto, puedes simplificar (hasFrom && hasTo) || (!hasFrom && !hasTo) a hasFrom === hasTo.
|
|||||||
|
return (hasFrom && hasTo) || (!hasFrom && !hasTo);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -53,7 +87,13 @@ const getGroupedStates = (data) => {
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
<FetchData url="Warehouses" @on-fetch="(data) => (warehouses = data)" auto-load />
|
<FetchData url="Warehouses" @on-fetch="(data) => (warehouses = data)" auto-load />
|
||||||
<VnFilterPanel :data-key="props.dataKey" :search-button="true">
|
<VnFilterPanel
|
||||||
|
ref="filterPanelRef"
|
||||||
|
:data-key="props.dataKey"
|
||||||
|
:search-button="true"
|
||||||
|
:validations="[validateDateRange]"
|
||||||
|
:exclude-params="initializeFromQuery"
|
||||||
|
>
|
||||||
<template #tags="{ tag, formatFn }">
|
<template #tags="{ tag, formatFn }">
|
||||||
<div class="q-gutter-x-xs">
|
<div class="q-gutter-x-xs">
|
||||||
<strong>{{ t(`params.${tag.label}`) }}: </strong>
|
<strong>{{ t(`params.${tag.label}`) }}: </strong>
|
||||||
|
@ -301,6 +341,7 @@ const getGroupedStates = (data) => {
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
en:
|
en:
|
||||||
|
dateRangeMustHaveBothFrom: The date range must have both 'from' and 'to'
|
||||||
params:
|
params:
|
||||||
search: Contains
|
search: Contains
|
||||||
clientFk: Customer
|
clientFk: Customer
|
||||||
|
@ -329,6 +370,7 @@ en:
|
||||||
DELIVERED: Delivered
|
DELIVERED: Delivered
|
||||||
ON_PREVIOUS: ON_PREVIOUS
|
ON_PREVIOUS: ON_PREVIOUS
|
||||||
es:
|
es:
|
||||||
|
dateRangeMustHaveBothFrom: El rango de fechas debe tener 'desde' y 'hasta'
|
||||||
params:
|
params:
|
||||||
search: Contiene
|
search: Contiene
|
||||||
clientFk: Cliente
|
clientFk: Cliente
|
||||||
|
|
|
@ -43,12 +43,8 @@ from.setDate(from.getDate() - 7);
|
||||||
const to = Date.vnNew();
|
const to = Date.vnNew();
|
||||||
to.setHours(23, 59, 0, 0);
|
to.setHours(23, 59, 0, 0);
|
||||||
to.setDate(to.getDate() + 1);
|
to.setDate(to.getDate() + 1);
|
||||||
const userParams = {
|
|
||||||
from: null,
|
|
||||||
to: null,
|
|
||||||
};
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
initializeFromQuery();
|
|
||||||
stateStore.rightDrawer = true;
|
stateStore.rightDrawer = true;
|
||||||
});
|
});
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
@ -79,6 +75,7 @@ const companiesOptions = ref([]);
|
||||||
const accountingOptions = ref([]);
|
const accountingOptions = ref([]);
|
||||||
const amountToReturn = ref();
|
const amountToReturn = ref();
|
||||||
const dataKey = 'TicketList';
|
const dataKey = 'TicketList';
|
||||||
|
const filterPanelRef = ref(null);
|
||||||
const formInitialData = ref({});
|
const formInitialData = ref({});
|
||||||
|
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
|
@ -483,11 +480,17 @@ function setReference(data) {
|
||||||
:array-data-props="{
|
:array-data-props="{
|
||||||
url: 'Tickets/filter',
|
url: 'Tickets/filter',
|
||||||
order: ['shippedDate DESC', 'shippedHour ASC', 'zoneLanding ASC', 'id'],
|
order: ['shippedDate DESC', 'shippedHour ASC', 'zoneLanding ASC', 'id'],
|
||||||
|
filterPanel: filterPanelRef,
|
||||||
|
searchRemoveParams: true,
|
||||||
exprBuilder,
|
exprBuilder,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<template #advanced-menu>
|
<template #advanced-menu>
|
||||||
<TicketFilter data-key="TicketList" />
|
<TicketFilter
|
||||||
|
ref="filterPanelRef"
|
||||||
|
data-key="TicketList"
|
||||||
|
:excludeParams="{ ...userParams }"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #body>
|
<template #body>
|
||||||
<VnTable
|
<VnTable
|
||||||
|
@ -501,7 +504,6 @@ function setReference(data) {
|
||||||
}"
|
}"
|
||||||
default-mode="table"
|
default-mode="table"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:user-params="userParams"
|
|
||||||
:right-search="false"
|
:right-search="false"
|
||||||
redirect="ticket"
|
redirect="ticket"
|
||||||
v-model:selected="selectedRows"
|
v-model:selected="selectedRows"
|
||||||
|
@ -581,7 +583,7 @@ function setReference(data) {
|
||||||
:options="clientsOptions"
|
:options="clientsOptions"
|
||||||
hide-selected
|
hide-selected
|
||||||
required
|
required
|
||||||
@update:model-value="() => onClientSelected(data)"
|
@update:model-value="onClientSelected(data)"
|
||||||
:sort-by="'id ASC'"
|
:sort-by="'id ASC'"
|
||||||
>
|
>
|
||||||
<template #option="scope">
|
<template #option="scope">
|
||||||
|
|
|
@ -6,10 +6,39 @@ describe('TicketFilter', () => {
|
||||||
cy.visit('/#/ticket/list');
|
cy.visit('/#/ticket/list');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('use search button', function () {
|
it('use search button', () => {
|
||||||
cy.waitForElement('.q-page');
|
cy.waitForElement('.q-page');
|
||||||
cy.get('[data-cy="Customer ID_input"]').type('1105');
|
cy.intercept('GET', /\/api\/Tickets\/filter/).as('ticketFilter');
|
||||||
cy.searchBtnFilterPanel();
|
cy.searchBtnFilterPanel();
|
||||||
cy.location('href').should('contain', '#/ticket/15/summary');
|
cy.waitRequest('@ticketFilter', ({ request }) => {
|
||||||
|
const { query } = request;
|
||||||
|
expect(query).to.have.property('from');
|
||||||
|
expect(query).to.have.property('to');
|
||||||
|
});
|
||||||
|
// cy.on('uncaught:exception', () => {
|
||||||
|
// return false;
|
||||||
jsegarra marked this conversation as resolved
Outdated
jorgep
commented
Estas ignorando un error no capturado? porque? Estas ignorando un error no capturado? porque?
|
|||||||
|
// });
|
||||||
|
cy.dataCy('From_inputDate').type(`${today()} `).type('{enter}');
|
||||||
|
cy.get('.q-notification').should(
|
||||||
|
'contain',
|
||||||
|
`The date range must have both 'from' and 'to'`,
|
||||||
|
);
|
||||||
|
|
||||||
|
cy.dataCy('To_inputDate').type(`${today()}{enter}`);
|
||||||
|
cy.intercept('GET', /\/api\/Tickets\/filter/).as('ticketFilter');
|
||||||
|
cy.searchBtnFilterPanel();
|
||||||
|
cy.wait('@ticketFilter').then(({ request }) => {
|
||||||
|
const { query } = request;
|
||||||
|
expect(query).to.have.property('from');
|
||||||
|
expect(query).to.have.property('to');
|
||||||
|
});
|
||||||
|
cy.location('href').should('contain', '#/ticket/999999');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
function today(date) {
|
||||||
|
return new Intl.DateTimeFormat('es-ES', {
|
||||||
|
day: '2-digit',
|
||||||
|
month: '2-digit',
|
||||||
|
year: 'numeric',
|
||||||
|
}).format(date ?? new Date());
|
||||||
|
}
|
||||||
|
|
|
@ -35,6 +35,31 @@ describe('TicketList', () => {
|
||||||
cy.get('.summaryBody').should('exist');
|
cy.get('.summaryBody').should('exist');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('filter client and create ticket', () => {
|
||||||
|
cy.intercept('GET', /\/api\/Tickets\/filter/).as('ticketSearchbar');
|
||||||
|
searchResults();
|
||||||
|
cy.wait('@ticketSearchbar').then(({ request }) => {
|
||||||
jorgep
commented
Veo bien que compruebes los parametros que se envian en la solicitud, pero también creo que es importante comprobar que en el DOM se ha actualizado con los valores correctos. Ej. ver solo los tickets del 1 al 30 de febrero Veo bien que compruebes los parametros que se envian en la solicitud, pero también creo que es importante comprobar que en el DOM se ha actualizado con los valores correctos. Ej. ver solo los tickets del 1 al 30 de febrero
|
|||||||
|
const { query } = request;
|
||||||
|
expect(query).to.have.property('from');
|
||||||
|
expect(query).to.have.property('to');
|
||||||
|
expect(query).to.not.have.property('clientFk');
|
||||||
|
});
|
||||||
|
cy.intercept('GET', /\/api\/Tickets\/filter/).as('ticketFilter');
|
||||||
|
cy.dataCy('Customer ID_input').clear('1');
|
||||||
|
cy.dataCy('Customer ID_input').type('1101{enter}');
|
||||||
|
cy.wait('@ticketFilter').then(({ request }) => {
|
||||||
|
const { query } = request;
|
||||||
|
expect(query).to.not.have.property('from');
|
||||||
|
expect(query).to.not.have.property('to');
|
||||||
|
expect(query).to.have.property('clientFk');
|
||||||
|
});
|
||||||
|
cy.get('[data-cy="vnTableCreateBtn"] > .q-btn__content > .q-icon').click();
|
||||||
|
cy.dataCy('Customer_select').should('have.value', 'Bruce Wayne');
|
||||||
|
cy.dataCy('Address_select').click();
|
||||||
|
|
||||||
|
cy.getOption().click();
|
||||||
|
cy.dataCy('Address_select').should('have.value', 'Bruce Wayne');
|
||||||
|
});
|
||||||
it('filter client and create ticket', () => {
|
it('filter client and create ticket', () => {
|
||||||
cy.intercept('GET', /\/api\/Tickets\/filter/).as('ticketSearchbar');
|
cy.intercept('GET', /\/api\/Tickets\/filter/).as('ticketSearchbar');
|
||||||
searchResults();
|
searchResults();
|
||||||
|
@ -66,7 +91,7 @@ describe('TicketList', () => {
|
||||||
cy.url().should('match', /\/ticket\/\d+\/summary/);
|
cy.url().should('match', /\/ticket\/\d+\/summary/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show the correct problems', () => {
|
it.only('should show the correct problems', () => {
|
||||||
cy.intercept('GET', '**/api/Tickets/filter*', (req) => {
|
cy.intercept('GET', '**/api/Tickets/filter*', (req) => {
|
||||||
req.headers['cache-control'] = 'no-cache';
|
req.headers['cache-control'] = 'no-cache';
|
||||||
req.headers['pragma'] = 'no-cache';
|
req.headers['pragma'] = 'no-cache';
|
||||||
|
@ -81,7 +106,7 @@ describe('TicketList', () => {
|
||||||
cy.get('[data-cy="Warehouse_select"]').type('Warehouse Five');
|
cy.get('[data-cy="Warehouse_select"]').type('Warehouse Five');
|
||||||
cy.get('.q-menu .q-item').contains('Warehouse Five').click();
|
cy.get('.q-menu .q-item').contains('Warehouse Five').click();
|
||||||
cy.wait('@ticket').then((interception) => {
|
cy.wait('@ticket').then((interception) => {
|
||||||
const data = interception.response.body[1];
|
const data = interception.response.body.at(-1);
|
||||||
expect(data.hasComponentLack).to.equal(1);
|
expect(data.hasComponentLack).to.equal(1);
|
||||||
expect(data.isTooLittle).to.equal(1);
|
expect(data.isTooLittle).to.equal(1);
|
||||||
expect(data.hasItemShortage).to.equal(1);
|
expect(data.hasItemShortage).to.equal(1);
|
||||||
|
|
Usar toRef .
Copilot dice:
Usar ref directamente en $props no es la mejor práctica porque $props ya es reactivo por defecto en Vue 3. Si necesitas una referencia reactiva a una propiedad específica de $props, toRef es más adecuado. Sin embargo, si decides usar ref, tendrías que hacer una copia de la propiedad para que sea reactiva, lo cual no es necesario con toRef.
b5549dae8813235e9be27aebcddafdb07d05ad88