0
0
Fork 0

Merge branch '6825-vnTable' of https://gitea.verdnatura.es/verdnatura/salix-front into 7406-workerFormation

This commit is contained in:
Carlos Satorres 2024-05-27 10:07:49 +02:00
commit e6ff13c09c
6 changed files with 80 additions and 606 deletions

View File

@ -89,11 +89,15 @@ const components = {
async function addFilter(value) { async function addFilter(value) {
if (value && typeof value === 'object') value = model.value; if (value && typeof value === 'object') value = model.value;
value = value === '' ? null : value; value = value === '' ? undefined : value;
let field = columnFilter.value?.name ?? $props.column.name; let field = columnFilter.value?.name ?? $props.column.name;
const toFilter = { [field]: value };
await arrayData.addFilter({ params: toFilter }); let params = { [field]: value };
if (columnFilter.value?.inWhere) {
if (columnFilter.value.prefix) field = columnFilter.value.prefix + '.' + field;
params = { filter: { where: params } };
}
await arrayData.addFilter({ params });
} }
function alignRow() { function alignRow() {

View File

@ -148,6 +148,7 @@ defineExpose({
:data-key="$attrs['data-key']" :data-key="$attrs['data-key']"
:search-button="true" :search-button="true"
v-model="params" v-model="params"
:disable-submit-event="true"
> >
<template #body> <template #body>
<VnTableFilter <VnTableFilter
@ -242,10 +243,7 @@ defineExpose({
</template> </template>
<template #body-cell="{ col, row }"> <template #body-cell="{ col, row }">
<!-- Columns --> <!-- Columns -->
<QTd <QTd class="no-margin" :class="`text-${col.align ?? 'left'}`">
class="no-padding no-margin"
:class="`text-${col.align ?? 'left'}`"
>
<VnTableColumn <VnTableColumn
:column="col" :column="col"
:row="row" :row="row"

View File

@ -42,6 +42,10 @@ const props = defineProps({
type: Array, type: Array,
default: () => [], default: () => [],
}, },
disableSubmitEvent: {
type: Boolean,
default: false,
},
}); });
const emit = defineEmits(['refresh', 'clear', 'search', 'init', 'remove']); const emit = defineEmits(['refresh', 'clear', 'search', 'init', 'remove']);
@ -58,7 +62,11 @@ onMounted(() => {
if (params.value) userParams.value = JSON.parse(JSON.stringify(params.value)); if (params.value) userParams.value = JSON.parse(JSON.stringify(params.value));
if (Object.keys(store.userParams).length > 0) { if (Object.keys(store.userParams).length > 0) {
userParams.value = JSON.parse(JSON.stringify(store.userParams)); userParams.value = JSON.parse(JSON.stringify(store.userParams));
params.value = { ...params.value, ...userParams.value }; params.value = {
...params.value,
...userParams.value,
...userParams.value?.filter?.where,
};
} }
emit('init', { params: userParams.value }); emit('init', { params: userParams.value });
}); });
@ -67,7 +75,7 @@ function setUserParams(params) {
if (!params) { if (!params) {
userParams.value = {}; userParams.value = {};
} else { } else {
userParams.value = params; userParams.value = typeof params == 'string' ? JSON.parse(params) : params;
} }
} }
@ -86,7 +94,9 @@ watch(
); );
const isLoading = ref(false); const isLoading = ref(false);
async function search() { async function search(evt) {
if (evt && props.disableSubmitEvent) return;
store.filter.where = {}; store.filter.where = {};
isLoading.value = true; isLoading.value = true;
const filter = { ...userParams.value, ...params.value }; const filter = { ...userParams.value, ...params.value };
@ -141,23 +151,33 @@ async function clearFilters() {
} }
const tagsList = computed(() => { const tagsList = computed(() => {
return Object.entries(userParams.value) const tagList = [];
.filter(([key, value]) => value && !(props.hiddenTags || []).includes(key)) const params = {
.map(([key, value]) => ({ ...userParams.value,
label: key, };
value: value, const where = params?.filter?.where;
})); if (where) {
Object.assign(params, where);
}
delete params.filter;
for (const key of Object.keys(params)) {
const value = params[key];
if (!value || (props.hiddenTags || []).includes(key)) continue;
tagList.push({ key, value });
}
return tagList;
}); });
const tags = computed(() => const tags = computed(() =>
tagsList.value.filter((tag) => !(props.customTags || []).includes(tag.label)) tagsList.value.filter((tag) => !(props.customTags || []).includes(tag.key))
); );
const customTags = computed(() => const customTags = computed(() =>
tagsList.value.filter((tag) => (props.customTags || []).includes(tag.label)) tagsList.value.filter((tag) => (props.customTags || []).includes(tag.key))
); );
async function remove(key) { async function remove(key) {
userParams.value[key] = null; delete userParams.value[key];
delete userParams.value.filter.where[key];
params.value[key] = undefined; params.value[key] = undefined;
await arrayData.applyFilter({ params: userParams.value }); await arrayData.applyFilter({ params: userParams.value });
emit('remove', key); emit('remove', key);
@ -224,13 +244,13 @@ function formatValue(value) {
<div> <div>
<VnFilterPanelChip <VnFilterPanelChip
v-for="chip of tags" v-for="chip of tags"
:key="chip.label" :key="chip.key"
:removable="!unremovableParams.includes(chip.label)" :removable="!unremovableParams.includes(chip.key)"
@remove="remove(chip.label)" @remove="remove(chip.key)"
> >
<slot name="tags" :tag="chip" :format-fn="formatValue"> <slot name="tags" :tag="chip" :format-fn="formatValue">
<div class="q-gutter-x-xs"> <div class="q-gutter-x-xs">
<strong>{{ chip.label }}:</strong> <strong>{{ chip.key }}:</strong>
<span>"{{ chip.value }}"</span> <span>"{{ chip.value }}"</span>
</div> </div>
</slot> </slot>
@ -260,8 +280,9 @@ function formatValue(value) {
dense dense
icon="search" icon="search"
rounded rounded
type="submit" :type="disableSubmitEvent ? 'button' : 'submit'"
unelevated unelevated
@click="search()"
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>

View File

@ -1,5 +1,5 @@
import { onMounted, ref, computed } from 'vue'; import { onMounted, ref, computed } from 'vue';
import { useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import axios from 'axios'; import axios from 'axios';
import { useArrayDataStore } from 'stores/useArrayDataStore'; import { useArrayDataStore } from 'stores/useArrayDataStore';
import { buildFilter } from 'filters/filterPanel'; import { buildFilter } from 'filters/filterPanel';
@ -13,6 +13,7 @@ export function useArrayData(key, userOptions) {
const store = arrayDataStore.get(key); const store = arrayDataStore.get(key);
const route = useRoute(); const route = useRoute();
const router = useRouter();
let canceller = null; let canceller = null;
const page = ref(1); const page = ref(1);
@ -189,15 +190,10 @@ export function useArrayData(key, userOptions) {
if (store.userParams && Object.keys(store.userParams).length !== 0) if (store.userParams && Object.keys(store.userParams).length !== 0)
query.params = JSON.stringify(store.userParams); query.params = JSON.stringify(store.userParams);
const url = new URL(window.location.href); router.replace({
const { hash: currentHash } = url; path: route.path,
const [currentRoute] = currentHash.split('?'); query,
});
const params = new URLSearchParams();
for (const param in query) params.append(param, query[param]);
url.hash = currentRoute + '?' + params.toString();
window.history.pushState({}, '', url.hash);
} }
const totalRows = computed(() => (store.data && store.data.length) || 0); const totalRows = computed(() => (store.data && store.data.length) || 0);

View File

@ -75,11 +75,17 @@ const columns = computed(() => [
align: 'left', align: 'left',
label: t('customer.extendedList.tableVisibleColumns.credit'), label: t('customer.extendedList.tableVisibleColumns.credit'),
name: 'credit', name: 'credit',
columnFilter: {
inWhere: true,
},
}, },
{ {
align: 'left', align: 'left',
label: t('customer.extendedList.tableVisibleColumns.creditInsurance'), label: t('customer.extendedList.tableVisibleColumns.creditInsurance'),
name: 'creditInsurance', name: 'creditInsurance',
columnFilter: {
inWhere: true,
},
}, },
{ {
align: 'left', align: 'left',
@ -98,6 +104,9 @@ const columns = computed(() => [
label: t('customer.extendedList.tableVisibleColumns.mobile'), label: t('customer.extendedList.tableVisibleColumns.mobile'),
name: 'mobile', name: 'mobile',
cardVisible: true, cardVisible: true,
columnFilter: {
inWhere: true,
},
}, },
{ {
align: 'left', align: 'left',
@ -108,12 +117,29 @@ const columns = computed(() => [
{ {
align: 'left', align: 'left',
label: t('customer.extendedList.tableVisibleColumns.countryFk'), label: t('customer.extendedList.tableVisibleColumns.countryFk'),
name: 'country', name: 'countryFk',
columnFilter: {
component: 'select',
inWhere: true,
prefix: 'c',
attrs: {
url: 'Countries',
},
},
format: (row, dashIfEmpty) => dashIfEmpty(row.country),
}, },
{ {
align: 'left', align: 'left',
label: t('customer.extendedList.tableVisibleColumns.provinceFk'), label: t('customer.extendedList.tableVisibleColumns.provinceFk'),
name: 'provinceFk', name: 'provinceFk',
component: 'select',
attrs: {
url: 'Provinces',
},
columnField: {
component: null,
},
format: (row, dashIfEmpty) => dashIfEmpty(row.province),
}, },
{ {
align: 'left', align: 'left',

View File

@ -1,571 +0,0 @@
<script setup>
import { ref, computed, onBeforeMount, onMounted } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import { QBtn, QIcon } from 'quasar';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
import CustomerExtendedListActions from './CustomerExtendedListActions.vue';
import CustomerExtendedListFilter from './CustomerExtendedListFilter.vue';
import TableVisibleColumns from 'src/components/common/TableVisibleColumns.vue';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import { useArrayData } from 'composables/useArrayData';
import { useStateStore } from 'stores/useStateStore';
import { toDate } from 'src/filters';
const { t } = useI18n();
const router = useRouter();
const stateStore = useStateStore();
const arrayData = ref(null);
onBeforeMount(async () => {
arrayData.value = useArrayData('CustomerExtendedList', {
url: 'Clients/extendedListFilter',
limit: 0,
});
await arrayData.value.fetch({ append: false });
stateStore.rightDrawer = true;
});
onMounted(() => {
const filteredColumns = columns.value.filter(
(col) => col.name !== 'actions' && col.name !== 'customerStatus'
);
allColumnNames.value = filteredColumns.map((col) => col.name);
});
const rows = computed(() => arrayData.value.store.data);
const selectedCustomerId = ref(0);
const selectedSalesPersonId = ref(0);
const allColumnNames = ref([]);
const visibleColumns = ref([]);
const tableColumnComponents = {
customerStatus: {
component: QIcon,
props: (prop) => ({
name: !prop.row.isActive
? 'vn:disabled'
: prop.row.isActive && prop.row.isFreezed
? 'vn:frozen'
: '',
color: 'primary',
size: 'sm',
}),
event: () => {},
},
id: {
component: QBtn,
props: () => ({ flat: true, color: 'blue' }),
event: (prop) => {
selectCustomerId(prop.row.id);
},
},
name: {
component: 'span',
props: () => {},
event: () => {},
},
fi: {
component: 'span',
props: () => {},
event: () => {},
},
salesPersonFk: {
component: QBtn,
props: () => ({ flat: true, color: 'blue' }),
event: (prop) => selectSalesPersonId(prop.row.salesPersonFk),
},
credit: {
component: 'span',
props: () => {},
event: () => {},
},
creditInsurance: {
component: 'span',
props: () => {},
event: () => {},
},
phone: {
component: 'span',
props: () => {},
event: () => {},
},
mobile: {
component: 'span',
props: () => {},
event: () => {},
},
street: {
component: 'span',
props: () => {},
event: () => {},
},
countryFk: {
component: 'span',
props: () => {},
event: () => {},
},
provinceFk: {
component: 'span',
props: () => {},
event: () => {},
},
city: {
component: 'span',
props: () => {},
event: () => {},
},
postcode: {
component: 'span',
props: () => {},
event: () => {},
},
email: {
component: 'span',
props: () => {},
event: () => {},
},
created: {
component: 'span',
props: () => {},
event: () => {},
},
businessTypeFk: {
component: 'span',
props: () => {},
event: () => {},
},
payMethodFk: {
component: 'span',
props: () => {},
event: () => {},
},
sageTaxTypeFk: {
component: 'span',
props: () => {},
event: () => {},
},
sageTransactionTypeFk: {
component: 'span',
props: () => {},
event: () => {},
},
isActive: {
component: QIcon,
props: (prop) => ({
name: prop.row.isActive ? 'check' : 'close',
color: prop.row.isActive ? 'positive' : 'negative',
size: 'sm',
}),
event: () => {},
},
isVies: {
component: QIcon,
props: (prop) => ({
name: prop.row.isVies ? 'check' : 'close',
color: prop.row.isVies ? 'positive' : 'negative',
size: 'sm',
}),
event: () => {},
},
isTaxDataChecked: {
component: QIcon,
props: (prop) => ({
name: prop.row.isTaxDataChecked ? 'check' : 'close',
color: prop.row.isTaxDataChecked ? 'positive' : 'negative',
size: 'sm',
}),
event: () => {},
},
isEqualizated: {
component: QIcon,
props: (prop) => ({
name: prop.row.isEqualizated ? 'check' : 'close',
color: prop.row.isEqualizated ? 'positive' : 'negative',
size: 'sm',
}),
event: () => {},
},
isFreezed: {
component: QIcon,
props: (prop) => ({
name: prop.row.isFreezed ? 'check' : 'close',
color: prop.row.isFreezed ? 'positive' : 'negative',
size: 'sm',
}),
event: () => {},
},
hasToInvoice: {
component: QIcon,
props: (prop) => ({
name: prop.row.hasToInvoice ? 'check' : 'close',
color: prop.row.hasToInvoice ? 'positive' : 'negative',
size: 'sm',
}),
event: () => {},
},
hasToInvoiceByAddress: {
component: QIcon,
props: (prop) => ({
name: prop.row.hasToInvoiceByAddress ? 'check' : 'close',
color: prop.row.hasToInvoiceByAddress ? 'positive' : 'negative',
size: 'sm',
}),
event: () => {},
},
isToBeMailed: {
component: QIcon,
props: (prop) => ({
name: prop.row.isToBeMailed ? 'check' : 'close',
color: prop.row.isToBeMailed ? 'positive' : 'negative',
size: 'sm',
}),
event: () => {},
},
hasLcr: {
component: QIcon,
props: (prop) => ({
name: prop.row.hasLcr ? 'check' : 'close',
color: prop.row.hasLcr ? 'positive' : 'negative',
size: 'sm',
}),
event: () => {},
},
hasCoreVnl: {
component: QIcon,
props: (prop) => ({
name: prop.row.hasCoreVnl ? 'check' : 'close',
color: prop.row.hasCoreVnl ? 'positive' : 'negative',
size: 'sm',
}),
event: () => {},
},
hasSepaVnl: {
component: QIcon,
props: (prop) => ({
name: prop.row.hasSepaVnl ? 'check' : 'close',
color: prop.row.hasSepaVnl ? 'positive' : 'negative',
size: 'sm',
}),
event: () => {},
},
actions: {
component: CustomerExtendedListActions,
props: (prop) => ({
id: prop.row.id,
}),
event: () => {},
},
};
const columns = computed(() => [
{
align: 'left',
field: '',
label: '',
name: 'customerStatus',
format: () => ' ',
},
{
align: 'left',
field: 'id',
label: t('customer.extendedList.tableVisibleColumns.id'),
name: 'id',
},
{
align: 'left',
field: 'name',
label: t('customer.extendedList.tableVisibleColumns.name'),
name: 'name',
},
{
align: 'left',
field: 'fi',
label: t('customer.extendedList.tableVisibleColumns.fi'),
name: 'fi',
},
{
align: 'left',
field: 'salesPerson',
label: t('customer.extendedList.tableVisibleColumns.salesPersonFk'),
name: 'salesPersonFk',
},
{
align: 'left',
field: 'credit',
label: t('customer.extendedList.tableVisibleColumns.credit'),
name: 'credit',
},
{
align: 'left',
field: 'creditInsurance',
label: t('customer.extendedList.tableVisibleColumns.creditInsurance'),
name: 'creditInsurance',
},
{
align: 'left',
field: 'phone',
label: t('customer.extendedList.tableVisibleColumns.phone'),
name: 'phone',
},
{
align: 'left',
field: 'mobile',
label: t('customer.extendedList.tableVisibleColumns.mobile'),
name: 'mobile',
},
{
align: 'left',
field: 'street',
label: t('customer.extendedList.tableVisibleColumns.street'),
name: 'street',
},
{
align: 'left',
field: 'country',
label: t('customer.extendedList.tableVisibleColumns.countryFk'),
name: 'countryFk',
},
{
align: 'left',
field: 'province',
label: t('customer.extendedList.tableVisibleColumns.provinceFk'),
name: 'provinceFk',
},
{
align: 'left',
field: 'city',
label: t('customer.extendedList.tableVisibleColumns.city'),
name: 'city',
},
{
align: 'left',
field: 'postcode',
label: t('customer.extendedList.tableVisibleColumns.postcode'),
name: 'postcode',
},
{
align: 'left',
field: 'email',
label: t('customer.extendedList.tableVisibleColumns.email'),
name: 'email',
},
{
align: 'left',
field: 'created',
label: t('customer.extendedList.tableVisibleColumns.created'),
name: 'created',
format: (value) => toDate(value),
},
{
align: 'left',
field: 'businessType',
label: t('customer.extendedList.tableVisibleColumns.businessTypeFk'),
name: 'businessTypeFk',
},
{
align: 'left',
field: 'payMethod',
label: t('customer.extendedList.tableVisibleColumns.payMethodFk'),
name: 'payMethodFk',
},
{
align: 'left',
field: 'sageTaxType',
label: t('customer.extendedList.tableVisibleColumns.sageTaxTypeFk'),
name: 'sageTaxTypeFk',
},
{
align: 'left',
field: 'sageTransactionType',
label: t('customer.extendedList.tableVisibleColumns.sageTransactionTypeFk'),
name: 'sageTransactionTypeFk',
},
{
align: 'left',
field: 'isActive',
label: t('customer.extendedList.tableVisibleColumns.isActive'),
name: 'isActive',
format: () => ' ',
},
{
align: 'left',
field: 'isVies',
label: t('customer.extendedList.tableVisibleColumns.isVies'),
name: 'isVies',
format: () => ' ',
},
{
align: 'left',
field: 'isTaxDataChecked',
label: t('customer.extendedList.tableVisibleColumns.isTaxDataChecked'),
name: 'isTaxDataChecked',
format: () => ' ',
},
{
align: 'left',
field: 'isEqualizated',
label: t('customer.extendedList.tableVisibleColumns.isEqualizated'),
name: 'isEqualizated',
format: () => ' ',
},
{
align: 'left',
field: 'isFreezed',
label: t('customer.extendedList.tableVisibleColumns.isFreezed'),
name: 'isFreezed',
format: () => ' ',
},
{
align: 'left',
field: 'hasToInvoice',
label: t('customer.extendedList.tableVisibleColumns.hasToInvoice'),
name: 'hasToInvoice',
format: () => ' ',
},
{
align: 'left',
field: 'hasToInvoiceByAddress',
label: t('customer.extendedList.tableVisibleColumns.hasToInvoiceByAddress'),
name: 'hasToInvoiceByAddress',
format: () => ' ',
},
{
align: 'left',
field: 'isToBeMailed',
label: t('customer.extendedList.tableVisibleColumns.isToBeMailed'),
name: 'isToBeMailed',
format: () => ' ',
},
{
align: 'left',
field: 'hasLcr',
label: t('customer.extendedList.tableVisibleColumns.hasLcr'),
name: 'hasLcr',
format: () => ' ',
},
{
align: 'left',
field: 'hasCoreVnl',
label: t('customer.extendedList.tableVisibleColumns.hasCoreVnl'),
name: 'hasCoreVnl',
format: () => ' ',
},
{
align: 'left',
field: 'hasSepaVnl',
label: t('customer.extendedList.tableVisibleColumns.hasSepaVnl'),
name: 'hasSepaVnl',
format: () => ' ',
},
{
align: 'right',
field: 'actions',
label: '',
name: 'actions',
},
]);
const stopEventPropagation = (event, col) => {
if (!['id', 'salesPersonFk'].includes(col.name)) return;
event.preventDefault();
event.stopPropagation();
};
const navigateToTravelId = (id) => router.push({ path: `/customer/${id}` });
const selectCustomerId = (id) => (selectedCustomerId.value = id);
const selectSalesPersonId = (id) => (selectedSalesPersonId.value = id);
</script>
<template>
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above>
<QScrollArea class="fit text-grey-8">
<CustomerExtendedListFilter
v-if="visibleColumns.length !== 0"
data-key="CustomerExtendedList"
:visible-columns="visibleColumns"
/>
</QScrollArea>
</QDrawer>
<VnSubToolbar>
<template #st-actions>
<TableVisibleColumns
:all-columns="allColumnNames"
table-code="clientsDetail"
labels-traductions-path="customer.extendedList.tableVisibleColumns"
@on-config-saved="
visibleColumns = ['customerStatus', ...$event, 'actions']
"
/>
</template>
</VnSubToolbar>
<QPage class="column items-center q-pa-md">
<QTable
:columns="columns"
:rows="rows"
class="full-width q-mt-md"
row-key="id"
:visible-columns="visibleColumns"
@row-click="(evt, row, id) => navigateToTravelId(row.id)"
>
<template #body-cell="{ col, value }">
<QTd @click="stopEventPropagation($event, col)">
{{ value }}
</QTd>
</template>
<template #body-cell-id="props">
<QTd @click="stopEventPropagation($event, props.col)">
<component
:is="tableColumnComponents[props.col.name].component"
class="col-content"
v-bind="tableColumnComponents[props.col.name].props(props)"
@click="tableColumnComponents[props.col.name].event(props)"
>
<CustomerDescriptorProxy :id="props.row.id" />
{{ props.row.id }}
</component>
</QTd>
</template>
<template #body-cell-salesPersonFk="props">
<QTd @click="stopEventPropagation($event, props.col)">
<component
v-if="props.row.salesPerson"
class="col-content"
:is="tableColumnComponents[props.col.name].component"
v-bind="tableColumnComponents[props.col.name].props(props)"
@click="tableColumnComponents[props.col.name].event(props)"
>
<WorkerDescriptorProxy :id="props.row.salesPersonFk" />
{{ props.row.salesPerson }}
</component>
<span class="col-content" v-else>-</span>
</QTd>
</template>
<template #body-cell-actions="props">
<QTd @click="stopEventPropagation($event, props.col)">
<component
:is="tableColumnComponents[props.col.name].component"
class="col-content"
v-bind="tableColumnComponents[props.col.name].props(props)"
@click="tableColumnComponents[props.col.name].event(props)"
/>
</QTd>
</template>
</QTable>
</QPage>
</template>
<style lang="scss" scoped>
.col-content {
border-radius: 4px;
padding: 6px;
}
</style>