Merge pull request '#8949 - Perf: VnCheckboxMenu' (!1749) from fix_vnMultiCheck into dev
gitea/salix-front/pipeline/head This commit looks good Details

Reviewed-on: #1749
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
Reviewed-by: Pablo Natek <pablone@verdnatura.es>
This commit is contained in:
Javier Segarra 2025-04-29 16:52:35 +00:00
commit 6bffb4614a
5 changed files with 124 additions and 98 deletions

View File

@ -34,7 +34,7 @@ import VnTableFilter from './VnTableFilter.vue';
import { getColAlign } from 'src/composables/getColAlign'; import { getColAlign } from 'src/composables/getColAlign';
import RightMenu from '../common/RightMenu.vue'; import RightMenu from '../common/RightMenu.vue';
import VnScroll from '../common/VnScroll.vue'; import VnScroll from '../common/VnScroll.vue';
import VnMultiCheck from '../common/VnMultiCheck.vue'; import VnCheckboxMenu from '../common/VnCheckboxMenu.vue';
const arrayData = useArrayData(useAttrs()['data-key']); const arrayData = useArrayData(useAttrs()['data-key']);
const $props = defineProps({ const $props = defineProps({
@ -644,21 +644,15 @@ const rowCtrlClickFunction = computed(() => {
}; };
return () => {}; return () => {};
}); });
const handleMultiCheck = (value) => { const handleHeaderSelection = (evt, data) => {
if (value) { if (evt === 'selected' && data) {
selected.value = tableRef.value.rows; selected.value = tableRef.value.rows;
} else { } else if (evt === 'selectAll') {
selected.value = [];
}
emit('update:selected', selected.value);
};
const handleSelectedAll = (data) => {
if (data) {
selected.value = data; selected.value = data;
} else { } else {
selected.value = []; selected.value = [];
} }
emit('update:selected', selected.value); emit('update:selected', selected.value);
}; };
</script> </script>
@ -724,14 +718,14 @@ const handleSelectedAll = (data) => {
:data-cy :data-cy
> >
<template #header-selection> <template #header-selection>
<VnMultiCheck <VnCheckboxMenu
:searchUrl="searchUrl" :searchUrl="searchUrl"
:expand="$props.multiCheck.expand" :expand="$props.multiCheck.expand"
v-model="selectAll" v-model="selectAll"
:url="$attrs['url']" :url="$attrs['url']"
@update:selected="handleMultiCheck" @update:selected="handleHeaderSelection('selected', $event)"
@select:all="handleSelectedAll" @select:all="handleHeaderSelection('selectAll', $event)"
></VnMultiCheck> />
</template> </template>
<template #top-left v-if="!$props.withoutHeader"> <template #top-left v-if="!$props.withoutHeader">

View File

@ -0,0 +1,113 @@
<script setup>
import { ref } from 'vue';
import VnCheckbox from './VnCheckbox.vue';
import axios from 'axios';
import { toRaw } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
const route = useRoute();
const { t } = useI18n();
const model = defineModel({ type: [Boolean] });
const props = defineProps({
expand: {
type: Boolean,
default: false,
},
url: {
type: String,
required: true,
},
searchUrl: {
type: [String, Boolean],
default: 'table',
},
});
const value = ref(false);
const menuRef = ref(null);
const errorMessage = ref(null);
const rows = ref(0);
const onClick = async () => {
if (value.value) {
const { filter } = JSON.parse(route.query[props.searchUrl]);
filter.limit = 0;
const params = {
params: { filter: JSON.stringify(filter) },
};
try {
const { data } = await axios.get(props.url, params);
rows.value = data;
} catch (error) {
const response = error.response;
if (response.data.error.name === 'UserError') {
errorMessage.value = t('tooManyResults');
} else {
errorMessage.value = response.data.error.message;
}
}
}
};
defineEmits(['update:selected', 'select:all']);
</script>
<template>
<div class="flex items-center no-wrap" style="display: flex">
<VnCheckbox v-model="value" @click="$emit('update:selected', value)" />
<QIcon
style="margin-left: -10px"
data-cy="btnMultiCheck"
v-if="value && $props.expand"
name="expand_more"
@click="onClick"
class="cursor-pointer"
color="primary"
size="xs"
>
<QMenu
fit
anchor="bottom start"
self="top left"
ref="menuRef"
data-cy="menuMultiCheck"
>
<QList separator>
<QItem
data-cy="selectAll"
v-ripple
clickable
@click="
$refs.menuRef.hide();
$emit('select:all', toRaw(rows));
"
>
<QItemSection>
<QItemLabel>
<span v-text="t('Select all')" />
</QItemLabel>
<QItemLabel overline caption>
<span
v-if="errorMessage"
class="text-negative"
v-text="errorMessage"
/>
<span
v-else
v-text="t('records', { rows: rows.length })"
/>
</QItemLabel>
</QItemSection>
</QItem>
<slot name="more-options"></slot>
</QList>
</QMenu>
</QIcon>
</div>
</template>
<i18n lang="yml">
en:
tooManyResults: Too many results. Please narrow down your search.
records: '{rows} records'
es:
Select all: Seleccionar todo
tooManyResults: Demasiados registros. Restringe la búsqueda.
records: '{rows} registros'
</i18n>

View File

@ -1,80 +0,0 @@
<script setup>
import { ref } from 'vue';
import VnCheckbox from './VnCheckbox.vue';
import axios from 'axios';
import { toRaw } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
const route = useRoute();
const { t } = useI18n();
const model = defineModel({ type: [Boolean] });
const props = defineProps({
expand: {
type: Boolean,
default: false,
},
url: {
type: String,
default: null,
required: true,
},
searchUrl: {
type: [String, Boolean],
default: 'table',
},
});
const value = ref(false);
const rows = ref(0);
const onClick = () => {
if (value.value) {
const { filter } = JSON.parse(route.query[props.searchUrl]);
filter.limit = 0;
const params = {
params: { filter: JSON.stringify(filter) },
};
axios
.get(props.url, params)
.then(({ data }) => {
rows.value = data;
})
.catch(console.error);
}
};
defineEmits(['update:selected', 'select:all']);
</script>
<template>
<div style="display: flex">
<VnCheckbox v-model="value" @click="$emit('update:selected', value)" />
<QBtn
v-if="value && $props.expand"
flat
dense
icon="expand_more"
@click="onClick"
>
<QMenu anchor="bottom right" self="top right">
<QList>
<QItem v-ripple clickable @click="$emit('select:all', toRaw(rows))">
{{ t('Select all', { rows: rows.length }) }}
</QItem>
<slot name="more-options"></slot>
</QList>
</QMenu>
</QBtn>
</div>
</template>
<i18n lang="yml">
en:
Select all: 'Select all ({rows})'
fr:
Select all: 'Sélectionner tout ({rows})'
es:
Select all: 'Seleccionar todo ({rows})'
de:
Select all: 'Alle auswählen ({rows})'
it:
Select all: 'Seleziona tutto ({rows})'
pt:
Select all: 'Selecionar tudo ({rows})'
</i18n>

View File

@ -89,7 +89,6 @@ const columns = computed(() => [
<CustomerNotificationsCampaignConsumption <CustomerNotificationsCampaignConsumption
:selected-rows="selected.length > 0" :selected-rows="selected.length > 0"
:clients="selected" :clients="selected"
:promise="refreshData"
/> />
</template> </template>
</VnSubToolbar> </VnSubToolbar>

View File

@ -142,13 +142,13 @@ onMounted(async () => {
valentinesDay: Valentine's Day valentinesDay: Valentine's Day
mothersDay: Mother's Day mothersDay: Mother's Day
allSaints: All Saints' Day allSaints: All Saints' Day
Campaign consumption: Campaign consumption ({rows}) Campaign consumption: Campaign consumption - {rows} records
es: es:
params: params:
valentinesDay: Día de San Valentín valentinesDay: Día de San Valentín
mothersDay: Día de la Madre mothersDay: Día de la Madre
allSaints: Día de Todos los Santos allSaints: Día de Todos los Santos
Campaign consumption: Consumo campaña ({rows}) Campaign consumption: Consumo campaña - {rows} registros
Campaign: Campaña Campaign: Campaña
From: Desde From: Desde
To: Hasta To: Hasta